forked from MapComplete/MapComplete
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:
parent
77ffdc093a
commit
2a31badd3d
16 changed files with 427 additions and 394 deletions
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue