Rendering bug fixes, add 'get' to the ExtraFunctions, filtering in the GRB theme

This commit is contained in:
Pieter Vander Vennet 2021-10-28 03:15:36 +02:00
parent 10d9f18110
commit c74989e88d
9 changed files with 318 additions and 114 deletions

View file

@ -163,12 +163,41 @@ export class ExtraFunction {
}
)
private static readonly GetParsed = new ExtraFunction(
{
name: "get",
doc: "Gets the property of the feature, parses it (as JSON) and returns it. Might return 'undefined' if not defined, null, ...",
args: ["key"]
},
(params, feat) => {
return key => {
const value = feat.properties[key]
if (value === undefined) {
return undefined;
}
try {
const parsed = JSON.parse(value)
if(parsed === null){
return undefined;
}
return parsed;
} catch (e) {
console.warn("Could not parse property " + key + " due to: " + e + ", the value is " + value)
return undefined;
}
}
}
)
private static readonly allFuncs: ExtraFunction[] = [
ExtraFunction.DistanceToFunc,
ExtraFunction.OverlapFunc,
ExtraFunction.ClosestObjectFunc,
ExtraFunction.ClosestNObjectFunc,
ExtraFunction.Memberships
ExtraFunction.Memberships,
ExtraFunction.GetParsed
];
private readonly _name: string;
private readonly _args: string[];
@ -248,11 +277,11 @@ export class ExtraFunction {
console.error("Could not calculate the distance between", feature, "and", otherFeature)
throw "Undefined distance!"
}
if(distance === 0){
console.trace("Got a suspiciously zero distance between", otherFeature, "and self-feature",feature)
if (distance === 0) {
console.trace("Got a suspiciously zero distance between", otherFeature, "and self-feature", feature)
}
if (distance > maxDistance) {
continue
}

View file

@ -12,7 +12,6 @@ import OverpassFeatureSource from "../Actors/OverpassFeatureSource";
import {Changes} from "../Osm/Changes";
import GeoJsonSource from "./Sources/GeoJsonSource";
import Loc from "../../Models/Loc";
import WayHandlingApplyingFeatureSource from "./Sources/RenderingMultiPlexerFeatureSource";
import RegisteringAllFromFeatureSourceActor from "./Actors/RegisteringAllFromFeatureSourceActor";
import TiledFromLocalStorageSource from "./TiledFeatureSource/TiledFromLocalStorageSource";
import SaveTileToLocalStorageActor from "./Actors/SaveTileToLocalStorageActor";
@ -26,6 +25,7 @@ import OsmFeatureSource from "./TiledFeatureSource/OsmFeatureSource";
import {OsmConnection} from "../Osm/OsmConnection";
import {Tiles} from "../../Models/TileRange";
import TileFreshnessCalculator from "./TileFreshnessCalculator";
import {ElementStorage} from "../ElementStorage";
/**
@ -85,7 +85,8 @@ export default class FeaturePipeline {
readonly overpassMaxZoom: UIEventSource<number>;
readonly osmConnection: OsmConnection
readonly currentBounds: UIEventSource<BBox>,
readonly osmApiTileSize: UIEventSource<number>
readonly osmApiTileSize: UIEventSource<number>,
readonly allElements: ElementStorage
}) {
this.state = state;

View file

@ -3,6 +3,8 @@ import FilteredLayer from "../../../Models/FilteredLayer";
import {FeatureSourceForLayer, Tiled} from "../FeatureSource";
import Hash from "../../Web/Hash";
import {BBox} from "../../BBox";
import {ElementStorage} from "../../ElementStorage";
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig";
export default class FilteringFeatureSource implements FeatureSourceForLayer, Tiled {
public features: UIEventSource<{ feature: any; freshness: Date }[]> =
@ -12,12 +14,16 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
public readonly tileIndex: number
public readonly bbox: BBox
private readonly upstream: FeatureSourceForLayer;
private readonly state: { locationControl: UIEventSource<{ zoom: number }>; selectedElement: UIEventSource<any> };
private readonly state: {
locationControl: UIEventSource<{ zoom: number }>; selectedElement: UIEventSource<any>,
allElements: ElementStorage
};
constructor(
state: {
locationControl: UIEventSource<{ zoom: number }>,
selectedElement: UIEventSource<any>,
allElements: ElementStorage
},
tileIndex,
upstream: FeatureSourceForLayer
@ -30,23 +36,51 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
this.layer = upstream.layer;
const layer = upstream.layer;
const self = this;
upstream.features.addCallback(() => {
this. update();
self.update();
});
layer.appliedFilters.addCallback(_ => {
this.update()
self.update()
})
this._is_dirty.stabilized(250).addCallbackAndRunD(dirty => {
if (dirty) {
self.update()
}
})
this.update();
}
public update() {
private readonly _alreadyRegistered = new Set<UIEventSource<any>>();
private readonly _is_dirty = new UIEventSource(false)
private registerCallback(feature: any, layer: LayerConfig) {
const src = this.state.allElements.addOrGetElement(feature)
if (this._alreadyRegistered.has(src)) {
return
}
this._alreadyRegistered.add(src)
if (layer.isShown !== undefined) {
const self = this;
src.map(tags => layer.isShown?.GetRenderValue(tags, "yes").txt).addCallbackAndRunD(isShown => {
self._is_dirty.setData(true)
})
}
}
public update() {
const self = this;
const layer = this.upstream.layer;
const features: { feature: any; freshness: Date }[] = this.upstream.features.data;
const newFeatures = features.filter((f) => {
self.registerCallback(f.feature, layer.layerDef)
if (
this.state.selectedElement.data?.id === f.feature.id ||
f.feature.id === Hash.hash.data) {
@ -79,6 +113,7 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti
});
this.features.setData(newFeatures);
this._is_dirty.setData(false)
}
}

View file

@ -13,19 +13,19 @@ export default class LineRenderingConfig extends WithContextLoader {
public readonly dashArray: TagRenderingConfig;
public readonly offset: TagRenderingConfig;
public readonly leftRightSensitive: boolean
constructor(json: LineRenderingConfigJson, context: string) {
super(json, context)
this.color = this.tr("color", "#0000ff");
this.width = this.tr("width", "7");
this.dashArray = this.tr("dashArray", "");
this.leftRightSensitive = json.offset !== undefined && json.offset !== 0 && json.offset !== "0"
this.leftRightSensitive = json.offset !== undefined && json.offset !== 0 && json.offset !== "0"
this.offset = this.tr("offset", "0");
}
public GenerateLeafletStyle( tags: {} ):
public GenerateLeafletStyle(tags: {}):
{
color: string,
weight: number,

View file

@ -15,6 +15,7 @@ import {VariableUiElement} from "../../UI/Base/VariableUIElement";
export default class PointRenderingConfig extends WithContextLoader {
private static readonly allowed_location_codes = new Set<string>(["point", "centroid","start","end"])
public readonly location: Set<"point" | "centroid" | "start" | "end">
public readonly icon: TagRenderingConfig;
@ -25,7 +26,19 @@ export default class PointRenderingConfig extends WithContextLoader {
constructor(json: PointRenderingConfigJson, context: string) {
super(json, context)
if(typeof json.location === "string"){
json.location = [json.location]
}
this.location = new Set(json.location)
this.location.forEach(l => {
const allowed = PointRenderingConfig.allowed_location_codes
if(!allowed.has(l)){
throw `A point rendering has an invalid location: '${l}' is not one of ${Array.from(allowed).join(", ")} (at ${context}.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)"

View file

@ -212,12 +212,13 @@ export default class ShowDataLayer {
const lineRenderingIndex = feature.lineRenderingIndex
if (pointRenderingIndex !== undefined) {
const style = layer.mapRendering[pointRenderingIndex].GenerateLeafletStyle(tagsSource, this._enablePopups)
return {
icon: layer.mapRendering[pointRenderingIndex].GenerateLeafletStyle(tagsSource, this._enablePopups)
icon: style
}
}
if (lineRenderingIndex !== undefined) {
return layer.lineRendering[lineRenderingIndex].GenerateLeafletStyle(tagsSource)
return layer.lineRendering[lineRenderingIndex].GenerateLeafletStyle(tagsSource.data)
}
throw "Neither lineRendering nor mapRendering defined for " + feature
@ -232,9 +233,8 @@ export default class ShowDataLayer {
if (layer === undefined) {
return;
}
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) && this._enablePopups
let style: any = layer.mapRendering[feature.pointRenderingIndex].GenerateLeafletStyle(tagSource, clickable);
const baseElement = style.html;
if (!this._enablePopups) {

View file

@ -20,6 +20,9 @@
"startZoom": 14,
"widenFactor": 2,
"socialImage": "",
"clustering": {
"maxZoom": 15
},
"layers": [
{
"id": "OSM-buildings",
@ -28,7 +31,7 @@
"osmTags": "building~*",
"maxCacheAge": 0
},
"minzoom": 18,
"minzoom": 16,
"mapRendering": [
{
"width": {
@ -277,7 +280,7 @@
{
"location": [
"point",
"center"
"centroid"
],
"label": {
"mappings": [
@ -311,17 +314,46 @@
"geoJsonZoomLevel": 18,
"maxCacheAge": 0
},
"minzoom": 19,
"minzoom": 16,
"name": "CRAB-addressen",
"title": "CRAB-adres",
"mapRendering": [
{
"location": "point",
"location": ["point"],
"icon": "circle:#bb3322",
"iconSize": "15,15,center"
}
],
"calculatedTags": [
"_embedded_in=feat.overlapWith('OSM-buildings').filter(f => f.feat.properties['addr:housenumber'] !== undefined)[0]?.feat?.properties ",
"_embedding_nr=feat.get('_embedded_in')['addr:housenumber']",
"_embedding_street=feat.get('_embedded_in')['addr:street']"
],
"isShown": {
"render": "yes",
"mappings": [
{
"if": {
"and":["_embedding_nr:={HUISNR}","_embedding_street:={STRAATNM}"]
},
"then": "no"
}
]
},
"tagRenderings": [
{
"id": "render_crab",
"render": "Volgens het CRAB ligt hier <b>{STRAATNM}</b> {HUISNR} (label: {HNRLABEL})"
},
{
"id": "render_embedded",
"render": "Het omliggende object met addres heeft <b>{_embedding_street}</b> {_embedding_nr}",
"condition": {
"and": ["_embedding_street~*","_embedding_nr~*"]
}
},
"all_tags",
{
"id": "import-button",
@ -334,7 +366,7 @@
"name": {
"nl": "Fixmes op gebouwen"
},
"minzoom": 12,
"minzoom": 16,
"source": {
"maxCacheAge": 0,
"osmTags": {
@ -490,7 +522,7 @@
{
"location": [
"point",
"center"
"centroid"
],
"iconSize": {
"render": "40,40,center"
@ -512,12 +544,66 @@
"render": "#00f"
}
}
]
},
{
"id": "GRB",
"source": {
"geoJson": "https://betadata.grbosm.site/grb?bbox={x_min},{y_min},{x_max},{y_max}",
"geoJsonZoomLevel": 18,
"mercatorCrs": true,
"maxCacheAge": 0
},
"name": "GRB geometries",
"title": "GRB outline",
"minzoom": 16,
"calculatedTags": [
"_overlaps_with=feat.overlapWith('OSM-buildings').filter(f => f.overlap > 1 && feat.properties._surface - f.overlap < 5)[0] ?? null",
"_osm_obj:source:ref=JSON.parse(feat.properties._overlaps_with)?.feat?.properties['source:geometry:ref']",
"_osm_obj:source:date=JSON.parse(feat.properties._overlaps_with)?.feat?.properties['source:geometry:date'].replace(/\\//g, '-')",
"_imported_osm_object_found= feat.properties['_osm_obj:source:ref'] == feat.properties['source:geometry:entity'] + '/' + feat.properties['source:geometry:oidn']",
"_grb_date=feat.properties['source:geometry:date'].replace(/\\//g,'-')",
"_imported_osm_still_fresh= feat.properties['_osm_obj:source:date'] == feat.properties._grb_date"
],
"presets": []
"tagRenderings": [
"all_tags"
],
"isShown": {
"render": "yes",
"mappings": [
{
"if": {
"and": [
"_imported_osm_object_found=true",
"_imported_osm_still_fresh=true"
]
},
"then": "no"
}
]
},
"mapRendering": [
{
"color": {
"render": "#00a",
"mappings": [
{
"if": {
"and": [
"_imported_osm_object_found=true",
"_imported_osm_still_fresh=true"
]
},
"then": "#0f0"
}
]
}
}
]
}
],
"hideFromOverview": true,
"defaultBackgroundId": "AGIVFlandersGRB",
"overpassMaxZoom": 18,
"overpassMaxZoom": 15,
"osmApiTileSize": 17
}

View file

@ -57,9 +57,13 @@
},
"minzoom": 13,
"minzoomVisible": 0,
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/nature_reserve.svg"
}
"mapRendering": [
{
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/nature_reserve.svg"
}
}
]
}
},
{
@ -77,9 +81,13 @@
"isOsmCache": "duplicate"
},
"minzoom": 1,
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/nature_reserve.svg"
},
"mapRendering": [
{
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/nature_reserve.svg"
}
}
],
"presets": []
}
},
@ -96,9 +104,13 @@
"isOsmCache": true
},
"minzoom": 1,
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/information.svg"
}
"mapRendering": [
{
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/information.svg"
}
}
]
}
},
{
@ -115,19 +127,23 @@
"isOsmCache": true
},
"minzoom": 10,
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/trail.svg",
"mappings": [
{
"if": "wheelchair=yes",
"then": "circle:#FE6F32;./assets/themes/natuurpunt/walk_wheelchair.svg"
},
{
"if": "pushchair=yes",
"then": "circle:#FE6F32;./assets/themes/natuurpunt/pushchair.svg"
"mapRendering": [
{
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/trail.svg",
"mappings": [
{
"if": "wheelchair=yes",
"then": "circle:#FE6F32;./assets/themes/natuurpunt/walk_wheelchair.svg"
},
{
"if": "pushchair=yes",
"then": "circle:#FE6F32;./assets/themes/natuurpunt/pushchair.svg"
}
]
}
]
}
}
]
}
},
{
@ -139,19 +155,23 @@
"geoJsonZoomLevel": 12,
"isOsmCache": true
},
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/toilets.svg",
"mappings": [
{
"if": "wheelchair=yes",
"then": "circle:#FE6F32;./assets/themes/natuurpunt/wheelchair.svg"
},
{
"if": "toilets:position=urinals",
"then": "circle:#FE6F32;./assets/themes/natuurpunt/urinal.svg"
"mapRendering": [
{
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/toilets.svg",
"mappings": [
{
"if": "wheelchair=yes",
"then": "circle:#FE6F32;./assets/themes/natuurpunt/wheelchair.svg"
},
{
"if": "toilets:position=urinals",
"then": "circle:#FE6F32;./assets/themes/natuurpunt/urinal.svg"
}
]
}
]
}
}
]
}
},
{
@ -163,10 +183,14 @@
"geoJsonZoomLevel": 12,
"isOsmCache": true
},
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/birdhide.svg",
"mappings": null
}
"mapRendering": [
{
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/birdhide.svg",
"mappings": null
}
}
]
}
},
{
@ -178,9 +202,13 @@
"geoJsonZoomLevel": 12,
"isOsmCache": true
},
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/picnic_table.svg"
}
"mapRendering": [
{
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/picnic_table.svg"
}
}
]
}
},
{
@ -192,34 +220,42 @@
"geoJsonZoomLevel": 12,
"isOsmCache": true
},
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/drips.svg"
}
"mapRendering": [
{
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/drips.svg"
}
}
]
}
},
{
"builtin": "parking",
"override": {
"minzoom": "16",
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/parking.svg",
"mappings": [
{
"if": "amenity=bicycle_parking",
"then": "circle:#FE6F32;./assets/themes/natuurpunt/parkingbike.svg"
}
]
},
"iconOverlays": [
"mapRendering": [
{
"if": "amenity=motorcycle_parking",
"then": "circle:#335D9F;./assets/themes/natuurpunt/parkingmotor.svg",
"badge": true
},
{
"if": "capacity:disabled=yes",
"then": "circle:#335D9F;./assets/themes/natuurpunt/parkingwheels.svg",
"badge": true
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/parking.svg",
"mappings": [
{
"if": "amenity=bicycle_parking",
"then": "circle:#FE6F32;./assets/themes/natuurpunt/parkingbike.svg"
}
]
},
"iconOverlays": [
{
"if": "amenity=motorcycle_parking",
"then": "circle:#335D9F;./assets/themes/natuurpunt/parkingmotor.svg",
"badge": true
},
{
"if": "capacity:disabled=yes",
"then": "circle:#335D9F;./assets/themes/natuurpunt/parkingwheels.svg",
"badge": true
}
]
}
]
}
@ -233,9 +269,13 @@
"geoJsonZoomLevel": 12,
"isOsmCache": true
},
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/information_board.svg"
}
"mapRendering": [
{
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/information_board.svg"
}
}
]
}
},
{
@ -247,9 +287,13 @@
"geoJsonZoomLevel": 12,
"isOsmCache": true
},
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/bench.svg"
}
"mapRendering": [
{
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/bench.svg"
}
}
]
}
},
{
@ -261,9 +305,13 @@
"geoJsonZoomLevel": 12,
"isOsmCache": true
},
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/watermill.svg"
}
"mapRendering": [
{
"icon": {
"render": "circle:#FE6F32;./assets/themes/natuurpunt/watermill.svg"
}
}
]
}
}
],

View file

@ -251,12 +251,11 @@
}
]
},
"width": {
"render": "8"
},
"iconSize": {
"render": "40,40,center"
},
}
}, {
"color": {
"render": "#00f",
"mappings": [
@ -275,6 +274,9 @@
"then": "#ff0"
}
]
},
"width": {
"render": "8"
}
}
]
@ -290,17 +292,7 @@
]
}
},
"mapRendering": [
{
"location": "point",
"color": {
"render": "#ccc"
},
"width": {
"render": "0"
}
}
]
"mapRendering": []
}
],
"enableShareScreen": false,