diff --git a/src/UI/Map/ShowDataLayer.ts b/src/UI/Map/ShowDataLayer.ts index a7889a94d9..0a2d74cae8 100644 --- a/src/UI/Map/ShowDataLayer.ts +++ b/src/UI/Map/ShowDataLayer.ts @@ -154,7 +154,7 @@ class PointRenderingLayer { if (this._onClick) { const self = this - el.addEventListener("click", function (ev) { + el.addEventListener("click", function(ev) { ev.preventDefault() self._onClick(feature) // Workaround to signal the MapLibreAdaptor to ignore this click @@ -200,7 +200,7 @@ class LineRenderingLayer { "lineCap", "offset", "fill", - "fillColor", + "fillColor" ] as const private static readonly lineConfigKeysColor = ["color", "fillColor"] as const @@ -264,8 +264,8 @@ class LineRenderingLayer { "icon-rotation-alignment": "map", "icon-pitch-alignment": "map", "icon-image": imgId, - "icon-size": 0.055, - }, + "icon-size": 0.055 + } } const filter = img.if?.asMapboxExpression() if (filter) { @@ -338,9 +338,9 @@ class LineRenderingLayer { type: "geojson", data: { type: "FeatureCollection", - features, + features }, - promoteId: "id", + promoteId: "id" }) const linelayer = this._layername + "_line" const layer: AddLayerObject = { @@ -351,11 +351,11 @@ class LineRenderingLayer { "line-color": ["feature-state", "color"], "line-opacity": ["feature-state", "color-opacity"], "line-width": ["feature-state", "width"], - "line-offset": ["feature-state", "offset"], + "line-offset": ["feature-state", "offset"] }, layout: { - "line-cap": "round", - }, + "line-cap": "round" + } } if (this._config.dashArray) { layer.paint["line-dasharray"] = @@ -393,8 +393,8 @@ class LineRenderingLayer { layout: {}, paint: { "fill-color": ["feature-state", "fillColor"], - "fill-opacity": ["feature-state", "fillColor-opacity"], - }, + "fill-opacity": ["feature-state", "fillColor-opacity"] + } }) if (this._onClick) { map.on("click", polylayer, (e) => { @@ -425,7 +425,7 @@ class LineRenderingLayer { this.currentSourceData = features src.setData({ type: "FeatureCollection", - features: this.currentSourceData, + features: this.currentSourceData }) } } @@ -494,8 +494,7 @@ export default class ShowDataLayer { } ) { this._options = options - const self = this - this.onDestroy.push(map.addCallbackAndRunD((map) => self.initDrawFeatures(map))) + this.onDestroy.push(map.addCallbackAndRunD((map) => this.initDrawFeatures(map))) } public static showMultipleLayers( @@ -509,14 +508,24 @@ export default class ShowDataLayer { layers.filter((l) => l.source !== null).map((l) => new FilteredLayer(l)), features, { - constructStore: (features, layer) => new SimpleFeatureSource(layer, features), + constructStore: (features, layer) => new SimpleFeatureSource(layer, features) } ) + if (options?.zoomToFeatures) { + options.zoomToFeatures = false + features.features.addCallbackD(features => { + ShowDataLayer.zoomToCurrentFeatures(mlmap.data, features) + }) + mlmap.addCallbackD(map => { + ShowDataLayer.zoomToCurrentFeatures(map, features.features.data) + }) + } + perLayer.forEach((fs) => { new ShowDataLayer(mlmap, { layer: fs.layer.layerDef, features: fs, - ...(options ?? {}), + ...(options ?? {}) }) }) } @@ -529,34 +538,39 @@ export default class ShowDataLayer { return new ShowDataLayer(map, { layer: ShowDataLayer.rangeLayer, features, - doShowLayer, + doShowLayer }) } - public destruct() {} + public destruct() { + } - private zoomToCurrentFeatures(map: MlMap) { - if (this._options.zoomToFeatures) { - const features = this._options.features.features.data - const bbox = BBox.bboxAroundAll(features.map(BBox.get)) - map.resize() - map.fitBounds(bbox.toLngLat(), { - padding: { top: 10, bottom: 10, left: 10, right: 10 }, - animate: false, - }) + private static zoomToCurrentFeatures(map: MlMap, features: Feature[]) { + if (!features || !map || features.length == 0) { + return } + const bbox = BBox.bboxAroundAll(features.map(BBox.get)) + console.log("Zooming to features", bbox.asGeoJson()) + window.requestAnimationFrame(() => { + + map.resize() + map.fitBounds(bbox.toLngLat(), { + padding: { top: 10, bottom: 10, left: 10, right: 10 }, + animate: false + }) + }) } private initDrawFeatures(map: MlMap) { - let { features, doShowLayer, fetchStore, selectedElement } = this._options + const { features, doShowLayer, fetchStore, selectedElement } = this._options let onClick = this._options.onClick if (!onClick && selectedElement) { onClick = this._options.layer.title === undefined ? undefined : (feature: Feature) => { - selectedElement?.setData(feature) - } + selectedElement?.setData(feature) + } } if (this._options.drawLines !== false) { for (let i = 0; i < this._options.layer.lineRendering.length; i++) { @@ -587,6 +601,8 @@ export default class ShowDataLayer { ) } } - features.features.addCallbackAndRunD((_) => this.zoomToCurrentFeatures(map)) + if (this._options.zoomToFeatures) { + features.features.addCallbackAndRunD((features) => ShowDataLayer.zoomToCurrentFeatures(map, features)) + } } } diff --git a/src/UI/Popup/MinimapViz.ts b/src/UI/Popup/MinimapViz.ts index 4fea6bbfda..b528f17dc9 100644 --- a/src/UI/Popup/MinimapViz.ts +++ b/src/UI/Popup/MinimapViz.ts @@ -17,13 +17,13 @@ export class MinimapViz implements SpecialVisualization { { doc: "The (maximum) zoomlevel: the target zoomlevel after fitting the entire feature. The minimap will fit the entire feature, then zoom out to this zoom level. The higher, the more zoomed in with 1 being the entire world and 19 being really close", name: "zoomlevel", - defaultValue: "18", + defaultValue: "18" }, { doc: "(Matches all resting arguments) This argument should be the key of a property of the feature. The corresponding value is interpreted as either the id or the a list of ID's. The features with these ID's will be shown on this minimap. (Note: if the key is 'id', list interpration is disabled)", name: "idKey", - defaultValue: "id", - }, + defaultValue: "id" + } ] example: "`{minimap()}`, `{minimap(17, id, _list_of_embedded_feature_ids_calculated_by_calculated_tag):height:10rem; border: 2px solid black}`" @@ -78,41 +78,36 @@ export class MinimapViz implements SpecialVisualization { ) const mlmap = new UIEventSource(undefined) + const [lon, lat] = GeoOperations.centerpointCoordinates(feature) const mla = new MapLibreAdaptor(mlmap, { rasterLayer: state.mapProperties.rasterLayer, + zoom: new UIEventSource(18) }) - mla.maxzoom.setData(17) - let zoom = 18 + mla.allowMoving.setData(false) + mla.allowZooming.setData(false) + mla.location.setData({lon, lat}) + + if (args[0]) { const parsed = Number(args[0]) if (!isNaN(parsed) && parsed > 0 && parsed < 25) { - zoom = parsed + mla.zoom.setData(parsed) } } - featuresToShow.addCallbackAndRunD((features) => { - if (features.length === 0) { - return - } - const bboxGeojson = GeoOperations.bbox({ features, type: "FeatureCollection" }) - const [lon, lat] = GeoOperations.centerpointCoordinates(bboxGeojson) - mla.bounds.setData(BBox.get(bboxGeojson)) - mla.location.setData({ lon, lat }) - }) - mla.zoom.setData(zoom) - mla.allowMoving.setData(false) - mla.allowZooming.setData(false) + mlmap.addCallbackAndRun(map => console.log("Map for minimap vis is now", map)) ShowDataLayer.showMultipleLayers( mlmap, new StaticFeatureSource(featuresToShow), - state.layout.layers + state.layout.layers, + {zoomToFeatures: true} ) return new SvelteUIElement(MaplibreMap, { interactive: false, map: mlmap, - mapProperties: mla, + mapProperties: mla }) .SetClass("h-40 rounded") .SetStyle("overflow: hidden; pointer-events: none;")