-
Notifications
You must be signed in to change notification settings - Fork 3
Multi Visualizations
multi visualizations are not tied to one specific render location in viewer. The GeoPTZ visualization type is the best example of this, as it is rendered as a point marker on the map but also has a custom Controller Vue component in the "Visualizations" tab to task it.
The VisualizationSidebar.vue does not specifically check for multi ViewLocations. However, it checks for geoPtz visualization types in order to conditionally enable the GeoPTZ panel in the "Visualizations" tab.
Since multi visualizations are not as straightforward when it comes to rendering in a specific location, and some include extra listener functions to work, there is no single guide on how to render the visualization. It's best to reference an example visualization type, such as the GeoPTZ visualization, to better understand how to integrate any new multi ViewLocation visualizations into the viewer.
The GeoPTZ visualization type is rendered using a combination of panel and map viewLocation approaches. A list of its connections is included below to provide better context on its implementation.
- Filters for visualizations with type
geoPtz
const geoPtzVisualizations = computed<OSHVisualization[]>(() => visualizations.value.filter(viz =>
viz.type === 'geoPtz'
))
- Keeps an array of selected
GeoPTZcontroller instances
const selectedGeoPtzControllers = ref<OSHVisualization[]>([])
- Handles deletion of
GeoPTZcontroller visualizations
const removeGeoPTZ = (controller: OSHVisualization) => {
visualizationStore.removeVisualization(controller); // Remove from visualization store
selectedGeoPtzControllers.value = selectedGeoPtzControllers.value.filter((item: OSHVisualization) => item.id !== controller.id). // Remove from selected list
}
- UI to handle selection of
GeoPTZcontrollers
<!-- GEOPTZ VISUALIZATIONS -->
<v-expansion-panel :disabled="geoPtzVisualizations.length == 0">
<template #title>
<div class="panel-header">GeoPTZ Controllers</div>
</template>
<v-expansion-panel-text>
<v-sheet>
<GeoPTZ v-if="selectedGeoPtzControllers" :visualizations="selectedGeoPtzControllers">
<template #controllers>
<v-select label="Process" v-model="selectedGeoPtzControllers" :items="geoPtzVisualizations"
item-title="name" :item-value="(item: OSHVisualization) => item" chips multiple hide-details
clearable>
<template v-slot:item="{ props, item }">
<v-list-item v-bind="props">
<template v-slot:prepend="{ isSelected }">
<v-checkbox-btn :model-value="isSelected"></v-checkbox-btn>
</template>
<!-- Actions -->
<template v-slot:append>
<v-tooltip text="Edit Visualization" location="bottom">
<template v-slot:activator="{ props }">
<IconButton v-bind="props" aria-label="Edit Visualization" size="x-small" variant="plain"
icon="mdi-pencil"
@click.stop="handleEditViz(visualizationStore.getVisualizationById(item.raw.id)!)">
</IconButton>
</template>
</v-tooltip>
<DeleteButton label="Remove" @delete="removeGeoPTZ(item.raw)"></DeleteButton>
</template>
</v-list-item>
</template>
</v-select>
</template>
</GeoPTZ>
</v-sheet>
</v-expansion-panel-text>
</v-expansion-panel>
- Map click listener
/**
* Map click listener
*/
watch(
mapView,
(map) => {
if (!map) return;
// Handle leaflet map click
if (mapLayerType.value === 'leaflet') {
map.map.on('click', (event: any) => {
const lat = event.latlng.lat;
const lon = event.latlng.lng;
if (uiStore.isGeoPTZSelected) taskGeoPtz(lat, lon, 100);
})
}
// Handle cesium map click
else if (mapLayerType.value === 'cesium') {
const viewer = map.viewer;
// Description box styling
viewer.infoBox.frame.onload = function () {
const doc = viewer.infoBox.frame.contentDocument;
doc.body.style.backgroundColor = '#242424';
doc.body.style.color = '#ffffff';
};
const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
handler.setInputAction((click: any) => {
const cartesian = viewer.camera.pickEllipsoid(
click.position,
viewer.scene.globe.ellipsoid
);
if (!cartesian) return;
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const lat = Cesium.Math.toDegrees(cartographic.latitude);
const lon = Cesium.Math.toDegrees(cartographic.longitude);
if (uiStore.isGeoPTZSelected) taskGeoPtz(lat, lon, 100);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
}
}
)
- Send
GeoPTZcommands
/**
* Based on given LLA, send GeoPTZ task
*
* @param lat
* @param lon
* @param alt
*/
function taskGeoPtz(lat: number, lon: number, alt: number) {
uiStore.setCurrentLLA(lat, lon, alt);
console.log('LLA:', uiStore.currentLLA)
if (!uiStore.isGeoPTZSelected || !uiStore.selectedGeoPTZ) return;
const command = {
parameters: {
lat: lat,
lon: lon,
alt: 120.0,
},
};
uiStore.sendGeoPTZCommand(command); // Send command
}
- Handle
GeoPTZmarker based on selection
/**
* Create/delete GeoPTZ marker as selected GeoPTZ value changes
*/
watch(() => uiStore.selectedGeoPTZ, (geoPtz, oldGeoPtz) => {
// If had a value, delete
if (oldGeoPtz?.length) deleteVisualizations([oldGeoPtz[0].id]);
// If has a new value, create new
if (geoPtz?.length) createVisualizations([geoPtz[0].id]);
}, { deep: true })
- Handle cursor style for
GeoPTZ
/**
* Handle cursor style for GeoPTZ selection
*/
watch(() => uiStore.isGeoPTZSelected, (geoPtz) => {
// Leaflet
if (mapLayerType.value === 'leaflet') {
mapView.value.map.getContainer().style.cursor = geoPtz ? 'crosshair' : '';
}
// Cesium
else if (mapLayerType.value === 'cesium') {
mapView.value.viewer.canvas.style.cursor = geoPtz ? 'crosshair' : '';
}
})
- Create
GeoPTZpoint marker increateVisualizations()
else if (viz.type === 'geoPtz') {
for (const dsProps of dsArray) {
const dsInstance = createDatasource(dsProps);
dsInstance.connect();
dsInstances.push(dsInstance);
listDatasourceInstances.value.push(dsInstance); // Push to list of active datasources
}
console.log('[MapView] Creating datasource for GeoPTZ PointMarkerLayer:', dsInstances)
const pmLayer = new PointMarkerLayer({
name: 'GeoPTZ',
label: 'GeoPTZ',
id: viz.id,
icon: `${iconBase}/icons/map/geoPtz-pin.svg`,
iconSize: [32, 32],
iconAnchor: [16, 16],
labelOffset: [-16, -32],
dataSourceIds: dsInstances.map(ds => ds.id),
getLocation: {
dataSourceIds: [dsInstances.map(ds => ds.id)],
handler: (rec: any) => {
return {
x: uiStore.currentLLA?.longitude,
y: uiStore.currentLLA?.latitude,
z: uiStore.currentLLA?.altitude,
}
},
},
getDescription: {
dataSourceIds: [dsInstances.map(ds => ds.id)],
handler: (rec: any) => {
return (`
<div>${uiStore.selectedGeoPTZ?.map((viz: OSHVisualization) => {
return `${viz.name}`
}).join(', ')}</div>
`)
}
}
})
mapItemLayers.value.set(viz.id, pmLayer)
mapView.value.addLayer(pmLayer)
console.log('[MapView] Creating GeoPTZ PointMarkerLayer:', pmLayer)
}
Troubleshooting
Developer Documentation