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()
+ }
+ }
+
+
+
+
+