diff --git a/leaflet/src/lines/lines-layer.ts b/leaflet/src/lines/lines-layer.ts index 1a818e34..62d991c5 100644 --- a/leaflet/src/lines/lines-layer.ts +++ b/leaflet/src/lines/lines-layer.ts @@ -1,5 +1,5 @@ import type { ID, Line, LinePointsEvent, ObjectWithId, Point, Stroke, Width } from "facilmap-types"; -import { FeatureGroup, latLng, type LayerOptions, Map, type PolylineOptions, type LatLngBounds } from "leaflet"; +import { FeatureGroup, latLng, type LayerOptions, type Map as LeafletMap, type PolylineOptions, type LatLngBounds } from "leaflet"; import { type HighlightableLayerOptions, HighlightablePolyline } from "leaflet-highlightable-layers"; import { type BasicTrackPoints, disconnectSegmentsOutsideViewport, tooltipOptions, trackPointsToLatLngArray, fmToLeafletBbox } from "../utils/leaflet"; import { numberKeys, quoteHtml } from "facilmap-utils"; @@ -25,13 +25,14 @@ export default class LinesLayer extends FeatureGroup { protected highlightedLinesIds = new Set(); protected hiddenLinesIds = new Set(); protected lastMapBounds?: LatLngBounds; + protected filterResults = new Map(); constructor(client: Client, options?: LinesLayerOptions) { super([], options); this.client = client; } - onAdd(map: Map): this { + onAdd(map: LeafletMap): this { super.onAdd(map); this.client.on("line", this.handleLine); @@ -41,13 +42,18 @@ export default class LinesLayer extends FeatureGroup { map.on("moveend", this.handleMoveEnd); map.on("fmFilter", this.handleFilter); - if (map._loaded) - this.handleMoveEnd(); + if (map._loaded) { + this.lastMapBounds = this._map.getBounds(); + } + + for (const lineId of numberKeys(this.client.lines)) { + this.handleLine(this.client.lines[lineId]); + } return this; } - onRemove(map: Map): this { + onRemove(map: LeafletMap): this { super.onRemove(map); this.client.removeListener("line", this.handleLine); @@ -60,11 +66,17 @@ export default class LinesLayer extends FeatureGroup { return this; } + protected recalculateFilter(line: Line): void { + this.filterResults.set(line.id, this._map.fmFilterFunc(line, this.client.types[line.typeId])); + } + protected shouldShowLine(line: Line): boolean { - return !this.hiddenLinesIds.has(line.id) && this._map.fmFilterFunc(line, this.client.types[line.typeId]); + return !this.hiddenLinesIds.has(line.id) && !!this.filterResults.get(line.id); } protected handleLine = (line: Line): void => { + this.recalculateFilter(line); + if(this.shouldShowLine(line)) this._addLine(line); else @@ -79,6 +91,7 @@ export default class LinesLayer extends FeatureGroup { protected handleDeleteLine = (data: ObjectWithId): void => { this._deleteLine(data); + this.filterResults.delete(data.id); }; protected handleMoveEnd = (): void => { @@ -87,8 +100,8 @@ export default class LinesLayer extends FeatureGroup { Promise.resolve().then(() => { const lastMapBounds = this.lastMapBounds; const mapBounds = this.lastMapBounds = this._map.getBounds(); - for(const i of numberKeys(this.client.lines)) { - const lineBounds = fmToLeafletBbox(this.client.lines[i]); + for(const lineId of numberKeys(this.client.lines)) { + const lineBounds = fmToLeafletBbox(this.client.lines[lineId]); if ( ( // We do not have to do this for lines that are either completely outside or completely within the @@ -98,21 +111,22 @@ export default class LinesLayer extends FeatureGroup { (lastMapBounds.contains(lineBounds) && mapBounds.contains(lineBounds)) || (!lastMapBounds.intersects(lineBounds) && !mapBounds.intersects(lineBounds)) ) - ) && this.shouldShowLine(this.client.lines[i]) + ) && this.shouldShowLine(this.client.lines[lineId]) ) { - this._addLine(this.client.lines[i]); + this._addLine(this.client.lines[lineId]); } } }); }; protected handleFilter = (): void => { - for(const i of numberKeys(this.client.lines)) { - const show = this.shouldShowLine(this.client.lines[i]); - if(this.linesById[i] && !show) - this._deleteLine(this.client.lines[i]); - else if(!this.linesById[i] && show) - this._addLine(this.client.lines[i]); + for(const lineId of numberKeys(this.client.lines)) { + this.recalculateFilter(this.client.lines[lineId]); + const show = this.shouldShowLine(this.client.lines[lineId]); + if(this.linesById[lineId] && !show) + this._deleteLine(this.client.lines[lineId]); + else if(!this.linesById[lineId] && show) + this._addLine(this.client.lines[lineId]); } }; diff --git a/leaflet/src/markers/markers-layer.ts b/leaflet/src/markers/markers-layer.ts index 0f5d187a..ceef2362 100644 --- a/leaflet/src/markers/markers-layer.ts +++ b/leaflet/src/markers/markers-layer.ts @@ -1,6 +1,6 @@ import type Client from "facilmap-client"; import type { ID, Marker, ObjectWithId } from "facilmap-types"; -import { Map } from "leaflet"; +import { Map as LeafletMap } from "leaflet"; import { tooltipOptions } from "../utils/leaflet"; import { numberKeys, quoteHtml } from "facilmap-utils"; import MarkerCluster, { type MarkerClusterOptions } from "./marker-cluster"; @@ -14,6 +14,7 @@ export default class MarkersLayer extends MarkerCluster { declare options: MarkersLayerOptions; protected markersById: Record = {}; protected highlightedMarkerIds = new Set(); + protected filterResults = new Map(); /** The position of these markers will not be touched until they are unlocked again. */ protected lockedMarkerIds = new Set(); @@ -22,18 +23,22 @@ export default class MarkersLayer extends MarkerCluster { super(client, options); } - onAdd(map: Map): this { + onAdd(map: LeafletMap): this { super.onAdd(map); this.client.on("marker", this.handleMarker); this.client.on("deleteMarker", this.handleDeleteMarker); + for (const markerId of numberKeys(this.client.markers)) { + this.handleMarker(this.client.markers[markerId]); + } + map.on("fmFilter", this.handleFilter); return this; } - onRemove(map: Map): this { + onRemove(map: LeafletMap): this { super.onRemove(map); this.client.removeListener("marker", this.handleMarker); @@ -44,8 +49,17 @@ export default class MarkersLayer extends MarkerCluster { return this; } + protected recalculateFilter(marker: Marker): void { + this.filterResults.set(marker.id, this._map.fmFilterFunc(marker, this.client.types[marker.typeId])); + } + + protected shouldShowMarker(marker: Marker): boolean { + return !!this.filterResults.get(marker.id); + } + protected handleMarker = (marker: Marker): void => { - if(this._map.fmFilterFunc(marker, this.client.types[marker.typeId])) + this.recalculateFilter(marker); + if(this.shouldShowMarker(marker)) this._addMarker(marker); else this._deleteMarker(marker); @@ -53,16 +67,18 @@ export default class MarkersLayer extends MarkerCluster { protected handleDeleteMarker = (data: ObjectWithId): void => { this._deleteMarker(data); + this.filterResults.delete(data.id); }; protected handleFilter = (): void => { - for(const i of numberKeys(this.client.markers)) { - if (!this.lockedMarkerIds.has(i)) { - const show = this._map.fmFilterFunc(this.client.markers[i], this.client.types[this.client.markers[i].typeId]); - if(this.markersById[i] && !show) - this._deleteMarker(this.client.markers[i]); - else if(!this.markersById[i] && show) - this._addMarker(this.client.markers[i]); + for(const markerId of numberKeys(this.client.markers)) { + if (!this.lockedMarkerIds.has(markerId)) { + this.recalculateFilter(this.client.markers[markerId]); + const show = this.shouldShowMarker(this.client.markers[markerId]); + if(this.markersById[markerId] && !show) + this._deleteMarker(this.client.markers[markerId]); + else if(!this.markersById[markerId] && show) + this._addMarker(this.client.markers[markerId]); } } }; @@ -120,7 +136,7 @@ export default class MarkersLayer extends MarkerCluster { unlockMarker(id: ID): void { this.lockedMarkerIds.delete(id); - if (this._map.fmFilterFunc(this.client.markers[id], this.client.types[this.client.markers[id].typeId])) + if (this.shouldShowMarker(this.client.markers[id])) this._addMarker(this.client.markers[id]); else this._deleteMarker(this.client.markers[id]);