mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-22 00:01:34 +00:00
feat: add map support in renderer
This commit is contained in:
@@ -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>
|
||||
Reference in New Issue
Block a user