Move MinimapViz to proper svelte component

This commit is contained in:
Pieter Vander Vennet 2024-07-16 14:43:40 +02:00
parent 4bd6f9d4ac
commit 7038fcc6f6
3 changed files with 117 additions and 139 deletions

View file

@ -0,0 +1,86 @@
<script lang="ts">
import { Store, UIEventSource } from "../../Logic/UIEventSource"
import type { Feature } from "geojson"
import { GeoOperations } from "../../Logic/GeoOperations"
import { MapLibreAdaptor } from "../Map/MapLibreAdaptor"
import type { SpecialVisualizationState } from "../SpecialVisualization"
import ShowDataLayer from "../Map/ShowDataLayer"
import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource"
import MaplibreMap from "../Map/MaplibreMap.svelte"
export let state: SpecialVisualizationState
export let tagSource: UIEventSource<Record<string, string>>
export let args: string[]
export let feature: Feature
const keys = [...args]
keys.splice(0, 1)
let featuresToShow: Store<Feature[]> = state.indexedFeatures.featuresById.map(
(featuresById) => {
if (featuresById === undefined) {
return []
}
const properties = tagSource.data
const features: Feature[] = []
for (const key of keys) {
const value = properties[key]
if (value === undefined || value === null) {
continue
}
let idList = [value]
if (Array.isArray(value)) {
idList = value
} else if (
key !== "id" &&
typeof value === "string" &&
value?.startsWith("[")
) {
// This is a list of values
idList = JSON.parse(value)
}
for (const id of idList) {
const feature = featuresById.get(id)
if (feature === undefined) {
console.warn("No feature found for id ", id)
continue
}
features.push(feature)
}
}
return features
},
[tagSource]
)
let mlmap = new UIEventSource(undefined)
let [lon, lat] = GeoOperations.centerpointCoordinates(feature)
let mla = new MapLibreAdaptor(mlmap, {
rasterLayer: state.mapProperties.rasterLayer,
zoom: new UIEventSource<number>(17),
maxzoom: new UIEventSource<number>(17)
})
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) {
mla.zoom.setData(parsed)
}
}
ShowDataLayer.showMultipleLayers(
mlmap,
new StaticFeatureSource(featuresToShow),
state.layout.layers,
{ zoomToFeatures: true }
)
</script>
<div class="h-40 rounded" style="overflow: hidden; pointer-events: none;">
<MaplibreMap interactive={false} map={mlmap} mapProperties={mla} />
</div>

View file

@ -1,115 +0,0 @@
import { Store, UIEventSource } from "../../Logic/UIEventSource"
import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource"
import { SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization"
import { Feature } from "geojson"
import { MapLibreAdaptor } from "../Map/MapLibreAdaptor"
import SvelteUIElement from "../Base/SvelteUIElement"
import MaplibreMap from "../Map/MaplibreMap.svelte"
import ShowDataLayer from "../Map/ShowDataLayer"
import { GeoOperations } from "../../Logic/GeoOperations"
import { BBox } from "../../Logic/BBox"
export class MinimapViz implements SpecialVisualization {
funcName = "minimap"
docs = "A small map showing the selected feature."
needsUrls = []
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: SpecialVisualizationState,
tagSource: UIEventSource<Record<string, string>>,
args: string[],
feature: Feature
) {
if (state === undefined || feature === undefined) {
return undefined
}
const keys = [...args]
keys.splice(0, 1)
const featuresToShow: Store<Feature[]> = state.indexedFeatures.featuresById.map(
(featuresById) => {
if (featuresById === undefined) {
return []
}
const properties = tagSource.data
const features: Feature[] = []
for (const key of keys) {
const value = properties[key]
if (value === undefined || value === null) {
continue
}
let idList = [value]
if (Array.isArray(value)) {
idList = value
} else if (
key !== "id" &&
typeof value === "string" &&
value?.startsWith("[")
) {
// This is a list of values
idList = JSON.parse(value)
}
for (const id of idList) {
const feature = featuresById.get(id)
if (feature === undefined) {
console.warn("No feature found for id ", id)
continue
}
features.push(feature)
}
}
return features
},
[tagSource]
)
const mlmap = new UIEventSource(undefined)
const [lon, lat] = GeoOperations.centerpointCoordinates(feature)
const mla = new MapLibreAdaptor(mlmap, {
rasterLayer: state.mapProperties.rasterLayer,
zoom: new UIEventSource<number>(17),
maxzoom: new UIEventSource<number>(17),
})
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) {
mla.zoom.setData(parsed)
}
}
mlmap.addCallbackAndRun((map) => console.log("Map for minimap vis is now", map))
ShowDataLayer.showMultipleLayers(
mlmap,
new StaticFeatureSource(featuresToShow),
state.layout.layers,
{ zoomToFeatures: true }
)
return new SvelteUIElement(MaplibreMap, {
interactive: false,
map: mlmap,
mapProperties: mla,
})
.SetClass("h-40 rounded")
.SetStyle("overflow: hidden; pointer-events: none;")
}
}

View file

@ -8,7 +8,7 @@ import {
SpecialVisualizationState, SpecialVisualizationState,
} from "./SpecialVisualization" } from "./SpecialVisualization"
import { HistogramViz } from "./Popup/HistogramViz" import { HistogramViz } from "./Popup/HistogramViz"
import { MinimapViz } from "./Popup/MinimapViz" import MinimapViz from "./Popup/MinimapViz.svelte"
import { ShareLinkViz } from "./Popup/ShareLinkViz" import { ShareLinkViz } from "./Popup/ShareLinkViz"
import { UploadToOsmViz } from "./Popup/UploadToOsmViz" import { UploadToOsmViz } from "./Popup/UploadToOsmViz"
import { MultiApplyViz } from "./Popup/MultiApplyViz" import { MultiApplyViz } from "./Popup/MultiApplyViz"
@ -125,7 +125,7 @@ class NearbyImageVis implements SpecialVisualization {
args: string[], args: string[],
feature: Feature, feature: Feature,
layer: LayerConfig layer: LayerConfig
): BaseUIElement { ): SvelteUIElement {
const isOpen = args[0] === "open" const isOpen = args[0] === "open"
const readonly = args[1] === "readonly" const readonly = args[1] === "readonly"
const [lon, lat] = GeoOperations.centerpointCoordinates(feature) const [lon, lat] = GeoOperations.centerpointCoordinates(feature)
@ -240,7 +240,7 @@ export class QuestionViz implements SpecialVisualization {
args: string[], args: string[],
feature: Feature, feature: Feature,
layer: LayerConfig layer: LayerConfig
): BaseUIElement { ): SvelteUIElement {
const labels = args[0] const labels = args[0]
?.split(";") ?.split(";")
?.map((s) => s.trim()) ?.map((s) => s.trim())
@ -346,26 +346,6 @@ export default class SpecialVisualizations {
return firstPart + "\n\n" + helpTexts.join("\n\n") return firstPart + "\n\n" + helpTexts.join("\n\n")
} }
// noinspection JSUnusedGlobalSymbols
public static renderExampleOfSpecial(
state: SpecialVisualizationState,
s: SpecialVisualization
): BaseUIElement {
const examples =
s.structuredExamples === undefined
? []
: s.structuredExamples().map((e) => {
return s.constr(
state,
new UIEventSource<Record<string, string>>(e.feature.properties),
e.args,
e.feature,
undefined
)
})
return new Combine([new Title(s.funcName), s.docs, ...examples])
}
private static initList(): SpecialVisualization[] { private static initList(): SpecialVisualization[] {
const specialVisualizations: SpecialVisualization[] = [ const specialVisualizations: SpecialVisualization[] = [
new QuestionViz(), new QuestionViz(),
@ -426,7 +406,34 @@ export default class SpecialVisualizations {
}, },
new HistogramViz(), new HistogramViz(),
new StealViz(), new StealViz(),
new MinimapViz(), {
funcName : "minimap",
docs :"A small map showing the selected feature.",
needsUrls : [],
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: SpecialVisualizationState,
tagSource: UIEventSource<Record<string, string>>,
args: string[],
feature: Feature
): SvelteUIElement {
return new SvelteUIElement(MinimapViz, {state, args, feature, tagSource})
}
},
{ {
funcName: "split_button", funcName: "split_button",
docs: "Adds a button which allows to split a way", docs: "Adds a button which allows to split a way",