Move MinimapViz to proper svelte component
This commit is contained in:
parent
4bd6f9d4ac
commit
7038fcc6f6
3 changed files with 117 additions and 139 deletions
86
src/UI/Popup/MinimapViz.svelte
Normal file
86
src/UI/Popup/MinimapViz.svelte
Normal 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>
|
|
@ -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;")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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",
|
||||||
|
|
Loading…
Reference in a new issue