forked from MapComplete/MapComplete
		
	First working version with multi-rendering
This commit is contained in:
		
							parent
							
								
									b9b8a5c71a
								
							
						
					
					
						commit
						0c0ef48a96
					
				
					 16 changed files with 228 additions and 135 deletions
				
			
		|  | @ -114,10 +114,8 @@ export default class FeaturePipeline { | ||||||
|             // This will already contain the merged features for this tile. In other words, this will only be triggered once for every tile
 |             // This will already contain the merged features for this tile. In other words, this will only be triggered once for every tile
 | ||||||
|             const srcFiltered = |             const srcFiltered = | ||||||
|                 new FilteringFeatureSource(state, src.tileIndex, |                 new FilteringFeatureSource(state, src.tileIndex, | ||||||
|                     new WayHandlingApplyingFeatureSource( |  | ||||||
|                         new ChangeGeometryApplicator(src, state.changes) |                         new ChangeGeometryApplicator(src, state.changes) | ||||||
|                 ) |                 ) | ||||||
|                 ) |  | ||||||
| 
 | 
 | ||||||
|             handleFeatureSource(srcFiltered) |             handleFeatureSource(srcFiltered) | ||||||
|             self.somethingLoaded.setData(true) |             self.somethingLoaded.setData(true) | ||||||
|  |  | ||||||
|  | @ -1,58 +1,62 @@ | ||||||
| /** | /** | ||||||
|  * This is the part of the pipeline which introduces extra points at the center of an area (but only if this is demanded by the wayhandling) |  * This feature source helps the ShowDataLayer class: it introduces the necessary extra features and indiciates with what renderConfig it should be rendered. | ||||||
|  */ |  */ | ||||||
| import {UIEventSource} from "../../UIEventSource"; | import {UIEventSource} from "../../UIEventSource"; | ||||||
| import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"; |  | ||||||
| import {GeoOperations} from "../../GeoOperations"; | import {GeoOperations} from "../../GeoOperations"; | ||||||
| import {FeatureSourceForLayer} from "../FeatureSource"; | import FeatureSource from "../FeatureSource"; | ||||||
|  | import PointRenderingConfig from "../../../Models/ThemeConfig/PointRenderingConfig"; | ||||||
|  | import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"; | ||||||
| 
 | 
 | ||||||
| export default class WayHandlingApplyingFeatureSource implements FeatureSourceForLayer { |  | ||||||
|     public readonly features: UIEventSource<{ feature: any; freshness: Date }[]>; |  | ||||||
|     public readonly name; |  | ||||||
|     public readonly layer; |  | ||||||
| 
 | 
 | ||||||
|     constructor(upstream: FeatureSourceForLayer) { | export default class RenderingMultiPlexerFeatureSource  { | ||||||
|          |     public readonly features: UIEventSource<(any & {pointRenderingIndex: number | undefined, lineRenderingIndex: number | undefined})[]>; | ||||||
|         this.name = "Wayhandling(" + upstream.name + ")"; |  | ||||||
|         this.layer = upstream.layer |  | ||||||
|         const layer = upstream.layer.layerDef; |  | ||||||
| 
 |  | ||||||
|         if (layer.wayHandling === LayerConfig.WAYHANDLING_DEFAULT) { |  | ||||||
|             // We don't have to do anything fancy
 |  | ||||||
|             // lets just wire up the upstream
 |  | ||||||
|             this.features = upstream.features; |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|  |     constructor(upstream: FeatureSource, layer: LayerConfig) { | ||||||
|         this.features = upstream.features.map( |         this.features = upstream.features.map( | ||||||
|             features => { |             features => { | ||||||
|                 if (features === undefined) { |                 if (features === undefined) { | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                 const newFeatures: { feature: any, freshness: Date }[] = []; |                  | ||||||
|  |                 const pointRenderObjects: { rendering: PointRenderingConfig, index: number }[] = layer.mapRendering.map((r, i) => ({rendering: r, index: i})) | ||||||
|  |                 const pointRenderings = pointRenderObjects.filter(r => r.rendering.location.has("point")) | ||||||
|  |                 const centroidRenderings = pointRenderObjects.filter(r => r.rendering.location.has("centroid")) | ||||||
|  |                  | ||||||
|  |                 const lineRenderObjects = layer.lineRendering | ||||||
|  |                  | ||||||
|  |                 const withIndex : (any & {pointRenderingIndex: number | undefined, lineRenderingIndex: number | undefined})[] = []; | ||||||
|  |                  | ||||||
|                 for (const f of features) { |                 for (const f of features) { | ||||||
|                     const feat = f.feature; |                     const feat = f.feature; | ||||||
|                      |                      | ||||||
|                     if (layer.wayHandling === LayerConfig.WAYHANDLING_DEFAULT) { |                     if(feat.geometry.type === "Point"){ | ||||||
|                         newFeatures.push(f); | 
 | ||||||
|                         continue; |                         for (const rendering of pointRenderings) { | ||||||
|  |                             withIndex.push({ | ||||||
|  |                                 ...feat, | ||||||
|  |                                 pointRenderingIndex: rendering.index | ||||||
|  |                             }) | ||||||
|  |                         } | ||||||
|  |                     }else{ | ||||||
|  |                         // This is a a line
 | ||||||
|  |                         for (const rendering of centroidRenderings) { | ||||||
|  |                             withIndex.push({ | ||||||
|  |                                 ...GeoOperations.centerpoint(feat), | ||||||
|  |                                 pointRenderingIndex: rendering.index | ||||||
|  |                             }) | ||||||
|                         } |                         } | ||||||
|                          |                          | ||||||
|                     if (feat.geometry.type === "Point") { |                          | ||||||
|                         newFeatures.push(f); |                         for (let i = 0; i < lineRenderObjects.length; i++){ | ||||||
|                         // feature is a point, nothing to do here
 |                             withIndex.push({ | ||||||
|                         continue; |                                 ...feat, | ||||||
|  |                                 lineRenderingIndex:i | ||||||
|  |                             }) | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|                     // Create the copy
 |  | ||||||
|                     const centerPoint = GeoOperations.centerpoint(feat); |  | ||||||
| 
 |  | ||||||
|                     newFeatures.push({feature: centerPoint, freshness: f.freshness}); |  | ||||||
|                     if (layer.wayHandling === LayerConfig.WAYHANDLING_CENTER_AND_WAY) { |  | ||||||
|                         newFeatures.push(f); |  | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 return newFeatures; |                 return withIndex; | ||||||
|             } |             } | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,5 +1,4 @@ | ||||||
| import {TagRenderingConfigJson} from "./TagRenderingConfigJson"; | import {TagRenderingConfigJson} from "./TagRenderingConfigJson"; | ||||||
| import {AndOrTagConfigJson} from "./TagConfigJson"; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * The LineRenderingConfig gives all details onto how to render a single line of a feature. |  * The LineRenderingConfig gives all details onto how to render a single line of a feature. | ||||||
|  | @ -27,4 +26,10 @@ export default interface LineRenderingConfigJson { | ||||||
|      * Default value: "" (empty string == full line) |      * Default value: "" (empty string == full line) | ||||||
|      */ |      */ | ||||||
|     dashArray?: string | TagRenderingConfigJson |     dashArray?: string | TagRenderingConfigJson | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * The number of pixels this line should be moved.  | ||||||
|  |      * Use a positive numbe to move to the right, a negative to move to the left (left/right as defined by the drawing direction of the line) | ||||||
|  |      */ | ||||||
|  |     offset?: number | TagRenderingConfigJson | ||||||
| } | } | ||||||
|  | @ -6,9 +6,6 @@ import PresetConfig from "./PresetConfig"; | ||||||
| import {LayerConfigJson} from "./Json/LayerConfigJson"; | import {LayerConfigJson} from "./Json/LayerConfigJson"; | ||||||
| import Translations from "../../UI/i18n/Translations"; | import Translations from "../../UI/i18n/Translations"; | ||||||
| import {TagUtils} from "../../Logic/Tags/TagUtils"; | import {TagUtils} from "../../Logic/Tags/TagUtils"; | ||||||
| import {Utils} from "../../Utils"; |  | ||||||
| import {UIEventSource} from "../../Logic/UIEventSource"; |  | ||||||
| import BaseUIElement from "../../UI/BaseUIElement"; |  | ||||||
| import FilterConfig from "./FilterConfig"; | import FilterConfig from "./FilterConfig"; | ||||||
| import {Unit} from "../Unit"; | import {Unit} from "../Unit"; | ||||||
| import DeleteConfig from "./DeleteConfig"; | import DeleteConfig from "./DeleteConfig"; | ||||||
|  | @ -207,10 +204,6 @@ export default class LayerConfig extends WithContextLoader{ | ||||||
|             .map((r, i) => new LineRenderingConfig(<LineRenderingConfigJson>r, context+".mapRendering["+i+"]")) |             .map((r, i) => new LineRenderingConfig(<LineRenderingConfigJson>r, context+".mapRendering["+i+"]")) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         if(this.mapRendering.length > 1){ |  | ||||||
|             throw "Invalid maprendering for "+this.id+", currently only one mapRendering is supported!" |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         this.tagRenderings = this.trs(json.tagRenderings, false); |         this.tagRenderings = this.trs(json.tagRenderings, false); | ||||||
| 
 | 
 | ||||||
|         const missingIds = json.tagRenderings?.filter(tr => typeof tr !== "string" && tr["builtin"] === undefined && tr["id"] === undefined) ?? []; |         const missingIds = json.tagRenderings?.filter(tr => typeof tr !== "string" && tr["builtin"] === undefined && tr["id"] === undefined) ?? []; | ||||||
|  | @ -284,32 +277,8 @@ export default class LayerConfig extends WithContextLoader{ | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     public GenerateLeafletStyle( |  | ||||||
|         tags: UIEventSource<any>, |  | ||||||
|         clickable: boolean |  | ||||||
|     ): { |  | ||||||
|         icon: { |  | ||||||
|             html: BaseUIElement; |  | ||||||
|             iconSize: [number, number]; |  | ||||||
|             iconAnchor: [number, number]; |  | ||||||
|             popupAnchor: [number, number]; |  | ||||||
|             iconUrl: string; |  | ||||||
|             className: string; |  | ||||||
|         }; |  | ||||||
|         color: string; |  | ||||||
|         weight: number; |  | ||||||
|         dashArray: number[]; |  | ||||||
|     } { |  | ||||||
|      |      | ||||||
| 
 | 
 | ||||||
|         const icon = this.mapRendering[0].GenerateLeafletStyle(tags, clickable) |  | ||||||
|         const lineStyle = (this.lineRendering[0] ?? new LineRenderingConfig({}, "default"))?.GenerateLeafletStyle(tags) |  | ||||||
|         return { |  | ||||||
|             icon: icon, |  | ||||||
|             ...lineStyle |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public ExtractImages(): Set<string> { |     public ExtractImages(): Set<string> { | ||||||
|         const parts: Set<string>[] = []; |         const parts: Set<string>[] = []; | ||||||
|         parts.push(...this.tagRenderings?.map((tr) => tr.ExtractImages(false))); |         parts.push(...this.tagRenderings?.map((tr) => tr.ExtractImages(false))); | ||||||
|  |  | ||||||
|  | @ -11,13 +11,14 @@ export default class LineRenderingConfig extends WithContextLoader { | ||||||
|     public readonly color: TagRenderingConfig; |     public readonly color: TagRenderingConfig; | ||||||
|     public readonly width: TagRenderingConfig; |     public readonly width: TagRenderingConfig; | ||||||
|     public readonly dashArray: TagRenderingConfig; |     public readonly dashArray: TagRenderingConfig; | ||||||
|  |     public readonly offset: TagRenderingConfig; | ||||||
| 
 | 
 | ||||||
|     constructor(json: LineRenderingConfigJson, context: string) { |     constructor(json: LineRenderingConfigJson, context: string) { | ||||||
|         super(json, context) |         super(json, context) | ||||||
|         this.color = this.tr("color", "#0000ff"); |         this.color = this.tr("color", "#0000ff"); | ||||||
|         this.width = this.tr("width", "7"); |         this.width = this.tr("width", "7"); | ||||||
|         this.dashArray = this.tr("dashArray", ""); |         this.dashArray = this.tr("dashArray", ""); | ||||||
| 
 |         this.offset = this.tr("offset", "0"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -27,9 +28,9 @@ export default class LineRenderingConfig extends WithContextLoader { | ||||||
|         { |         { | ||||||
|             color: string, |             color: string, | ||||||
|             weight: number, |             weight: number, | ||||||
|             dashArray: number[] |             dashArray: number[], | ||||||
|         } |             offset: number | ||||||
|      { |         } { | ||||||
|         function rendernum(tr: TagRenderingConfig, deflt: number) { |         function rendernum(tr: TagRenderingConfig, deflt: number) { | ||||||
|             const str = Number(render(tr, "" + deflt)); |             const str = Number(render(tr, "" + deflt)); | ||||||
|             const n = Number(str); |             const n = Number(str); | ||||||
|  | @ -38,17 +39,17 @@ export default class LineRenderingConfig extends WithContextLoader { | ||||||
|             } |             } | ||||||
|             return n; |             return n; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         function render(tr: TagRenderingConfig, deflt?: string) { |         function render(tr: TagRenderingConfig, deflt?: string) { | ||||||
|             if (tags === undefined) { |             if (tags === undefined) { | ||||||
|                 return deflt |                 return deflt | ||||||
|             } |             } | ||||||
|             const str = tr?.GetRenderValue(tags.data)?.txt ?? deflt; |             const str = tr?.GetRenderValue(tags.data)?.txt ?? deflt; | ||||||
|              return Utils.SubstituteKeys(str, tags.data).replace(/{.*}/g, ""); |             return Utils.SubstituteKeys(str, tags.data)?.replace(/{.*}/g, ""); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const dashArray = render(this.dashArray)?.split(" ")?.map(Number); |         const dashArray = render(this.dashArray)?.split(" ")?.map(Number); | ||||||
|         let color = render(this.color, "#00f"); |         let color = render(this.color, "#00f"); | ||||||
| 
 |  | ||||||
|         if (color.startsWith("--")) { |         if (color.startsWith("--")) { | ||||||
|             color = getComputedStyle(document.body).getPropertyValue( |             color = getComputedStyle(document.body).getPropertyValue( | ||||||
|                 "--catch-detail-color" |                 "--catch-detail-color" | ||||||
|  | @ -56,10 +57,13 @@ export default class LineRenderingConfig extends WithContextLoader { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const weight = rendernum(this.width, 5); |         const weight = rendernum(this.width, 5); | ||||||
|  |         const offset = rendernum(this.offset, 0) | ||||||
|  |         console.log("Calculated offset:", offset, "for", this.offset) | ||||||
|         return { |         return { | ||||||
|             color, |             color, | ||||||
|             weight, |             weight, | ||||||
|              dashArray |             dashArray, | ||||||
|  |             offset | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -15,6 +15,8 @@ import {VariableUiElement} from "../../UI/Base/VariableUIElement"; | ||||||
| 
 | 
 | ||||||
| export default class PointRenderingConfig extends WithContextLoader { | export default class PointRenderingConfig extends WithContextLoader { | ||||||
| 
 | 
 | ||||||
|  |     public readonly location: Set<"point" | "centroid"> | ||||||
|  | 
 | ||||||
|     public readonly icon: TagRenderingConfig; |     public readonly icon: TagRenderingConfig; | ||||||
|     public readonly iconBadges: { if: TagsFilter; then: TagRenderingConfig }[]; |     public readonly iconBadges: { if: TagsFilter; then: TagRenderingConfig }[]; | ||||||
|     public readonly iconSize: TagRenderingConfig; |     public readonly iconSize: TagRenderingConfig; | ||||||
|  | @ -23,6 +25,11 @@ export default class PointRenderingConfig extends WithContextLoader { | ||||||
| 
 | 
 | ||||||
|     constructor(json: PointRenderingConfigJson, context: string) { |     constructor(json: PointRenderingConfigJson, context: string) { | ||||||
|         super(json, context) |         super(json, context) | ||||||
|  |         this.location = new Set(json.location) | ||||||
|  | 
 | ||||||
|  |         if(this.location.size == 0){ | ||||||
|  |             throw "A pointRendering should have at least one 'location' to defined where it should be rendered. (At "+context+".location)" | ||||||
|  |         } | ||||||
|         this.icon = this.tr("icon", ""); |         this.icon = this.tr("icon", ""); | ||||||
|         this.iconBadges = (json.iconBadges ?? []).map((overlay, i) => { |         this.iconBadges = (json.iconBadges ?? []).map((overlay, i) => { | ||||||
|             let tr : TagRenderingConfig; |             let tr : TagRenderingConfig; | ||||||
|  | @ -114,7 +121,7 @@ export default class PointRenderingConfig extends WithContextLoader { | ||||||
|         return new VariableUiElement(tags.map(tags => { |         return new VariableUiElement(tags.map(tags => { | ||||||
|             const rotation = self.rotation?.GetRenderValue(tags)?.txt ?? "0deg" |             const rotation = self.rotation?.GetRenderValue(tags)?.txt ?? "0deg" | ||||||
|              |              | ||||||
|             const htmlDefs = self.icon.GetRenderValue(tags)?.txt |             const htmlDefs = Utils.SubstituteKeys(self.icon.GetRenderValue(tags)?.txt, tags) | ||||||
|             let defaultPin : BaseUIElement = undefined |             let defaultPin : BaseUIElement = undefined | ||||||
|             if(self.label === undefined){ |             if(self.label === undefined){ | ||||||
|                 defaultPin =  Svg.teardrop_with_hole_green_svg() |                 defaultPin =  Svg.teardrop_with_hole_green_svg() | ||||||
|  | @ -137,7 +144,7 @@ export default class PointRenderingConfig extends WithContextLoader { | ||||||
|                         return undefined |                         return undefined | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     const htmlDefs = badge.then.GetRenderValue(tags)?.txt |                     const htmlDefs = Utils.SubstituteKeys(badge.then.GetRenderValue(tags)?.txt, tags) | ||||||
|                     const badgeElement= PointRenderingConfig.FromHtmlMulti(htmlDefs, "0", true)?.SetClass("block relative") |                     const badgeElement= PointRenderingConfig.FromHtmlMulti(htmlDefs, "0", true)?.SetClass("block relative") | ||||||
|                     if(badgeElement === undefined){ |                     if(badgeElement === undefined){ | ||||||
|                         return undefined; |                         return undefined; | ||||||
|  |  | ||||||
|  | @ -47,6 +47,12 @@ export default class TagRenderingConfig { | ||||||
|             this.condition = null; |             this.condition = null; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         if(typeof json === "number"){ | ||||||
|  |             this.render =Translations.WT( ""+json) | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |          | ||||||
|         if (json === undefined) { |         if (json === undefined) { | ||||||
|             throw "Initing a TagRenderingConfig with undefined in " + context; |             throw "Initing a TagRenderingConfig with undefined in " + context; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -16,12 +16,12 @@ export default class AddNewMarker extends Combine { | ||||||
|                 const layer = filteredLayer.layerDef; |                 const layer = filteredLayer.layerDef; | ||||||
|                 for (const preset of filteredLayer.layerDef.presets) { |                 for (const preset of filteredLayer.layerDef.presets) { | ||||||
|                     const tags = TagUtils.KVtoProperties(preset.tags) |                     const tags = TagUtils.KVtoProperties(preset.tags) | ||||||
|                     const icon = layer.GenerateLeafletStyle(new UIEventSource<any>(tags), false).icon.html |                     const icon = layer.mapRendering[0].GenerateLeafletStyle(new UIEventSource<any>(tags), false).html | ||||||
|                         .SetClass("block relative") |                         .SetClass("block relative") | ||||||
|                         .SetStyle("width: 42px; height: 42px;"); |                         .SetStyle("width: 42px; height: 42px;"); | ||||||
|                     icons.push(icon) |                     icons.push(icon) | ||||||
|                     if (last === undefined) { |                     if (last === undefined) { | ||||||
|                         last = layer.GenerateLeafletStyle(new UIEventSource<any>(tags), false).icon.html |                         last = layer.mapRendering[0].GenerateLeafletStyle(new UIEventSource<any>(tags), false).html | ||||||
|                             .SetClass("block relative") |                             .SetClass("block relative") | ||||||
|                             .SetStyle("width: 42px; height: 42px;"); |                             .SetStyle("width: 42px; height: 42px;"); | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|  | @ -368,7 +368,7 @@ export default class SimpleAddUI extends Toggle { | ||||||
|             for (const preset of presets) { |             for (const preset of presets) { | ||||||
| 
 | 
 | ||||||
|                 const tags = TagUtils.KVtoProperties(preset.tags ?? []); |                 const tags = TagUtils.KVtoProperties(preset.tags ?? []); | ||||||
|                 let icon: () => BaseUIElement = () => layer.layerDef.GenerateLeafletStyle(new UIEventSource<any>(tags), false).icon.html |                 let icon: () => BaseUIElement = () => layer.layerDef.mapRendering[0]. GenerateLeafletStyle(new UIEventSource<any>(tags), false).html | ||||||
|                     .SetClass("w-12 h-12 block relative"); |                     .SetClass("w-12 h-12 block relative"); | ||||||
|                 const presetInfo: PresetInfo = { |                 const presetInfo: PresetInfo = { | ||||||
|                     tags: preset.tags, |                     tags: preset.tags, | ||||||
|  |  | ||||||
|  | @ -6,12 +6,14 @@ import LayerConfig from "../../Models/ThemeConfig/LayerConfig"; | ||||||
| import FeatureInfoBox from "../Popup/FeatureInfoBox"; | import FeatureInfoBox from "../Popup/FeatureInfoBox"; | ||||||
| import {ShowDataLayerOptions} from "./ShowDataLayerOptions"; | import {ShowDataLayerOptions} from "./ShowDataLayerOptions"; | ||||||
| import {ElementStorage} from "../../Logic/ElementStorage"; | import {ElementStorage} from "../../Logic/ElementStorage"; | ||||||
|  | import RenderingMultiPlexerFeatureSource from "../../Logic/FeatureSource/Sources/WayHandlingApplyingFeatureSource"; | ||||||
|  | import 'leaflet-polylineoffset'; | ||||||
| 
 | 
 | ||||||
| export default class ShowDataLayer { | export default class ShowDataLayer { | ||||||
| 
 | 
 | ||||||
|     private readonly _leafletMap: UIEventSource<L.Map>; |     private readonly _leafletMap: UIEventSource<L.Map>; | ||||||
|     private readonly _enablePopups: boolean; |     private readonly _enablePopups: boolean; | ||||||
|     private readonly _features: UIEventSource<{ feature: any }[]> |     private readonly _features: RenderingMultiPlexerFeatureSource | ||||||
|     private readonly _layerToShow: LayerConfig; |     private readonly _layerToShow: LayerConfig; | ||||||
|     private readonly _selectedElement: UIEventSource<any> |     private readonly _selectedElement: UIEventSource<any> | ||||||
|     private readonly allElements : ElementStorage |     private readonly allElements : ElementStorage | ||||||
|  | @ -41,8 +43,7 @@ export default class ShowDataLayer { | ||||||
|             console.error("Invalid ShowDataLayer invocation: options.features is undefed") |             console.error("Invalid ShowDataLayer invocation: options.features is undefed") | ||||||
|             throw "Invalid ShowDataLayer invocation: options.features is undefed" |             throw "Invalid ShowDataLayer invocation: options.features is undefed" | ||||||
|         } |         } | ||||||
|         const features = options.features.features.map(featFreshes => featFreshes.map(ff => ff.feature)); |         this._features = new RenderingMultiPlexerFeatureSource(options.features, options.layerToShow); | ||||||
|         this._features = features; |  | ||||||
|         this._layerToShow = options.layerToShow; |         this._layerToShow = options.layerToShow; | ||||||
|         this._selectedElement = options.selectedElement |         this._selectedElement = options.selectedElement | ||||||
|         this.allElements = options.allElements; |         this.allElements = options.allElements; | ||||||
|  | @ -53,7 +54,7 @@ export default class ShowDataLayer { | ||||||
|             } |             } | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|         features.addCallback(_ => self.update(options)); |         this._features.features.addCallback(_ => self.update(options)); | ||||||
|         options.doShowLayer?.addCallback(doShow => { |         options.doShowLayer?.addCallback(doShow => { | ||||||
|             const mp = options.leafletMap.data; |             const mp = options.leafletMap.data; | ||||||
|             if (mp == undefined) { |             if (mp == undefined) { | ||||||
|  | @ -109,7 +110,7 @@ export default class ShowDataLayer { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private update(options: ShowDataLayerOptions) { |     private update(options: ShowDataLayerOptions) { | ||||||
|         if (this._features.data === undefined) { |         if (this._features.features.data === undefined) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         this.isDirty = true; |         this.isDirty = true; | ||||||
|  | @ -139,13 +140,25 @@ export default class ShowDataLayer { | ||||||
|             onEachFeature: (feature, leafletLayer) => self.postProcessFeature(feature, leafletLayer) |             onEachFeature: (feature, leafletLayer) => self.postProcessFeature(feature, leafletLayer) | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         const allFeats = this._features.data; |         const allFeats = this._features.features.data; | ||||||
|         for (const feat of allFeats) { |         for (const feat of allFeats) { | ||||||
|             if (feat === undefined) { |             if (feat === undefined) { | ||||||
|                 continue |                 continue | ||||||
|             } |             } | ||||||
|             try { |             try { | ||||||
|  |                  | ||||||
|  |                 if((feat.geometry.type === "LineString" || feat.geometry.type === "MultiLineString")) { | ||||||
|  |                     const coords = L.GeoJSON.coordsToLatLngs(feat.geometry.coordinates) | ||||||
|  |                     const tagsSource = this.allElements?.addOrGetElement(feat) ?? new UIEventSource<any>(feat.properties); | ||||||
|  |                     const lineStyle = this._layerToShow.lineRendering[feat.lineRenderingIndex].GenerateLeafletStyle(tagsSource) | ||||||
|  |                     const offsettedLine = L.polyline(coords, lineStyle); | ||||||
|  |                      | ||||||
|  |                     this.postProcessFeature(feat, offsettedLine) | ||||||
|  |                      | ||||||
|  |                     offsettedLine.addTo(this.geoLayer) | ||||||
|  |                 }else{ | ||||||
|                     this.geoLayer.addData(feat); |                     this.geoLayer.addData(feat); | ||||||
|  |                 } | ||||||
|             } catch (e) { |             } catch (e) { | ||||||
|                 console.error("Could not add ", feat, "to the geojson layer in leaflet due to", e, e.stack) |                 console.error("Could not add ", feat, "to the geojson layer in leaflet due to", e, e.stack) | ||||||
|             } |             } | ||||||
|  | @ -170,7 +183,20 @@ export default class ShowDataLayer { | ||||||
|         const tagsSource = this.allElements?.addOrGetElement(feature) ?? new UIEventSource<any>(feature.properties); |         const tagsSource = this.allElements?.addOrGetElement(feature) ?? new UIEventSource<any>(feature.properties); | ||||||
|         // Every object is tied to exactly one layer
 |         // Every object is tied to exactly one layer
 | ||||||
|         const layer = this._layerToShow |         const layer = this._layerToShow | ||||||
|         return layer?.GenerateLeafletStyle(tagsSource, true); |          | ||||||
|  |         const pointRenderingIndex = feature.pointRenderingIndex | ||||||
|  |         const lineRenderingIndex = feature.lineRenderingIndex | ||||||
|  |          | ||||||
|  |         if(pointRenderingIndex !== undefined){ | ||||||
|  |             return { | ||||||
|  |                 icon: layer.mapRendering[pointRenderingIndex].GenerateLeafletStyle(tagsSource, this._enablePopups) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if(lineRenderingIndex !== undefined){ | ||||||
|  |             return layer.lineRendering[lineRenderingIndex].GenerateLeafletStyle(tagsSource) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         throw "Neither lineRendering nor mapRendering defined for "+feature | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private pointToLayer(feature, latLng): L.Layer { |     private pointToLayer(feature, latLng): L.Layer { | ||||||
|  | @ -185,20 +211,14 @@ export default class ShowDataLayer { | ||||||
| 
 | 
 | ||||||
|         let tagSource = this.allElements?.getEventSourceById(feature.properties.id) ?? new UIEventSource<any>(feature.properties) |         let tagSource = this.allElements?.getEventSourceById(feature.properties.id) ?? new UIEventSource<any>(feature.properties) | ||||||
|         const clickable = !(layer.title === undefined && (layer.tagRenderings ?? []).length === 0) |         const clickable = !(layer.title === undefined && (layer.tagRenderings ?? []).length === 0) | ||||||
|         const style = layer.GenerateLeafletStyle(tagSource, clickable); |         let style : any = layer.mapRendering[feature.pointRenderingIndex].GenerateLeafletStyle(tagSource, clickable); | ||||||
|         const baseElement = style.icon.html; |         const baseElement = style.html; | ||||||
|         if (!this._enablePopups) { |         if (!this._enablePopups) { | ||||||
|             baseElement.SetStyle("cursor: initial !important") |             baseElement.SetStyle("cursor: initial !important") | ||||||
|         } |         } | ||||||
|  |         style.html = style.html.ConstructElement() | ||||||
|         return L.marker(latLng, { |         return L.marker(latLng, { | ||||||
|             icon: L.divIcon({ |             icon: L.divIcon(style) | ||||||
|                 html: baseElement.ConstructElement(), |  | ||||||
|                 className: style.icon.className, |  | ||||||
|                 iconAnchor: style.icon.iconAnchor, |  | ||||||
|                 iconUrl: style.icon.iconUrl ?? "./assets/svg/bug.svg", |  | ||||||
|                 popupAnchor: style.icon.popupAnchor, |  | ||||||
|                 iconSize: style.icon.iconSize |  | ||||||
|             }) |  | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -228,7 +248,7 @@ export default class ShowDataLayer { | ||||||
| 
 | 
 | ||||||
|         let infobox: FeatureInfoBox = undefined; |         let infobox: FeatureInfoBox = undefined; | ||||||
| 
 | 
 | ||||||
|         const id = `popup-${feature.properties.id}-${feature.geometry.type}-${this.showDataLayerid}-${this._cleanCount}` |         const id = `popup-${feature.properties.id}-${feature.geometry.type}-${this.showDataLayerid}-${this._cleanCount}-${feature.pointerRenderingIndex ?? feature.lineRenderingIndex}` | ||||||
|         popup.setContent(`<div style='height: 65vh' id='${id}'>Popup for ${feature.properties.id} ${feature.geometry.type} ${id} is loading</div>`) |         popup.setContent(`<div style='height: 65vh' id='${id}'>Popup for ${feature.properties.id} ${feature.geometry.type} ${id} is loading</div>`) | ||||||
|         leafletLayer.on("popupopen", () => { |         leafletLayer.on("popupopen", () => { | ||||||
|             if (infobox === undefined) { |             if (infobox === undefined) { | ||||||
|  |  | ||||||
							
								
								
									
										6
									
								
								Utils.ts
									
										
									
									
									
								
							
							
						
						
									
										6
									
								
								Utils.ts
									
										
									
									
									
								
							|  | @ -165,8 +165,10 @@ export class Utils { | ||||||
|         return [a.substr(0, index), a.substr(index + sep.length)]; |         return [a.substr(0, index), a.substr(index + sep.length)]; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static SubstituteKeys(txt: string, tags: any) { |     public static SubstituteKeys(txt: string | undefined, tags: any): string | undefined { | ||||||
| 
 |         if (txt === undefined) { | ||||||
|  |             return undefined | ||||||
|  |         } | ||||||
|         const regex = /.*{([^}]*)}.*/ |         const regex = /.*{([^}]*)}.*/ | ||||||
| 
 | 
 | ||||||
|         let match = txt.match(regex) |         let match = txt.match(regex) | ||||||
|  |  | ||||||
|  | @ -489,7 +489,7 @@ | ||||||
|     "mapRendering": [ |     "mapRendering": [ | ||||||
|         { |         { | ||||||
|             "icon": { |             "icon": { | ||||||
|                 "render": "./assets/themes/bookcases/bookcase.svg;" |                 "render": "./assets/themes/bookcases/bookcase.svg" | ||||||
|             }, |             }, | ||||||
|             "label": { |             "label": { | ||||||
|                 "mappings": [ |                 "mappings": [ | ||||||
|  |  | ||||||
							
								
								
									
										61
									
								
								assets/themes/sidewalks/sidewalks.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								assets/themes/sidewalks/sidewalks.json
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,61 @@ | ||||||
|  | { | ||||||
|  |   "id": "sidewalks", | ||||||
|  |   "title": { | ||||||
|  |     "en": "Sidewalks" | ||||||
|  |   }, | ||||||
|  |   "shortDescription": { | ||||||
|  |     "en": "Sidewalk mapping" | ||||||
|  |   }, | ||||||
|  |   "description": { | ||||||
|  |     "en": "Experimental theme" | ||||||
|  |   }, | ||||||
|  |   "language": [ | ||||||
|  |     "en" | ||||||
|  |   ], | ||||||
|  |   "maintainer": "", | ||||||
|  |   "icon": "./assets/svg/bug.svg", | ||||||
|  |   "version": "0", | ||||||
|  |   "startLat": 0, | ||||||
|  |   "startLon": 0, | ||||||
|  |   "startZoom": 1, | ||||||
|  |   "widenFactor": 0.05, | ||||||
|  |   "socialImage": "", | ||||||
|  |   "layers": [ | ||||||
|  |     { | ||||||
|  |       "id": "sidewalks", | ||||||
|  |       "name": { | ||||||
|  |         "en": "Sidewalks" | ||||||
|  |       }, | ||||||
|  |       "minzoom": 12, | ||||||
|  |       "source": { | ||||||
|  |         "osmTags": "highway=residential" | ||||||
|  |       }, | ||||||
|  |       "title": { | ||||||
|  |         "render": { | ||||||
|  |           "en": "Street {name}" | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       "description": { | ||||||
|  |         "en": "Layer showing sidewalks of highways" | ||||||
|  |       }, | ||||||
|  |       "tagRenderings": [], | ||||||
|  |       "mapRendering": [ | ||||||
|  |         { | ||||||
|  |           "color": "#ddd", | ||||||
|  |           "width": 8 | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "color": "#888", | ||||||
|  |           "width": 8, | ||||||
|  |           "offset": -8 | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "color": "#888", | ||||||
|  |           "width": 8, | ||||||
|  |           "offset": 8 | ||||||
|  |         } | ||||||
|  |       ], | ||||||
|  |   "allowSplit": true | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										11
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							|  | @ -30,6 +30,7 @@ | ||||||
|         "jspdf": "^2.3.1", |         "jspdf": "^2.3.1", | ||||||
|         "latlon2country": "^1.1.3", |         "latlon2country": "^1.1.3", | ||||||
|         "leaflet": "^1.7.1", |         "leaflet": "^1.7.1", | ||||||
|  |         "leaflet-polylineoffset": "^1.1.1", | ||||||
|         "leaflet-providers": "^1.13.0", |         "leaflet-providers": "^1.13.0", | ||||||
|         "leaflet-simple-map-screenshoter": "^0.4.4", |         "leaflet-simple-map-screenshoter": "^0.4.4", | ||||||
|         "leaflet.markercluster": "^1.4.1", |         "leaflet.markercluster": "^1.4.1", | ||||||
|  | @ -10034,6 +10035,11 @@ | ||||||
|       "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.7.1.tgz", |       "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.7.1.tgz", | ||||||
|       "integrity": "sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw==" |       "integrity": "sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw==" | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/leaflet-polylineoffset": { | ||||||
|  |       "version": "1.1.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/leaflet-polylineoffset/-/leaflet-polylineoffset-1.1.1.tgz", | ||||||
|  |       "integrity": "sha512-WcEjAROx9IhIVwSMoFy9p2QBCG9YeuGtJl4ZdunIgj4xbCdTrUkBj8JdonUeCyLPnD2/Vrem/raOPHm5LvebSw==" | ||||||
|  |     }, | ||||||
|     "node_modules/leaflet-providers": { |     "node_modules/leaflet-providers": { | ||||||
|       "version": "1.13.0", |       "version": "1.13.0", | ||||||
|       "resolved": "https://registry.npmjs.org/leaflet-providers/-/leaflet-providers-1.13.0.tgz", |       "resolved": "https://registry.npmjs.org/leaflet-providers/-/leaflet-providers-1.13.0.tgz", | ||||||
|  | @ -25964,6 +25970,11 @@ | ||||||
|       "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.7.1.tgz", |       "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.7.1.tgz", | ||||||
|       "integrity": "sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw==" |       "integrity": "sha512-/xwPEBidtg69Q3HlqPdU3DnrXQOvQU/CCHA1tcDQVzOwm91YMYaILjNp7L4Eaw5Z4sOYdbBz6koWyibppd8Zqw==" | ||||||
|     }, |     }, | ||||||
|  |     "leaflet-polylineoffset": { | ||||||
|  |       "version": "1.1.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/leaflet-polylineoffset/-/leaflet-polylineoffset-1.1.1.tgz", | ||||||
|  |       "integrity": "sha512-WcEjAROx9IhIVwSMoFy9p2QBCG9YeuGtJl4ZdunIgj4xbCdTrUkBj8JdonUeCyLPnD2/Vrem/raOPHm5LvebSw==" | ||||||
|  |     }, | ||||||
|     "leaflet-providers": { |     "leaflet-providers": { | ||||||
|       "version": "1.13.0", |       "version": "1.13.0", | ||||||
|       "resolved": "https://registry.npmjs.org/leaflet-providers/-/leaflet-providers-1.13.0.tgz", |       "resolved": "https://registry.npmjs.org/leaflet-providers/-/leaflet-providers-1.13.0.tgz", | ||||||
|  |  | ||||||
|  | @ -77,6 +77,7 @@ | ||||||
|     "jspdf": "^2.3.1", |     "jspdf": "^2.3.1", | ||||||
|     "latlon2country": "^1.1.3", |     "latlon2country": "^1.1.3", | ||||||
|     "leaflet": "^1.7.1", |     "leaflet": "^1.7.1", | ||||||
|  |     "leaflet-polylineoffset": "^1.1.1", | ||||||
|     "leaflet-providers": "^1.13.0", |     "leaflet-providers": "^1.13.0", | ||||||
|     "leaflet-simple-map-screenshoter": "^0.4.4", |     "leaflet-simple-map-screenshoter": "^0.4.4", | ||||||
|     "leaflet.markercluster": "^1.4.1", |     "leaflet.markercluster": "^1.4.1", | ||||||
|  |  | ||||||
|  | @ -13,6 +13,11 @@ import LineRenderingConfigJson from "../Models/ThemeConfig/Json/LineRenderingCon | ||||||
|  * In place fix |  * In place fix | ||||||
|  */ |  */ | ||||||
| function fixLayerConfig(config: LayerConfigJson): void { | function fixLayerConfig(config: LayerConfigJson): void { | ||||||
|  |     if(config["overpassTags"]){ | ||||||
|  |         config.source.osmTags = config["overpassTags"] | ||||||
|  |         delete config["overpassTags"] | ||||||
|  |     } | ||||||
|  |      | ||||||
|     if (config.tagRenderings !== undefined) { |     if (config.tagRenderings !== undefined) { | ||||||
|         for (const tagRendering of config.tagRenderings) { |         for (const tagRendering of config.tagRenderings) { | ||||||
|             if (tagRendering["#"] !== undefined) { |             if (tagRendering["#"] !== undefined) { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue