feat: add map support in renderer

This commit is contained in:
Ruben Fiszel
2024-03-27 10:14:16 +01:00
parent 1e9bee2915
commit d3f13925d4
2 changed files with 142 additions and 0 deletions
@@ -25,6 +25,7 @@
import ParqetTableRenderer from './ParqetTableRenderer.svelte'
import ToggleButtonGroup from './common/toggleButton-v2/ToggleButtonGroup.svelte'
import ToggleButton from './common/toggleButton-v2/ToggleButton.svelte'
import MapResult from './MapResult.svelte'
export let result: any
export let requireHtmlApproval = false
@@ -51,6 +52,7 @@
| 's3object-list'
| 'plain'
| 'markdown'
| 'map'
| undefined
$: resultKind = inferResultKind(result)
@@ -130,6 +132,8 @@
return 'table-col'
} else if (keys.length == 1 && keys[0] == 'html') {
return 'html'
} else if (keys.length == 1 && keys[0] == 'map') {
return 'map'
} else if (keys.length == 1 && keys[0] == 'file') {
return 'file'
} else if (
@@ -339,6 +343,15 @@
</div>
{/if}
</div>
{:else if !forceJson && resultKind == 'map'}
<div class="h-full">
<MapResult
lat={result.map.lat}
lon={result.map.lon}
zoom={result.map.zoom}
markers={result.map.markers}
/>
</div>
{:else if !forceJson && resultKind == 'png'}
<div class="h-full">
<img
@@ -0,0 +1,129 @@
<script lang="ts">
import { Map, View, Feature } from 'ol'
import { useGeographic } from 'ol/proj'
import { OSM, Vector as VectorSource } from 'ol/source'
import { Vector as VectorLayer, Tile as TileLayer } from 'ol/layer'
import { Point } from 'ol/geom'
import { defaults as defaultControls } from 'ol/control'
interface Marker {
lon: number
lat: number
title?: string
radius?: number
color?: string
strokeWidth?: number
strokeColor?: string
}
export let lon: number | undefined = undefined
export let lat: number | undefined = undefined
export let zoom: number | undefined = undefined
export let markers: Marker[] | string | undefined = undefined
const LAYER_NAME = {
MARKER: 'Marker'
} as const
let map: Map | undefined = undefined
let mapElement: HTMLDivElement | undefined = undefined
function getLayersByName(name: keyof typeof LAYER_NAME) {
return map
?.getLayers()
?.getArray()
?.filter((l) => l.getProperties().name === LAYER_NAME[name])
}
function getMarkerArray(): Marker[] | undefined {
let array: Marker[] | undefined = undefined
try {
if (typeof markers === 'string') {
const json = JSON.parse(markers)
array = Array.isArray(json) ? json : [json]
} else {
array = markers
}
return array?.filter((m) => !isNaN(+m.lat) && !isNaN(+m.lon))
} catch (error) {
console.log(error)
return undefined
}
}
function createMarkerLayers() {
const markerArray = getMarkerArray()
return markerArray?.map((m) => {
return new VectorLayer({
properties: {
name: LAYER_NAME.MARKER
},
source: new VectorSource({
features: [
new Feature({
geometry: new Point([+m.lon, +m.lat]),
name: m.title
})
]
}),
style: {
'circle-radius': m.radius ?? 7,
'circle-fill-color': m.color ?? '#dc2626',
'circle-stroke-width': m.strokeWidth ?? 3,
'circle-stroke-color': m.strokeColor ?? '#fca5a5'
}
})
})
}
function updateMarkers() {
const layers = getLayersByName('MARKER')
if (layers?.length) {
layers.forEach((l) => map?.removeLayer(l))
}
createMarkerLayers()?.forEach((l) => map?.addLayer(l))
}
$: if (!map && mapElement) {
useGeographic()
map = new Map({
target: mapElement,
layers: [
new TileLayer({
source: new OSM()
}),
...(createMarkerLayers() || [])
],
view: new View({
center: [lon ?? 0, lat ?? 0],
zoom: zoom ?? 2
}),
controls: defaultControls({
attribution: false
})
})
if (lat && lon) {
map.getView().setCenter([lon, lat])
}
if (map && zoom) {
map.getView().setZoom(zoom)
}
if (map && markers) {
updateMarkers()
}
}
</script>
<div bind:this={mapElement} class="w-full h-[300px]" />
<style global lang="postcss">
.ol-overlaycontainer-stopevent {
@apply flex flex-col justify-start items-end;
}
.ol-control button {
@apply w-7 h-7 center-center bg-surface border text-secondary
rounded mt-1 mr-1 shadow duration-200 hover:bg-surface-hover focus:bg-surface-hover;
}
</style>