191 lines
5.7 KiB
JavaScript
191 lines
5.7 KiB
JavaScript
import maplibregl from "maplibre-gl"
|
|
|
|
const defaultStyle = {
|
|
version: 8,
|
|
sources: {
|
|
osm: {
|
|
type: "raster",
|
|
tiles: [document.documentElement.dataset.mapTileUrl],
|
|
tileSize: 256,
|
|
attribution: "© OpenStreetMap contributors"
|
|
}
|
|
},
|
|
layers: [{id: "osm", type: "raster", source: "osm"}]
|
|
}
|
|
|
|
export const Hooks = {
|
|
AidMap: {
|
|
mounted() {
|
|
this.markers = []
|
|
this.markLoading = () => {
|
|
if (this.el.dataset.mapReady !== "true") {
|
|
this.el.dataset.mapReady = "false"
|
|
}
|
|
}
|
|
this.markReady = () => {
|
|
this.el.dataset.mapReady = "true"
|
|
}
|
|
this.showUnavailable = () => {
|
|
this.map = null
|
|
this.el.dataset.mapUnavailable = "true"
|
|
this.markReady()
|
|
|
|
const fallback = document.createElement("p")
|
|
fallback.className = "grid h-full place-items-center p-6 text-center text-sm"
|
|
fallback.dataset.mapFallback = "true"
|
|
fallback.textContent = this.el.dataset.mapUnavailableLabel
|
|
this.el.replaceChildren(fallback)
|
|
}
|
|
|
|
if (!supportsMapCanvas()) {
|
|
this.showUnavailable()
|
|
return
|
|
}
|
|
|
|
try {
|
|
this.map = new maplibregl.Map({
|
|
container: this.el,
|
|
style: defaultStyle,
|
|
center: [30.5234, 50.4501],
|
|
zoom: 5
|
|
})
|
|
} catch (_error) {
|
|
this.showUnavailable()
|
|
return
|
|
}
|
|
|
|
this.map.addControl(new maplibregl.NavigationControl(), "top-right")
|
|
this.map.on("dataloading", this.markLoading)
|
|
this.map.on("load", this.markReady)
|
|
this.map.on("idle", this.markReady)
|
|
this.renderMarkers()
|
|
},
|
|
updated() {
|
|
this.renderMarkers()
|
|
},
|
|
destroyed() {
|
|
this.map?.off("dataloading", this.markLoading)
|
|
this.map?.off("load", this.markReady)
|
|
this.map?.off("idle", this.markReady)
|
|
this.map?.remove()
|
|
},
|
|
renderMarkers() {
|
|
if (!this.map) return
|
|
this.markers.forEach(marker => marker.remove())
|
|
this.markers = []
|
|
|
|
const points = JSON.parse(this.el.dataset.markers || "[]")
|
|
points.forEach(point => {
|
|
const popupContent = document.createElement("div")
|
|
const title = document.createElement("strong")
|
|
title.textContent = point.title || ""
|
|
popupContent.append(title, document.createElement("br"))
|
|
popupContent.append(document.createTextNode(point.location || ""))
|
|
|
|
const popup = new maplibregl.Popup({offset: 18}).setDOMContent(popupContent)
|
|
const marker = new maplibregl.Marker({color: point.exact ? "#d6573b" : "#278467"})
|
|
.setLngLat([point.longitude, point.latitude])
|
|
.setPopup(popup)
|
|
.addTo(this.map)
|
|
this.markers.push(marker)
|
|
})
|
|
|
|
if (points.length === 1) {
|
|
this.map.flyTo({center: [points[0].longitude, points[0].latitude], zoom: 12})
|
|
} else if (points.length > 1) {
|
|
const bounds = new maplibregl.LngLatBounds()
|
|
points.forEach(point => bounds.extend([point.longitude, point.latitude]))
|
|
this.map.fitBounds(bounds, {padding: 52, maxZoom: 13})
|
|
}
|
|
}
|
|
},
|
|
|
|
LocationPicker: {
|
|
mounted() {
|
|
this.el.addEventListener("click", () => {
|
|
const latitudeInput = document.querySelector(this.el.dataset.latitudeTarget)
|
|
const longitudeInput = document.querySelector(this.el.dataset.longitudeTarget)
|
|
|
|
if (!latitudeInput || !longitudeInput || !navigator.geolocation) {
|
|
this.el.textContent = "Location is unavailable"
|
|
this.el.classList.add("btn-error")
|
|
return
|
|
}
|
|
|
|
navigator.geolocation.getCurrentPosition(
|
|
position => {
|
|
latitudeInput.value = position.coords.latitude
|
|
longitudeInput.value = position.coords.longitude
|
|
latitudeInput.dispatchEvent(new Event("input", {bubbles: true}))
|
|
longitudeInput.dispatchEvent(new Event("input", {bubbles: true}))
|
|
this.el.textContent = "Location added"
|
|
this.el.classList.add("btn-success")
|
|
},
|
|
() => {
|
|
this.el.textContent = "Location permission denied"
|
|
this.el.classList.add("btn-error")
|
|
},
|
|
{enableHighAccuracy: true, timeout: 10000}
|
|
)
|
|
})
|
|
}
|
|
},
|
|
|
|
LiveTracking: {
|
|
mounted() {
|
|
this.destroying = false
|
|
|
|
if (window.WhoNeedHelpAndroid) {
|
|
this.nativeError = () => {
|
|
this.pushEvent("location-error", {})
|
|
this.pushEvent("stop-tracking", {})
|
|
}
|
|
window.addEventListener("wnh:native-tracking-error", this.nativeError)
|
|
return
|
|
}
|
|
|
|
this.watchId = navigator.geolocation.watchPosition(
|
|
position => this.pushEvent("location-update", {
|
|
latitude: position.coords.latitude,
|
|
longitude: position.coords.longitude,
|
|
accuracy_meters: position.coords.accuracy
|
|
}),
|
|
() => {
|
|
if (!this.destroying) this.pushEvent("location-error", {})
|
|
},
|
|
{enableHighAccuracy: true, maximumAge: 5000, timeout: 15000}
|
|
)
|
|
},
|
|
destroyed() {
|
|
this.destroying = true
|
|
if (this.nativeError) {
|
|
window.removeEventListener("wnh:native-tracking-error", this.nativeError)
|
|
}
|
|
if (this.watchId !== undefined) navigator.geolocation.clearWatch(this.watchId)
|
|
}
|
|
}
|
|
}
|
|
|
|
function supportsMapCanvas() {
|
|
const canvas = document.createElement("canvas")
|
|
const attributes = {
|
|
alpha: true,
|
|
depth: true,
|
|
stencil: true,
|
|
premultipliedAlpha: true
|
|
}
|
|
|
|
try {
|
|
const context =
|
|
canvas.getContext("webgl2", attributes) ||
|
|
canvas.getContext("webgl", attributes)
|
|
|
|
if (!context) return false
|
|
|
|
context.getExtension("WEBGL_lose_context")?.loseContext()
|
|
return true
|
|
} catch (_error) {
|
|
return false
|
|
}
|
|
}
|