From d3f13925d48584a93b7879cbfbb67acfcee2a97a Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Wed, 27 Mar 2024 10:14:16 +0100 Subject: [PATCH] feat: add map support in renderer --- .../src/lib/components/DisplayResult.svelte | 13 ++ frontend/src/lib/components/MapResult.svelte | 129 ++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 frontend/src/lib/components/MapResult.svelte diff --git a/frontend/src/lib/components/DisplayResult.svelte b/frontend/src/lib/components/DisplayResult.svelte index e2c1ba5ab7..34e9fdfe1f 100644 --- a/frontend/src/lib/components/DisplayResult.svelte +++ b/frontend/src/lib/components/DisplayResult.svelte @@ -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 @@ {/if} + {:else if !forceJson && resultKind == 'map'} +
+ +
{:else if !forceJson && resultKind == 'png'}
+ 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() + } + } + + +
+ +