I have a simple graph with data plotted from 5 different features showing their speed over time. When a user right clicks on data on the graph, I display a context menu with a few options, one of them being a simple “Get Info” option where I’d like to display a dialog containing more detailed data about the feature they clicked on.
I’m having a hard time getting to the data within the graph. So far I have tried using the uplot cursor.idxs to get the location of the click from this example with no success:
https://jsfiddle.net/w07t8q4g/
I am not sure how to accomplish this. Can anyone help? Thanks so much!
This is my component code so far:
<template>
<div @contextmenu.prevent="showContextMenu($event)">
<ContextMenu
v-model="showMenu"
:x="menuX"
:y="menuY"
:actions="contextMenuActions"
@action-clicked="handleMenuAction"
/>
<v-main class="pa-0">
<v-container fluid >
<v-card >
<div id="uplot-Container" style="min-height: 350px; max-height: 400px;">
<UplotVue ref="timelineContainer" :options="options" :data="plotData" :key="graphKey" />
</div>
</v-card>
</v-container>
</v-main>
</div>
</template>
<script setup>
import {onMounted, onUpdated, ref, watch} from 'vue'
import "uplot/dist/uPlot.min.css";
import UplotVue from 'uplot-vue';
import ContextMenu from '@/components/ContextMenu.vue';
import {useState} from "@/store/State"
const stateStore = useStateStore()
import {storeToRefs} from 'pinia'
const graphKey = ref(0)
const timelineContainer = ref(null)
const height = ref(null)
const width = ref(null)
const showMenu = ref(false)
const menuX = ref(0)
const menuY = ref(0)
const contextMenuActions = ref([
{ label: 'Get Info', action: 'getInfo', icon: 'mdi-information-box-outline', disabled: false },
{ label: 'Sync', action: 'sync', icon: 'mdi-autorenew', disabled: false },
]);
const plotData = stateStore.plotData
const showContextMenu = (event) => {
//the context menu adds pixels to the x and y to show it offset, so get the correct pixel that was actually right clicked to find feature
event.preventDefault()
//this is the pixel location for the menu based on where the user right clicked and what gets passed to the contextMenu component for placement on screen.
menuX.value = event.clientX
menuY.value = event.clientY
showMenu.value = true
}
function handleMenuAction(action){
console.log(action)
console.log('x: '+menuX.value + ' ' +'y: '+menuY.value)`enter code here`
if (action === 'getInfo') {
//Get the feature's data at the location of the click
//THIS DOESN'T WORK - TypeError: Cannot read properties of undefined (reading 'idxs')
const [xIdx, yIdx] = timelineContainer.value.cursor.idxs
const xVal = timelineContainer.value.data[0][xIdx]
const yVal = timelineContainer.value.data[1][yIdx]
const xPos = timelineContainer.value.valToPos(xVal, 'x');
const yPos = timelineContainer.value.valToPos(yVal, 'y');
let popup = document.createElement("div");
popup.classList.add("popup");
popup.textContent = yVal;
popup.style.left = xPos + "px";
popup.style.top = yPos + "px";
timelineContainer.value.over.appendChild(popup);
}
}
const options = ref({
Title: "Plotted Data",
drawOrder: ["series", "axes"],
axes: [
{
side:0,
stroke: "white",
ticks: {
stroke: "#808080"
},
grid: {
stroke: "rgba(236, 236, 236, 0.5)"
}
},
{
stroke: "white",
ticks: {
stroke: "#808080"
},
grid: {
stroke: "rgba(236, 236, 236, 0.5)"
},
}
],
series: [
{
label: 'Timstamp'
},
{
label: 'CM',
stroke: "red",
width: 4
},
{
label: "NC",
stroke: "green",
width: 4
},
{
label: "OE",
stroke: "blue",
width: 4
},
{
label: "SB",
stroke: "orange",
width: 4
},
{
label: "ST",
stroke: "yellow",
width: 4
},
],
scales: { x: { time: true } },
},)
onUpdated(() => {
graphKey.value++
const element = document.getElementById('uplot-Container')
const positionInfo = element.getBoundingClientRect()
const height = positionInfo.height
const width = positionInfo.width
options.value = {
...options.value,
height: height - 50,
width: width - 30
}
})
onMounted(() => {
console.log(plotData.value)
})
This is what the graph looks like with the 5 different features and its data over time
