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,9 +114,7 @@ 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)
|
||||||
|
|
|
@ -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(feat.geometry.type === "Point"){
|
||||||
|
|
||||||
if (layer.wayHandling === LayerConfig.WAYHANDLING_DEFAULT) {
|
for (const rendering of pointRenderings) {
|
||||||
newFeatures.push(f);
|
withIndex.push({
|
||||||
continue;
|
...feat,
|
||||||
}
|
pointRenderingIndex: rendering.index
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
// This is a a line
|
||||||
|
for (const rendering of centroidRenderings) {
|
||||||
|
withIndex.push({
|
||||||
|
...GeoOperations.centerpoint(feat),
|
||||||
|
pointRenderingIndex: rendering.index
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (let i = 0; i < lineRenderObjects.length; i++){
|
||||||
|
withIndex.push({
|
||||||
|
...feat,
|
||||||
|
lineRenderingIndex:i
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (feat.geometry.type === "Point") {
|
|
||||||
newFeatures.push(f);
|
|
||||||
// feature is a point, nothing to do here
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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,31 +277,7 @@ 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>[] = [];
|
||||||
|
|
|
@ -8,16 +8,17 @@ import LineRenderingConfigJson from "./Json/LineRenderingConfigJson";
|
||||||
export default class LineRenderingConfig extends WithContextLoader {
|
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,40 +28,43 @@ 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) {
|
||||||
|
const str = Number(render(tr, "" + deflt));
|
||||||
|
const n = Number(str);
|
||||||
|
if (isNaN(n)) {
|
||||||
|
return deflt;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
{
|
|
||||||
function rendernum(tr: TagRenderingConfig, deflt: number) {
|
|
||||||
const str = Number(render(tr, "" + deflt));
|
|
||||||
const n = Number(str);
|
|
||||||
if (isNaN(n)) {
|
|
||||||
return deflt;
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
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 dashArray = render(this.dashArray)?.split(" ")?.map(Number);
|
function render(tr: TagRenderingConfig, deflt?: string) {
|
||||||
let color = render(this.color, "#00f");
|
if (tags === undefined) {
|
||||||
|
return deflt
|
||||||
|
}
|
||||||
|
const str = tr?.GetRenderValue(tags.data)?.txt ?? deflt;
|
||||||
|
return Utils.SubstituteKeys(str, tags.data)?.replace(/{.*}/g, "");
|
||||||
|
}
|
||||||
|
|
||||||
if (color.startsWith("--")) {
|
const dashArray = render(this.dashArray)?.split(" ")?.map(Number);
|
||||||
color = getComputedStyle(document.body).getPropertyValue(
|
let color = render(this.color, "#00f");
|
||||||
"--catch-detail-color"
|
if (color.startsWith("--")) {
|
||||||
);
|
color = getComputedStyle(document.body).getPropertyValue(
|
||||||
}
|
"--catch-detail-color"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const weight = rendernum(this.width, 5);
|
const weight = rendernum(this.width, 5);
|
||||||
return {
|
const offset = rendernum(this.offset, 0)
|
||||||
color,
|
console.log("Calculated offset:", offset, "for", this.offset)
|
||||||
weight,
|
return {
|
||||||
dashArray
|
color,
|
||||||
}
|
weight,
|
||||||
|
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 {
|
||||||
this.geoLayer.addData(feat);
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
} 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) {
|
||||||
|
|
8
Utils.ts
8
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)
|
||||||
|
@ -176,7 +178,7 @@ export class Utils {
|
||||||
txt = txt.replace("{" + key + "}", tags[key] ?? "")
|
txt = txt.replace("{" + key + "}", tags[key] ?? "")
|
||||||
match = txt.match(regex)
|
match = txt.match(regex)
|
||||||
}
|
}
|
||||||
|
|
||||||
return txt;
|
return txt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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