First working version of snapping to already existing ways from the add-UI (still too slow though), partial fix of #436
This commit is contained in:
parent
bf2d634208
commit
0a01561d37
15 changed files with 460 additions and 143 deletions
|
@ -14,11 +14,11 @@ import {UIEventSource} from "../../Logic/UIEventSource";
|
|||
import {FixedUiElement} from "../../UI/Base/FixedUiElement";
|
||||
import SourceConfig from "./SourceConfig";
|
||||
import {TagsFilter} from "../../Logic/Tags/TagsFilter";
|
||||
import {Tag} from "../../Logic/Tags/Tag";
|
||||
import BaseUIElement from "../../UI/BaseUIElement";
|
||||
import {Unit} from "./Denomination";
|
||||
import DeleteConfig from "./DeleteConfig";
|
||||
import FilterConfig from "./FilterConfig";
|
||||
import PresetConfig from "./PresetConfig";
|
||||
|
||||
export default class LayerConfig {
|
||||
static WAYHANDLING_DEFAULT = 0;
|
||||
|
@ -35,7 +35,7 @@ export default class LayerConfig {
|
|||
isShown: TagRenderingConfig;
|
||||
minzoom: number;
|
||||
minzoomVisible: number;
|
||||
maxzoom:number;
|
||||
maxzoom: number;
|
||||
title?: TagRenderingConfig;
|
||||
titleIcons: TagRenderingConfig[];
|
||||
icon: TagRenderingConfig;
|
||||
|
@ -51,12 +51,7 @@ export default class LayerConfig {
|
|||
public readonly deletion: DeleteConfig | null;
|
||||
public readonly allowSplit: boolean
|
||||
|
||||
presets: {
|
||||
title: Translation,
|
||||
tags: Tag[],
|
||||
description?: Translation,
|
||||
preciseInput?: { preferredBackground?: string }
|
||||
}[];
|
||||
presets: PresetConfig[];
|
||||
|
||||
tagRenderings: TagRenderingConfig[];
|
||||
filters: FilterConfig[];
|
||||
|
@ -149,17 +144,41 @@ export default class LayerConfig {
|
|||
this.minzoomVisible = json.minzoomVisible ?? this.minzoom;
|
||||
this.wayHandling = json.wayHandling ?? 0;
|
||||
this.presets = (json.presets ?? []).map((pr, i) => {
|
||||
if (pr.preciseInput === true) {
|
||||
pr.preciseInput = {
|
||||
preferredBackground: undefined
|
||||
|
||||
let preciseInput = undefined;
|
||||
if(pr.preciseInput !== undefined){
|
||||
if (pr.preciseInput === true) {
|
||||
pr.preciseInput = {
|
||||
preferredBackground: undefined
|
||||
}
|
||||
}
|
||||
let snapToLayers: string[];
|
||||
if (typeof pr.preciseInput.snapToLayer === "string") {
|
||||
snapToLayers = [pr.preciseInput.snapToLayer]
|
||||
} else {
|
||||
snapToLayers = pr.preciseInput.snapToLayer
|
||||
}
|
||||
|
||||
let preferredBackground : string[]
|
||||
if (typeof pr.preciseInput.preferredBackground === "string") {
|
||||
preferredBackground = [pr.preciseInput.preferredBackground]
|
||||
} else {
|
||||
preferredBackground = pr.preciseInput.preferredBackground
|
||||
}
|
||||
preciseInput = {
|
||||
preferredBackground: preferredBackground,
|
||||
snapToLayers: snapToLayers,
|
||||
maxSnapDistance: pr.preciseInput.maxSnapDistance ?? 10
|
||||
}
|
||||
}
|
||||
return {
|
||||
|
||||
const config : PresetConfig= {
|
||||
title: Translations.T(pr.title, `${context}.presets[${i}].title`),
|
||||
tags: pr.tags.map((t) => FromJSON.SimpleTag(t)),
|
||||
description: Translations.T(pr.description, `${context}.presets[${i}].description`),
|
||||
preciseInput: pr.preciseInput
|
||||
preciseInput: preciseInput,
|
||||
}
|
||||
return config;
|
||||
});
|
||||
|
||||
/** Given a key, gets the corresponding property from the json (or the default if not found
|
||||
|
@ -407,12 +426,15 @@ export default class LayerConfig {
|
|||
}
|
||||
|
||||
function render(tr: TagRenderingConfig, deflt?: string) {
|
||||
if(tags === undefined){
|
||||
return deflt
|
||||
}
|
||||
const str = tr?.GetRenderValue(tags.data)?.txt ?? deflt;
|
||||
return Utils.SubstituteKeys(str, tags.data).replace(/{.*}/g, "");
|
||||
}
|
||||
|
||||
const iconSize = render(this.iconSize, "40,40,center").split(",");
|
||||
const dashArray = render(this.dashArray).split(" ").map(Number);
|
||||
const dashArray = render(this.dashArray)?.split(" ")?.map(Number);
|
||||
let color = render(this.color, "#00f");
|
||||
|
||||
if (color.startsWith("--")) {
|
||||
|
@ -445,24 +467,26 @@ export default class LayerConfig {
|
|||
|
||||
const iconUrlStatic = render(this.icon);
|
||||
const self = this;
|
||||
const mappedHtml = tags.map((tgs) => {
|
||||
function genHtmlFromString(sourcePart: string): BaseUIElement {
|
||||
const style = `width:100%;height:100%;transform: rotate( ${rotation} );display:block;position: absolute; top: 0; left: 0`;
|
||||
let html: BaseUIElement = new FixedUiElement(
|
||||
`<img src="${sourcePart}" style="${style}" />`
|
||||
);
|
||||
const match = sourcePart.match(/([a-zA-Z0-9_]*):([^;]*)/);
|
||||
if (match !== null && Svg.All[match[1] + ".svg"] !== undefined) {
|
||||
html = new Combine([
|
||||
(Svg.All[match[1] + ".svg"] as string).replace(
|
||||
/#000000/g,
|
||||
match[2]
|
||||
),
|
||||
]).SetStyle(style);
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
function genHtmlFromString(sourcePart: string, rotation: string): BaseUIElement {
|
||||
const style = `width:100%;height:100%;transform: rotate( ${rotation} );display:block;position: absolute; top: 0; left: 0`;
|
||||
let html: BaseUIElement = new FixedUiElement(
|
||||
`<img src="${sourcePart}" style="${style}" />`
|
||||
);
|
||||
const match = sourcePart.match(/([a-zA-Z0-9_]*):([^;]*)/);
|
||||
if (match !== null && Svg.All[match[1] + ".svg"] !== undefined) {
|
||||
html = new Combine([
|
||||
(Svg.All[match[1] + ".svg"] as string).replace(
|
||||
/#000000/g,
|
||||
match[2]
|
||||
),
|
||||
]).SetStyle(style);
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
|
||||
const mappedHtml = tags?.map((tgs) => {
|
||||
// What do you mean, 'tgs' is never read?
|
||||
// It is read implicitly in the 'render' method
|
||||
const iconUrl = render(self.icon);
|
||||
|
@ -473,7 +497,7 @@ export default class LayerConfig {
|
|||
iconUrl.split(";").filter((prt) => prt != "")
|
||||
);
|
||||
for (const sourcePart of sourceParts) {
|
||||
htmlParts.push(genHtmlFromString(sourcePart));
|
||||
htmlParts.push(genHtmlFromString(sourcePart, rotation));
|
||||
}
|
||||
|
||||
let badges = [];
|
||||
|
@ -489,7 +513,7 @@ export default class LayerConfig {
|
|||
.filter((prt) => prt != "");
|
||||
|
||||
for (const badgePartStr of partDefs) {
|
||||
badgeParts.push(genHtmlFromString(badgePartStr));
|
||||
badgeParts.push(genHtmlFromString(badgePartStr, "0"));
|
||||
}
|
||||
|
||||
const badgeCompound = new Combine(badgeParts).SetStyle(
|
||||
|
@ -499,7 +523,7 @@ export default class LayerConfig {
|
|||
badges.push(badgeCompound);
|
||||
} else {
|
||||
htmlParts.push(
|
||||
genHtmlFromString(iconOverlay.then.GetRenderValue(tgs).txt)
|
||||
genHtmlFromString(iconOverlay.then.GetRenderValue(tgs).txt, "0")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -533,7 +557,7 @@ export default class LayerConfig {
|
|||
|
||||
return {
|
||||
icon: {
|
||||
html: new VariableUiElement(mappedHtml),
|
||||
html: mappedHtml === undefined ? new FixedUiElement(self.icon.render.txt) : new VariableUiElement(mappedHtml),
|
||||
iconSize: [iconW, iconH],
|
||||
iconAnchor: [anchorW, anchorH],
|
||||
popupAnchor: [0, 3 - anchorH],
|
||||
|
|
|
@ -226,7 +226,21 @@ export interface LayerConfigJson {
|
|||
* If 'preferredBackgroundCategory' is set, the element will attempt to pick a background layer of that category.
|
||||
*/
|
||||
preciseInput?: true | {
|
||||
preferredBackground: "osmbasedmap" | "photo" | "historicphoto" | "map" | string
|
||||
/**
|
||||
* The type of background picture
|
||||
*/
|
||||
preferredBackground: "osmbasedmap" | "photo" | "historicphoto" | "map" | string | string [],
|
||||
/**
|
||||
* If specified, these layers will be shown to and the new point will be snapped towards it
|
||||
*/
|
||||
snapToLayer?: string | string[],
|
||||
/**
|
||||
* If specified, a new point will only be snapped if it is within this range.
|
||||
* Distance in meter
|
||||
*
|
||||
* Default: 10
|
||||
*/
|
||||
maxSnapDistance?: number
|
||||
}
|
||||
}[],
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ export default class LayoutConfig {
|
|||
this.defaultBackgroundId = json.defaultBackgroundId;
|
||||
this.layers = LayoutConfig.ExtractLayers(json, this.units, official, context);
|
||||
|
||||
// ALl the layers are constructed, let them share tags in now!
|
||||
// ALl the layers are constructed, let them share tagRenderings now!
|
||||
const roaming: { r, source: LayerConfig }[] = []
|
||||
for (const layer of this.layers) {
|
||||
roaming.push({r: layer.GetRoamingRenderings(), source: layer});
|
||||
|
|
16
Customizations/JSON/PresetConfig.ts
Normal file
16
Customizations/JSON/PresetConfig.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import {Translation} from "../../UI/i18n/Translation";
|
||||
import {Tag} from "../../Logic/Tags/Tag";
|
||||
|
||||
export default interface PresetConfig {
|
||||
title: Translation,
|
||||
tags: Tag[],
|
||||
description?: Translation,
|
||||
/**
|
||||
* If precise input is set, then an extra map is shown in which the user can drag the map to the precise location
|
||||
*/
|
||||
preciseInput?: {
|
||||
preferredBackground?: string[],
|
||||
snapToLayers?: string[],
|
||||
maxSnapDistance?: number
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue