2023-04-20 01:52:23 +02:00
< script lang = "ts" >
/**
* This component shows a map which focuses on a single OSM-Way (linestring) feature.
* Clicking the map will add a new 'scissor' point, projected on the linestring (and possible snapped to an already existing node within the linestring;
* clicking this point again will remove it.
* The bound 'value' will contain the location of these projected points.
* Points are not coalesced with already existing nodes within the way; it is up to the code actually splitting the way to decide to reuse an existing point or not
*
* This component is _not_ responsible for the rest of the flow, e.g. the confirm button
*/
2023-06-14 20:39:36 +02:00
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
import type { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson"
2023-07-15 18:04:30 +02:00
import split_point from "../../../assets/layers/split_point/split_point.json"
import split_road from "../../../assets/layers/split_road/split_road.json"
2023-06-14 20:39:36 +02:00
import { UIEventSource } from "../../Logic/UIEventSource"
import { Map as MlMap } from "maplibre-gl"
import type { MapProperties } from "../../Models/MapProperties"
import { MapLibreAdaptor } from "../Map/MapLibreAdaptor"
import MaplibreMap from "../Map/MaplibreMap.svelte"
import { OsmWay } from "../../Logic/Osm/OsmObject"
import ShowDataLayer from "../Map/ShowDataLayer"
import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource"
import { GeoOperations } from "../../Logic/GeoOperations"
import { BBox } from "../../Logic/BBox"
import type { Feature , LineString , Point } from "geojson"
2024-03-04 15:31:09 +01:00
import type { SpecialVisualizationState } from "../SpecialVisualization"
import SmallZoomButtons from "../Map/SmallZoomButtons.svelte"
2023-04-20 01:52:23 +02:00
const splitpoint_style = new LayerConfig(
< LayerConfigJson > split_point,
"(BUILTIN) SplitRoadWizard.ts",
2024-04-13 02:40:21 +02:00
true
2024-03-04 15:31:09 +01:00
)
2023-04-20 01:52:23 +02:00
const splitroad_style = new LayerConfig(
< LayerConfigJson > split_road,
"(BUILTIN) SplitRoadWizard.ts",
2024-04-13 02:40:21 +02:00
true
2024-03-04 15:31:09 +01:00
)
2023-04-20 01:52:23 +02:00
/**
* The way to focus on
*/
export let osmWay: OsmWay
/**
* How to render this layer.
* A default is given
*/
export let layer: LayerConfig = splitroad_style
2024-03-04 15:31:09 +01:00
export let state: SpecialVisualizationState | undefined = undefined
2023-06-14 20:39:36 +02:00
/**
* Optional: use these properties to set e.g. background layer
*/
export let mapProperties: undefined | Partial< MapProperties > = undefined
2024-11-19 16:42:53 +01:00
/**
* Reuse a point if the clicked location is within this amount of meter
*/
2024-11-28 12:00:23 +01:00
export let snapTolerance: number = 5
2024-11-19 16:42:53 +01:00
2023-06-14 20:39:36 +02:00
let map: UIEventSource< MlMap > = new UIEventSource< MlMap > (undefined)
let adaptor = new MapLibreAdaptor(map, mapProperties)
2025-03-07 00:32:20 +01:00
let wayGeojson: Feature< LineString > = < Feature < LineString > >osmWay.asGeoJson()
2023-04-20 01:52:23 +02:00
adaptor.location.setData(GeoOperations.centerpointCoordinatesObj(wayGeojson))
adaptor.bounds.setData(BBox.get(wayGeojson).pad(2))
adaptor.maxbounds.setData(BBox.get(wayGeojson).pad(2))
2023-06-14 20:39:36 +02:00
2024-03-04 15:31:09 +01:00
state?.showCurrentLocationOn(map)
2023-04-20 01:52:23 +02:00
new ShowDataLayer(map, {
features: new StaticFeatureSource([wayGeojson]),
2024-11-19 16:42:53 +01:00
drawMarkers: true,
2023-06-14 20:39:36 +02:00
layer: layer,
2023-04-20 01:52:23 +02:00
})
2023-06-14 20:39:36 +02:00
export let splitPoints: UIEventSource<
Feature<
Point,
{
id: number
index: number
dist: number
location: number
}
>[]
> = new UIEventSource([])
2023-04-20 01:52:23 +02:00
const splitPointsFS = new StaticFeatureSource(splitPoints)
2023-06-14 20:39:36 +02:00
2023-04-20 01:52:23 +02:00
new ShowDataLayer(map, {
layer: splitpoint_style,
features: splitPointsFS,
onClick: (clickedFeature: Feature) => {
2024-11-19 16:42:53 +01:00
// A 'splitpoint' was clicked, so we remove it again
const i = splitPoints.data.findIndex((f) => f.properties.id === clickedFeature.properties.id)
2023-06-14 20:39:36 +02:00
if (i < 0 ) {
2023-04-20 01:52:23 +02:00
return
}
splitPoints.data.splice(i, 1)
splitPoints.ping()
2023-06-14 20:39:36 +02:00
},
2023-04-20 01:52:23 +02:00
})
let id = 0
2023-06-14 20:39:36 +02:00
adaptor.lastClickLocation.addCallbackD(({ lon , lat } ) => {
2024-11-28 12:00:23 +01:00
let projected: Feature< Point , { index : number ; id? : number ; reuse? : string } > =
GeoOperations.nearestPoint(wayGeojson, [lon, lat])
2024-11-19 16:42:53 +01:00
console.log("Added splitpoint", projected, id)
// We check the next and the previous point. If those are closer then the tolerance, we reuse those instead
const i = projected.properties.index
const p = projected.geometry.coordinates
const way = wayGeojson.geometry.coordinates
2024-11-28 12:00:23 +01:00
const nextPoint = < [number, number]>way[i + 1]
2024-11-19 16:42:53 +01:00
const nextDistance = GeoOperations.distanceBetween(nextPoint, p)
2024-11-28 12:00:23 +01:00
const previousPoint = < [number, number]>way[i]
2024-11-19 16:42:53 +01:00
const previousDistance = GeoOperations.distanceBetween(previousPoint, p)
console.log("ND", nextDistance, "PD", previousDistance)
2024-11-28 12:00:23 +01:00
if (nextDistance < = snapTolerance && previousDistance >= nextDistance) {
2024-11-19 16:42:53 +01:00
projected = {
2024-11-28 12:00:23 +01:00
type: "Feature",
2024-11-19 16:42:53 +01:00
geometry: {
2024-11-28 12:00:23 +01:00
type: "Point",
coordinates: nextPoint,
2024-11-19 16:42:53 +01:00
},
properties: {
2024-11-28 12:00:23 +01:00
index: i + 1,
reuse: "yes",
},
2024-11-19 16:42:53 +01:00
}
}
2024-11-28 12:00:23 +01:00
if (previousDistance < = snapTolerance && previousDistance < nextDistance ) {
2024-11-19 16:42:53 +01:00
projected = {
2024-11-28 12:00:23 +01:00
type: "Feature",
2024-11-19 16:42:53 +01:00
geometry: {
2024-11-28 12:00:23 +01:00
type: "Point",
coordinates: previousPoint,
2024-11-19 16:42:53 +01:00
},
properties: {
index: i,
2024-11-28 12:00:23 +01:00
reuse: "yes",
},
2024-11-19 16:42:53 +01:00
}
}
2023-06-14 20:39:36 +02:00
2023-04-20 01:52:23 +02:00
projected.properties["id"] = id
id++
2023-06-14 20:39:36 +02:00
splitPoints.data.push(< any > projected)
2023-04-20 01:52:23 +02:00
splitPoints.ping()
})
< / script >
2023-06-14 20:39:36 +02:00
2024-04-13 02:40:21 +02:00
< div class = "relative h-full w-full" >
2024-03-25 04:17:13 +01:00
< MaplibreMap { map } mapProperties = { adaptor } / >
2024-03-04 15:31:09 +01:00
< SmallZoomButtons { adaptor } />
2023-04-20 01:52:23 +02:00
< / div >