New roaming rendering system which allows layers to push questions, badges and title-icons to all the other layers, improve bike-clean-services

This commit is contained in:
Pieter Vander Vennet 2021-01-08 03:57:18 +01:00
parent 77ffdc093a
commit 2a31badd3d
16 changed files with 427 additions and 394 deletions

View file

@ -19,22 +19,18 @@ import {UIElement} from "../../UI/UIElement";
export default class LayerConfig {
static WAYHANDLING_DEFAULT = 0;
static WAYHANDLING_CENTER_ONLY = 1;
static WAYHANDLING_CENTER_AND_WAY = 2;
id: string;
name: Translation
description: Translation;
overpassTags: TagsFilter;
doNotDownload: boolean;
passAllFeatures: boolean;
minzoom: number;
title?: TagRenderingConfig;
titleIcons: TagRenderingConfig[];
icon: TagRenderingConfig;
iconOverlays: { if: TagsFilter, then: TagRenderingConfig, badge: boolean }[]
iconSize: TagRenderingConfig;
@ -42,14 +38,7 @@ export default class LayerConfig {
color: TagRenderingConfig;
width: TagRenderingConfig;
dashArray: TagRenderingConfig;
wayHandling: number;
static WAYHANDLING_DEFAULT = 0;
static WAYHANDLING_CENTER_ONLY = 1;
static WAYHANDLING_CENTER_AND_WAY = 2;
hideUnderlayingFeaturesMinPercentage?: number;
presets: {
@ -60,10 +49,10 @@ export default class LayerConfig {
tagRenderings: TagRenderingConfig [];
constructor(json: LayerConfigJson, roamingRenderings: TagRenderingConfig[],
constructor(json: LayerConfigJson,
context?: string) {
context = context + "." + json.id;
const self = this;
this.id = json.id;
this.name = Translations.T(json.name);
this.description = Translations.T(json.description);
@ -81,6 +70,28 @@ export default class LayerConfig {
}))
/** Given a key, gets the corresponding property from the json (or the default if not found
*
* The found value is interpreted as a tagrendering and fetched/parsed
* */
function tr(key: string, deflt) {
const v = json[key];
if (v === undefined || v === null) {
if (deflt === undefined) {
return undefined;
}
return new TagRenderingConfig(deflt, self.overpassTags, `${context}.${key}.default value`);
}
if (typeof v === "string") {
const shared = SharedTagRenderings.SharedTagRendering[v];
if (shared) {
console.log("Got shared TR:", v, "-->", shared)
return shared;
}
}
return new TagRenderingConfig(v, self.overpassTags, `${context}.${key}`);
}
/**
* Converts a list of tagRenderingCOnfigJSON in to TagRenderingConfig
* A string is interpreted as a name to call
@ -90,26 +101,27 @@ export default class LayerConfig {
if (tagRenderings === undefined) {
return [];
}
return tagRenderings.map(
(renderingJson, i) => {
if (typeof renderingJson === "string") {
if(renderingJson === "questions"){
return new TagRenderingConfig("questions")
if (renderingJson === "questions") {
return new TagRenderingConfig("questions", undefined)
}
const shared = SharedTagRenderings.SharedTagRendering[renderingJson];
if (shared !== undefined) {
return shared;
}
throw `Predefined tagRendering ${renderingJson} not found in ${context}`;
}
return new TagRenderingConfig(renderingJson, `${context}.tagrendering[${i}]`);
return new TagRenderingConfig(renderingJson, self.overpassTags, `${context}.tagrendering[${i}]`);
});
}
this.tagRenderings = trs(json.tagRenderings).concat(roamingRenderings);
this.tagRenderings = trs(json.tagRenderings);
const titleIcons = [];
@ -125,29 +137,10 @@ export default class LayerConfig {
this.titleIcons = trs(titleIcons);
function tr(key, deflt) {
const v = json[key];
if (v === undefined || v === null) {
if (deflt === undefined) {
return undefined;
}
return new TagRenderingConfig(deflt);
}
if (typeof v === "string") {
const shared = SharedTagRenderings.SharedTagRendering[v];
if (shared) {
console.log("Got shared TR:", v, "-->", shared)
return shared;
}
}
return new TagRenderingConfig(v, context + "." + key);
}
this.title = tr("title", undefined);
this.icon = tr("icon", Img.AsData(Svg.pin));
this.iconOverlays = (json.iconOverlays ?? []).map(overlay => {
let tr = new TagRenderingConfig(overlay.then);
this.iconOverlays = (json.iconOverlays ?? []).map((overlay, i) => {
let tr = new TagRenderingConfig(overlay.then, self.overpassTags, `iconoverlays.${i}`);
if (typeof overlay.then === "string" && SharedTagRenderings.SharedIcons[overlay.then] !== undefined) {
tr = SharedTagRenderings.SharedIcons[overlay.then];
}
@ -175,18 +168,54 @@ export default class LayerConfig {
}
public AddRoamingRenderings(addAll: {
tagRenderings: TagRenderingConfig[],
titleIcons: TagRenderingConfig[],
iconOverlays: { "if": TagsFilter, then: TagRenderingConfig, badge: boolean }[]
}): LayerConfig {
this.tagRenderings.push(...addAll.tagRenderings);
this.iconOverlays.push(...addAll.iconOverlays);
for (const icon of addAll.titleIcons) {
console.log("Adding ",icon, "to", this.id)
this.titleIcons.splice(0,0, icon);
}
return this;
}
public GetRoamingRenderings(): {
tagRenderings: TagRenderingConfig[],
titleIcons: TagRenderingConfig[],
iconOverlays: { "if": TagsFilter, then: TagRenderingConfig, badge: boolean }[]
} {
const tagRenderings = this.tagRenderings.filter(tr => tr.roaming);
const titleIcons = this.titleIcons.filter(tr => tr.roaming);
const iconOverlays = this.iconOverlays.filter(io => io.then.roaming)
return {
tagRenderings: tagRenderings,
titleIcons: titleIcons,
iconOverlays: iconOverlays
}
}
public GenerateLeafletStyle(tags: UIEventSource<any>, clickable: boolean):
{
color: string;
icon: {
iconUrl: string,
popupAnchor: [number, number];
iconAnchor: [number, number];
iconSize: [number, number];
html: UIElement;
className?: string;
};
weight: number; dashArray: number[]
icon:
{
html: UIElement,
iconSize: [number, number],
iconAnchor: [number, number],
popupAnchor: [number, number],
iconUrl: string,
className: string
},
color: string,
weight: number,
dashArray: number[]
} {
function num(str, deflt = 40) {
@ -259,7 +288,7 @@ export default class LayerConfig {
if (match !== null && Svg.All[match[1] + ".svg"] !== undefined) {
html = new Combine([
(Svg.All[match[1] + ".svg"] as string)
.replace(/#000000/g, match[2])
.replace(/#000000/g, match[2])
]).SetStyle(style);
}
return html;

View file

@ -75,7 +75,7 @@ export default class LayoutConfig {
return SharedTagRenderings.SharedTagRendering[tr];
}
}
return new TagRenderingConfig(tr, `${this.id}.roaming_renderings[${i}]`);
return new TagRenderingConfig(tr, undefined,`${this.id}.roaming_renderings[${i}]`);
}
);
this.defaultBackgroundId = json.defaultBackgroundId;
@ -102,9 +102,23 @@ export default class LayoutConfig {
}
// @ts-ignore
return new LayerConfig(layer, this.roamingRenderings, `${this.id}.layers[${i}]`);
return new LayerConfig(layer, `${this.id}.layers[${i}]`)
});
// ALl the layers are constructed, let them share tags in piece now!
const roaming : {r, source: LayerConfig}[] = []
for (const layer of this.layers) {
roaming.push({r: layer.GetRoamingRenderings(), source:layer});
}
for (const layer of this.layers) {
for (const r of roaming) {
if(r.source == layer){
continue;
}
layer.AddRoamingRenderings(r.r);
}
}
this.clustering = {
maxZoom: 16,

View file

@ -1,4 +1,4 @@
import {TagsFilter} from "../../Logic/Tags";
import {And, TagsFilter} from "../../Logic/Tags";
import {TagRenderingConfigJson} from "./TagRenderingConfigJson";
import Translations from "../../UI/i18n/Translations";
import {FromJSON} from "./FromJSON";
@ -11,25 +11,26 @@ import {Translation} from "../../UI/i18n/Translation";
*/
export default class TagRenderingConfig {
render?: Translation;
question?: Translation;
condition?: TagsFilter;
readonly render?: Translation;
readonly question?: Translation;
readonly condition?: TagsFilter;
freeform?: {
key: string,
type: string,
addExtraTags: TagsFilter[];
readonly freeform?: {
readonly key: string,
readonly type: string,
readonly addExtraTags: TagsFilter[];
};
readonly multiAnswer: boolean;
mappings?: {
if: TagsFilter,
then: Translation
hideInAnswer: boolean | TagsFilter
readonly mappings?: {
readonly if: TagsFilter,
readonly then: Translation
readonly hideInAnswer: boolean | TagsFilter
}[]
readonly roaming: boolean;
constructor(json: string | TagRenderingConfigJson, context?: string) {
constructor(json: string | TagRenderingConfigJson, conditionIfRoaming: TagsFilter, context?: string) {
if (json === "questions") {
// Very special value
@ -46,10 +47,16 @@ export default class TagRenderingConfig {
this.multiAnswer = false;
return;
}
this.render = Translations.T(json.render);
this.question = Translations.T(json.question);
this.condition = FromJSON.Tag(json.condition ?? {"and": []}, `${context}.condition`);
this.roaming = json.roaming ?? false;
const condition = FromJSON.Tag(json.condition ?? {"and": []}, `${context}.condition`);
if (this.roaming && conditionIfRoaming !== undefined) {
this.condition = new And([condition, conditionIfRoaming]);
} else {
this.condition = condition;
}
if (json.freeform) {
this.freeform = {
key: json.freeform.key,

View file

@ -53,4 +53,10 @@ export interface TagRenderingConfigJson {
then: string | any
hideInAnswer?: boolean
}[]
/**
* If set to true, this tagRendering will escape the current layer and attach itself to all the other layers too.
* However, it will _only_ be shown if it matches the overpass-tags of the layer it was originally defined in.
*/
roaming?: boolean
}