-
Notifications
You must be signed in to change notification settings - Fork 3
Viztype.vue
This Vue component is named based on the visualization type it corresponds with. It is only required if the visualization needs a custom component to render it. In general, all types that have viewLocation: panel or viewLocation: multi will need this custom component in order to be rendered in the visualization panel.
For example, Chart type has a Chart.vue component that creates the OSH ChartJsView and CurveLayer needed for the visualization.
Some commonly defined props will include the following:
const props = defineProps<{
visualization: OSHVisualization,
datasource: ISweApiDataSourceProperties[],
// Not always required:
dataLayer: VisualizationLayerProperties,
dataView: VisualizationViewProperties,
controlstream?: OSHControlStream
}>()
Almost all visualization components will require the visualization and datasource props, but the others will depend on the visualization type. These are the same properties that are generated in the visualization type's Builder.ts.
Connecting to the associated datastreams/controlstreams for the visualization is a standard step in generating any visualization view. Helper functions exist to generate these streams:
Takes ISweApiDataSourceProperties as a parameter to generate and return a SweApi instance.
/**
* Create a SweApi datasource from given datasource properties
*
* @param dsProps - Array of datasource properties to create SweApi object
* @returns Generated SweApi datasource instance
*/
export function createDatasource(dsProps: ISweApiDataSourceProperties) {
const dsInstance = new SweApi(dsProps.id, {
endpointUrl: dsProps.endpointUrl,
resource: dsProps.resource,
tls: dsProps.tls,
protocol: dsProps.protocol,
startTime: dsProps.startTime,
endTime: dsProps.endTime,
mode: dsProps.mode,
responseFormat: dsProps.responseFormat,
connectorOpts: {
username: dsProps?.connectorOpts.username ?? '',
password: dsProps?.connectorOpts.password ?? '',
}
});
return dsInstance;
}
Once the datastream is created, keep the datastream instances stored and connect them.
dsInstance.connect();
dsInstances.push(dsInstance);
When a visualization is deleted, all streams need to be disconnected. The useVisualizationCleanup() hook exists to easily delete any associated streams on unmount.
useVisualizationCleanup(ref(dsInstances));
A visualization type may need more than one Vue component associated with it. For example, the Video visualization has a Video.vue that renders the video itself, but optionally includes the PTZControl.vue component when PTZ controls are configured with the visualization.
Any associated visualization components should be located in the same folder as the visualization type it is used with (e.g. PTZControl.vue in /video).
Below is the Chart.vue for the Chart visualization:
<script setup lang="ts">
import { onMounted, ref, toRaw } from 'vue';
import { randomUUID } from 'osh-js/source/core/utils/Utils.js';
import SweApi from 'osh-js/source/core/datasource/sweapi/SweApi.datasource.js';
import ChartJsView from 'osh-js/source/core/ui/view/chart/ChartJsView.js';
import CurveLayer from 'osh-js/source/core/ui/layer/CurveLayer.js';
import { OSHVisualization } from '@/lib/OSHConnectDataStructs';
import { createDatasource, useVisualizationCleanup } from '../../shared/helpers';
import { IChartViewProperties, ICurveLayerProperties, ISweApiDataSourceProperties } from '@/lib/VisualizationHelpers';
const props = defineProps<{
visualization: OSHVisualization,
datasource: ISweApiDataSourceProperties[],
curveLayer: ICurveLayerProperties,
chartView: IChartViewProperties,
}>();
const chartId = ref('chart-' + randomUUID());
let curveLayer = ref<CurveLayer | null>(null);
let chartView = ref<ChartJsView | null>(null);
onMounted(async () => {
initializeChart();
});
// Array of SweApi instances for datasources
const dsInstances: SweApi[] = [];
function initializeChart() {
const viz = props.visualization;
if (!viz || viz.type !== 'chart') return;
let getValues: any;
const dsArray: ISweApiDataSourceProperties[] = props.datasource
for (const dsProps of dsArray) {
let rawDs = toRaw(dsProps);
const dsInstance = createDatasource(dsProps)
if (rawDs && rawDs.properties?.x && rawDs.properties?.y) {
getValues = (rec: any, timestamp: any) => {
const xProp = rawDs.properties?.x;
const yProp = rawDs.properties?.y;
return {
x: rec[xProp.outputName]?.[xProp.property] ?? rec[xProp.property] ?? timestamp,
y: rec[yProp.outputName]?.[yProp.property] ?? rec[yProp.property] ?? '',
}
}
}
dsInstance.connect();
dsInstances.push(dsInstance);
console.log('[Chart.vue] Chart datasource created:', dsInstance);
}
const layerOpts: ICurveLayerProperties = props.curveLayer;
curveLayer.value = new CurveLayer({
...layerOpts,
dataSourceIds: dsInstances.map(ds => ds.id),
...(getValues ? { getValues } : {}),
});
console.log('[Chart.vue] Creating CurveLayer:', curveLayer.value);
if (chartView.value) {
chartView.value.destroy?.();
chartView.value = null;
}
chartView.value = new ChartJsView({
...props.chartView,
container: chartId.value,
layers: [curveLayer.value],
});
console.log('[Chart.vue] Chart view created:', chartView.value);
}
useVisualizationCleanup(ref(dsInstances));
</script>
<template>
<v-sheet class="chart-card pa-4">
<div :id="chartId"></div>
</v-sheet>
</template>
<style scoped>
.chart-card {
height: auto;
}
</style>
Troubleshooting
Developer Documentation