mapcomplete/UI/Popup/MinimapViz.ts

99 lines
3.9 KiB
TypeScript

import {Store, UIEventSource} from "../../Logic/UIEventSource";
import Loc from "../../Models/Loc";
import Minimap from "../Base/Minimap";
import ShowDataMultiLayer from "../ShowDataLayer/ShowDataMultiLayer";
import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource";
import {SpecialVisualization} from "../SpecialVisualization";
export class MinimapViz implements SpecialVisualization {
funcName = "minimap"
docs = "A small map showing the selected feature."
args = [
{
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",
},
{
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",
},
]
example:
"`{minimap()}`, `{minimap(17, id, _list_of_embedded_feature_ids_calculated_by_calculated_tag):height:10rem; border: 2px solid black}`"
constr(state, tagSource, args, _) {
if (state === undefined) {
return undefined
}
const keys = [...args]
keys.splice(0, 1)
const featureStore = state.allElements.ContainingFeatures
const featuresToShow: Store<{ freshness: Date; feature: any }[]> =
tagSource.map((properties) => {
const features: { freshness: Date; feature: any }[] = []
for (const key of keys) {
const value = properties[key]
if (value === undefined || value === null) {
continue
}
let idList = [value]
if (key !== "id" && value.startsWith("[")) {
// This is a list of values
idList = JSON.parse(value)
}
for (const id of idList) {
const feature = featureStore.get(id)
if (feature === undefined) {
console.warn("No feature found for id ", id)
continue
}
features.push({
freshness: new Date(),
feature,
})
}
}
return features
})
const properties = tagSource.data
let zoom = 18
if (args[0]) {
const parsed = Number(args[0])
if (!isNaN(parsed) && parsed > 0 && parsed < 25) {
zoom = parsed
}
}
const locationSource = new UIEventSource<Loc>({
lat: Number(properties._lat),
lon: Number(properties._lon),
zoom: zoom,
})
const minimap = Minimap.createMiniMap({
background: state.backgroundLayer,
location: locationSource,
allowMoving: false,
})
locationSource.addCallback((loc) => {
if (loc.zoom > zoom) {
// We zoom back
locationSource.data.zoom = zoom
locationSource.ping()
}
})
new ShowDataMultiLayer({
leafletMap: minimap["leafletMap"],
zoomToFeatures: true,
layers: state.filteredLayers,
features: new StaticFeatureSource(featuresToShow),
})
minimap.SetStyle("overflow: hidden; pointer-events: none;")
return minimap
}
}