|
<template> |
|
<div class="h-auto" id="id-prediction-map-container"> |
|
|
|
<div class="grid grid-cols-1 2xl:grid-cols-5 lg:gap-1 lg:border-r ml-2 mt-2 md:ml-4 md:mr-4"> |
|
|
|
<div class="lg:border-r lg:col-span-3"> |
|
<div id="id-map-cont" class=""> |
|
<p class="hidden lg:block">{{ description }}</p> |
|
<div class="flex w-full md:pt-1 md:pb-1 lg:hidden portrait:xl:hidden"> |
|
<span class="flex portrait:hidden bg-slate-200 pl-2 pr-2">SamGIS demo</span> |
|
<ButtonMapSendArrayRequest |
|
id="id-button-submit" |
|
class="h-8 text-sm font-extralight min-w-[180px] max-w-[180px] ml-2 mr-2" |
|
:current-base-map-name="currentBaseMapNameRef" |
|
:map="map" |
|
:prompts-array="promptsArrayRef" |
|
:response-message="responseMessageRef" |
|
:send-m-l-request="sendMLArrayRequest" |
|
:waiting-string="waitingString" |
|
/> |
|
<span class="ml-2 lg:hidden"> |
|
<input type="checkbox" id="checkboxMapNavigationLocked" v-model="mapNavigationLocked" /> |
|
<span class="ml-2"> |
|
<label class="text-red-600" for="checkboxMapNavigationLocked" v-if="mapNavigationLocked">locked map!</label> |
|
<label class="text-blue-600" for="checkboxMapNavigationLocked" v-else>map unlocked</label> |
|
</span> |
|
</span> |
|
</div> |
|
<div id="map" class="map-predictions" /> |
|
<ButtonMapSendArrayRequest |
|
class="h-8 min-w-[240px] max-w-[240px] mt-2 mb-2 hidden sd:h-14 lg:block portrait:xl:block" |
|
:current-base-map-name="currentBaseMapNameRef" |
|
id="id-button-submit" |
|
:map="map" |
|
:prompts-array="promptsArrayRef" |
|
:response-message="responseMessageRef" |
|
:send-m-l-request="sendMLArrayRequest" |
|
:waiting-string="waitingString" |
|
/> |
|
<span class="hidden lg:block lg:ml-2"> |
|
<input type="checkbox" id="checkboxMapNavigationLocked" v-model="mapNavigationLocked" /> |
|
<span class="ml-2"> |
|
<label class="text-red-600" for="checkboxMapNavigationLocked" v-if="mapNavigationLocked">locked map navigation!</label> |
|
<label class="text-blue-600" for="checkboxMapNavigationLocked" v-else>map navigation unlocked</label> |
|
</span> |
|
</span> |
|
</div> |
|
</div> |
|
|
|
<div class="lg:col-span-2"> |
|
<div class="lg:pl-2 lg:pr-2 lg:border-l lg:border-3" id="id-map-info"> |
|
|
|
<h1>Map Info</h1> |
|
<div class="grid grid-cols-1 md:grid-cols-3"> |
|
<StatsGrid :stats-array="[ |
|
{statName: 'current Zoom', statValue: currentZoomRef}, |
|
{statName: 'current map name/type', statValue: currentBaseMapNameRef}, |
|
{statName: 'prompt: points/rectangles number', statValue: promptsArrayRef.length}, |
|
]" /> |
|
</div> |
|
<div v-if="responseMessageRef === waitingString" /> |
|
<h2 v-else-if="responseMessageRef || responseMessageRef == '-'" class="text-lg text-red-600">{{ responseMessageRef }}</h2> |
|
<div v-else> |
|
<div class="grid grid-cols-1 md:grid-cols-3"> |
|
<StatsGrid :stats-array="[ |
|
{statName: 'request duration', statValue: `${durationRef.toFixed(2)}s`}, |
|
{statName: 'polygons number', statValue: numberOfPolygonsRef}, |
|
{statName: 'predicted masks number', statValue: numberOfPredictedMasksRef}, |
|
]" /> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<h1 id="id-ml-request-prompt">ML request prompt</h1> |
|
<p>Exclude points: label 0, include points: label 1.</p> |
|
<div v-if="promptsArrayRef.filter(el => {return el.type === 'point'}).length > 0"> |
|
<TableGenericComponent |
|
:header="['id', 'data', 'label']" |
|
:rows="applyFnToObjectWithinArray(promptsArrayRef.filter(el => {return el.type === 'point'}))" |
|
title="Points" |
|
row-key="id" |
|
/> |
|
</div> |
|
<br /> |
|
<div v-if="promptsArrayRef.filter(el => {return el.type === 'rectangle'}).length > 0"> |
|
<TableGenericComponent |
|
:header="['id', 'data_ne', 'data_sw']" |
|
:rows="applyFnToObjectWithinArray(promptsArrayRef.filter(el => {return el.type === 'rectangle'}))" |
|
title="Rectangles" |
|
row-key="id" |
|
class="2md:min-h-[100px]" |
|
/> |
|
</div> |
|
</div> |
|
|
|
</div> |
|
</div> |
|
</template> |
|
|
|
<script lang="ts" setup> |
|
import { |
|
control as LeafletControl, |
|
Evented as LEvented, |
|
type LatLng, |
|
Map as LMap, |
|
map as LeafletMap, |
|
tileLayer, |
|
TileLayer as LTileLayer |
|
} from 'leaflet' |
|
import 'leaflet-providers' |
|
import '@geoman-io/leaflet-geoman-free' |
|
import { onMounted, onUpdated, ref, type Ref } from 'vue' |
|
// workaround because of dist/ content not included in @trincadev/driver.js tag release tarball |
|
import { driver } from "../../node_modules/@trincadev/driver.js/src/driver" |
|
|
|
import { |
|
currentBaseMapNameRef, |
|
currentMapBBoxRef, |
|
currentZoomRef, |
|
driverSteps, |
|
durationRef, |
|
layerControlGroupLayersRef, |
|
mapNavigationLocked, |
|
mapOptionsDefaultRef, |
|
maxZoom, |
|
minZoom, |
|
numberOfPolygonsRef, |
|
numberOfPredictedMasksRef, |
|
OpenStreetMap, |
|
prefix, |
|
promptsArrayRef, |
|
responseMessageRef, |
|
Satellite, |
|
waitingString |
|
} from './constants' |
|
import { |
|
applyFnToObjectWithinArray, |
|
getExtentCurrentViewMapBBox, |
|
sendMLArrayRequest, |
|
getQueryParams, |
|
getSelectedPointCoordinate, |
|
setGeomanControls, |
|
updateMapData, |
|
updateZoomBboxMap, |
|
getCurrentBasemap |
|
} from '@/components/helpers' |
|
import type { SourceTileType, ServiceTiles } from '@/components/types'; |
|
import StatsGrid from '@/components/StatsGrid.vue'; |
|
import TableGenericComponent from '@/components/TableGenericComponent.vue'; |
|
import ButtonMapSendArrayRequest from '@/components/buttons/ButtonMapSendArrayRequest.vue'; |
|
|
|
const driverObj = driver({ |
|
showProgress: true, |
|
steps: driverSteps |
|
}); |
|
|
|
let map: LMap |
|
|
|
const props = defineProps<{ |
|
mapBounds: Array<LatLng>, |
|
mapName: string, |
|
description: string |
|
}>() |
|
|
|
const getPopupContentPoint = (leafletEvent: LEvented, label: number): HTMLDivElement => { |
|
let popupContent: HTMLDivElement = document.createElement('div') |
|
let currentPointLayer: LatLng = getSelectedPointCoordinate(leafletEvent) |
|
|
|
popupContent.innerHTML = `<span>lat:${JSON.stringify(currentPointLayer.lat)}<br/>` |
|
popupContent.innerHTML += `lng:${JSON.stringify(currentPointLayer.lng)}<br/>` |
|
popupContent.innerHTML += `label:${label}, id:${leafletEvent.layer._leaflet_id}</span>` |
|
|
|
const popupDiv: HTMLDivElement = document.createElement('div') |
|
popupDiv.className = 'leaflet-popup-content-inner' |
|
popupDiv.appendChild(popupContent) |
|
|
|
return popupDiv |
|
} |
|
|
|
onMounted(async () => { |
|
const osmTile = tileLayer.provider(OpenStreetMap) |
|
const params = getQueryParams() |
|
let localVarSatellite: SourceTileType = params.source ? params.source : Satellite |
|
let localVarSatelliteOptions = params.options ? params.options : {} |
|
const satelliteTile = tileLayer.provider(localVarSatellite, localVarSatelliteOptions) |
|
let localVarTerrain: SourceTileType = "nextzen.terrarium" |
|
const terrainTile = new LTileLayer( |
|
"https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png", { |
|
id: localVarTerrain, |
|
attribution: "<a href='https://nextzen.org'>nextzen</a>," + |
|
"<a href='https://registry.opendata.aws/terrain-tiles/'>Mapzen Terrain Tiles - AWS opendata registry</a>," + |
|
"<a href='https://github.com/tilezen/joerd/blob/master/docs/attribution.md'>Mapzen Source Attributions</a>." |
|
} |
|
) |
|
let baseMaps: ServiceTiles = { OpenStreetMap: osmTile } |
|
baseMaps[localVarSatellite] = satelliteTile |
|
baseMaps[localVarTerrain] = terrainTile |
|
currentBaseMapNameRef.value = OpenStreetMap |
|
|
|
map = LeafletMap('map', { |
|
layers: [osmTile], |
|
minZoom: minZoom, |
|
maxZoom: maxZoom |
|
}) |
|
map.fitBounds(props.mapBounds) |
|
map.attributionControl.setPrefix(prefix) |
|
LeafletControl.scale({ position: 'bottomleft', imperial: false, metric: true }).addTo(map) |
|
layerControlGroupLayersRef.value = LeafletControl.layers(baseMaps).addTo(map) |
|
setGeomanControls(map) |
|
updateZoomBboxMap(map) |
|
mapOptionsDefaultRef.value = {...map.options} |
|
|
|
map.on('zoomend', (e: LEvented) => { |
|
updateZoomBboxMap(map) |
|
}) |
|
|
|
map.on('mouseup', (e: LEvented) => { |
|
currentMapBBoxRef.value = getExtentCurrentViewMapBBox(map) |
|
}) |
|
|
|
updateMapData(map, getPopupContentPoint, promptsArrayRef) |
|
map.on('baselayerchange', (e: LEvented) => { |
|
currentBaseMapNameRef.value = getCurrentBasemap(e.layer._url, baseMaps) |
|
}) |
|
|
|
driverObj.drive(); |
|
}) |
|
|
|
onUpdated(() => { |
|
if (mapNavigationLocked.value) { |
|
map.setMaxZoom(currentZoomRef.value) |
|
map.setMinZoom(currentZoomRef.value) |
|
map.options.maxBoundsViscosity = 1.0 |
|
map.setMaxBounds(map.getBounds()) |
|
} |
|
if (!mapNavigationLocked.value) { |
|
map.setMaxZoom(maxZoom) |
|
map.setMinZoom(minZoom) |
|
map.options.maxBoundsViscosity = 0.0 |
|
map.setMaxBounds([ |
|
[90, 180], |
|
[-90, -180] |
|
]) |
|
} |
|
}) |
|
</script> |
|
|