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:
Pieter Vander Vennet 2021-08-07 21:19:01 +02:00
parent bf2d634208
commit 0a01561d37
15 changed files with 460 additions and 143 deletions

View file

@ -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],

View file

@ -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
}
}[],

View file

@ -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});

View 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
}
}