- add right click context menu

This commit is contained in:
peterlu14
2023-03-20 17:40:34 +08:00
parent 8070da4270
commit 9bf9db5263
6 changed files with 194 additions and 75 deletions
+5
View File
@@ -6734,6 +6734,11 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"v-contextmenu": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/v-contextmenu/-/v-contextmenu-3.0.0.tgz",
"integrity": "sha512-zi38JxmTt66TmljgV1JbfEa9WvoQkpzRuEwZK7Tjb2XoRejbWLozQtkyTWXJa6x6Y3FrVDfgT36w01gpTpo41A=="
},
"validate-npm-package-license": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+1
View File
@@ -36,6 +36,7 @@
"pinia": "^2.0.33",
"register-service-worker": "^1.7.2",
"sass": "^1.58.3",
"v-contextmenu": "^3.0.0",
"vue": "^3.2.47",
"vue-chartjs": "^5.2.0",
"vue-good-table-next": "^0.2.1",
@@ -1,6 +1,17 @@
<template>
<div class="">
<va-card class="h-full">
<v-contextmenu ref="contextmenu">
<v-contextmenu-item @click="changeAxisPointer">pointer</v-contextmenu-item>
<v-contextmenu-item v-if="canvasInstance.format === 'line'" @click="changeFormat('scatter')"
>scatter</v-contextmenu-item
>
<v-contextmenu-item v-if="canvasInstance.format === 'scatter'" @click="changeFormat('line')"
>line</v-contextmenu-item
>
<v-contextmenu-item @click="deleteSelected">clear</v-contextmenu-item>
<v-contextmenu-item @click="download">download</v-contextmenu-item>
</v-contextmenu>
<va-card v-contextmenu:contextmenu class="h-full">
<va-card-content class="h-full">
<div style="position: relative" class="h-full">
<canvas
@@ -36,30 +47,81 @@
const canvasStore = useCanvasStore()
// 需要參數 1. canvas boundry 2. 上下左右的padding 3.
// global 參數
// const xRange = [2400000, 2600000]
// const yRange = [0, 5000000]
const { width, height, padding, numTicks, innerWidth, innerHeight, start, end, xTickPixels, yTickPixels, x, y } =
const { width, height, numTicks, innerWidth, innerHeight, start, end, xTickPixels, yTickPixels, x, y } =
canvasStore.canvas
// monitor screen height
const screenHeight = computed(() => canvasStore.canvas.screenHeight)
// monitor screen width
const screenWidth = computed(() => canvasStore.canvas.screenWidth)
// monitor screen inner height
const screenInnerHeight = computed(() => canvasStore.canvas.screenInnerHeight)
// monitor screen inner width
const screenInnerWidth = computed(() => canvasStore.canvas.screenInnerWidth)
// line or scatter
const format = computed(() => canvasStore.canvas.format)
// canvas instance
const canvasInstance = canvasStore.canvas
// show axis pointer
const showAxisPointer = ref(false)
// show axis pointer or not
const changeAxisPointer = function () {
showAxisPointer.value = !showAxisPointer.value
reDraw()
}
// change line or scatter
const changeFormat = function (format: string) {
canvasInstance.format = format
}
// delect select rect
const deleteSelected = function () {
canvasInstance.resetSelected()
reDraw()
}
const download = function () {
const axis = document.getElementById('canvasForAxis') as HTMLCanvasElement
const line = document.getElementById('LineCanvas') as HTMLCanvasElement
const scatter = document.getElementById('ScatterCanvas') as HTMLCanvasElement
const combinedCanvas = document.createElement('canvas')
const combinedCtx = combinedCanvas.getContext('2d')
if (combinedCtx && line && scatter) {
combinedCanvas.width = axis.width
combinedCanvas.height = axis.height
combinedCtx.fillStyle = '#FFFFFF'
combinedCtx.fillRect(0, 0, combinedCanvas.width, combinedCanvas.height)
combinedCtx.drawImage(axis, 0, 0)
combinedCtx.globalCompositeOperation = 'multiply'
if (format.value === 'line') combinedCtx.drawImage(line, 0, 0)
if (format.value === 'scatter') combinedCtx.drawImage(scatter, 0, 0)
const link = document.createElement('a')
link.download = 'filename.png'
link.href = combinedCanvas.toDataURL('image/jpeg')
link.click()
}
}
// mouse down position
let mouseStartX = -1
let mouseStartY = -1
// mouse moving temp position
let mouseTempX = -1
let mouseTempY = -1
// mouse up position
let mouseEndX = -1
let mouseEndY = -1
// dragging flag
let isDragging = false
// color code
let colorIndex = 0
const generatorColor = function () {
const colorCode = [
'#054A91',
@@ -116,7 +178,7 @@
const x = tickPixels[i]
ctx.moveTo(start.x + x, start.y)
ctx.lineTo(start.x + x, start.y + 15)
const text = generateXAxisText((xMin + (i / numTicks) * (xMax - xMin)).toFixed(2), xChannelInfo)
const text = canvasInstance.getXText(xMin + (i / numTicks) * (xMax - xMin))
ctx.fillText(text, start.x + x, start.y + 75)
}
ctx.strokeStyle = 'black'
@@ -143,7 +205,7 @@
const y = tickPixels[i]
ctx.moveTo(start.x, start.y - y)
ctx.lineTo(start.x - 25, start.y - y)
const text = generateYAxisText((yMin + (i / numTicks) * (yMax - yMin)).toFixed(2), yChannelInfo)
const text = canvasInstance.getYText(yMin + (i / numTicks) * (yMax - yMin))
ctx.fillText(text, start.x - 30, start.y - y + 15)
}
ctx.strokeStyle = 'black'
@@ -162,9 +224,10 @@
ctx.strokeStyle = 'black'
ctx.stroke()
const text = canvasInstance.mouseXToValue(mouseX)
const value = canvasInstance.mouseXToValue(mouseX)
const text = canvasInstance.getXText(value)
ctx.textAlign = 'center'
ctx.fillText(text, x, start.y)
ctx.fillText(text, x, start.y + 50)
}
const drawYAxisPointer = function (mouseY, ctx) {
@@ -174,8 +237,9 @@
ctx.strokeStyle = 'black'
ctx.stroke()
const text = canvasInstance.mouseYToValue(mouseY)
ctx.textAlign = 'center'
const value = canvasInstance.mouseYToValue(mouseY)
const text = canvasInstance.getYText(value)
ctx.textAlign = 'right'
ctx.fillText(text, start.x, y)
}
@@ -193,9 +257,10 @@
for (let i = 0; i < x.length; i++) {
const X = calcPositionX(x[i])
const Y = calcPositionY(y[i])
ctx1.lineTo(X, Y)
// draw point
drawPoint(X, Y, color, ctx)
ctx1.lineTo(X, Y)
}
ctx1.lineWidth = 2
ctx1.strokeStyle = color
@@ -223,6 +288,56 @@
scatterCtx?.clearRect(0, 0, width, height)
}
const outOfBoundry = function (mouseX, mouseY) {
if (mouseX < canvasInstance.getBoundryInScreen(3) || mouseX > canvasInstance.getBoundryInScreen(1)) return true
if (mouseY < canvasInstance.getBoundryInScreen(0) || mouseY > canvasInstance.getBoundryInScreen(2)) return true
return false
}
const reDraw = function () {
const canvas = document.getElementById('canvasForAxis')
const ctx = canvas?.getContext('2d')
const rect = canvas.getBoundingClientRect()
// Clear the canvas
ctx.clearRect(0, 0, width, height)
// Draw the x and y axes with tick marks
drawXAxis(Number(x.range[0]), Number(x.range[1]), xTickPixels, canvasStore.canvas.x.channel, ctx)
drawYAxis(Number(y.range[0]), Number(y.range[1]), yTickPixels, canvasStore.canvas.y.channel, ctx)
// Draw the x and y axis pointers
if (showAxisPointer.value === true) {
drawXAxisPointer(mouseTempX, ctx)
drawYAxisPointer(mouseTempY, ctx)
}
for (const selectionRect of canvasInstance.selectedSave) {
ctx.lineWidth = 5
ctx.strokeRect(
(selectionRect[0] / rect.width) * width,
(selectionRect[1] / rect.height) * height,
((selectionRect[2] - selectionRect[0]) / rect.width) * width,
((selectionRect[3] - selectionRect[1]) / rect.height) * height,
)
}
if (isDragging || (mouseEndX !== -1 && mouseEndY !== -1)) {
if (isDragging === true) {
mouseEndX = mouseTempX
mouseEndY = mouseTempY
}
ctx.lineWidth = 5
ctx.strokeRect(
(mouseStartX / rect.width) * width,
(mouseStartY / rect.height) * height,
((mouseEndX - mouseStartX) / rect.width) * width,
((mouseEndY - mouseStartY) / rect.height) * height,
)
}
}
onMounted(() => {
const canvas = document.getElementById('canvasForAxis')
const rect = canvas?.getBoundingClientRect()
@@ -247,29 +362,18 @@
// set starting coordinates of square
mouseStartX = event.clientX - rect.left
mouseStartY = event.clientY - rect.top
if (
mouseStartX <= canvasInstance.getBoundryInScreen(3) ||
mouseStartX >= canvasInstance.getBoundryInScreen(1)
) {
return
}
if (
mouseStartY <= canvasInstance.getBoundryInScreen(0) ||
mouseStartY >= canvasInstance.getBoundryInScreen(2)
) {
return
}
if (outOfBoundry(mouseStartX, mouseStartY) === true) return
isDragging = true
}
})
// listen for mouse up event
canvas?.addEventListener('mouseup', async () => {
const rect = canvas.getBoundingClientRect()
isDragging = false
const rect = canvas.getBoundingClientRect()
if (mouseEndX === -1 || mouseEndY === -1) return
canvasInstance.selectedSave.push([mouseStartX, mouseStartY, mouseEndX, mouseEndY])
console.log('mouse', mouseStartX, mouseEndX, mouseStartY, mouseEndY)
// update ending coordinates of square
const dataStartX =
((mouseStartX - rect.width * 0.1) * (x.range[1] - x.range[0])) / screenInnerWidth.value + Number(x.range[0])
@@ -281,7 +385,6 @@
const dataEndY =
((rect.height - mouseEndY - rect.height * 0.1) * (y.range[1] - y.range[0])) / screenInnerHeight.value +
Number(y.range[0])
console.log(dataStartX, dataStartY, dataEndX, dataEndY)
const xInfo = [canvasInstance.x.channel.id, dataStartX, dataEndX]
const yInfo = [canvasInstance.y.channel.id, dataStartY, dataEndY]
const ret = await api.meta.findMeta(canvasStore.canvas.metaIds, [xInfo, yInfo])
@@ -292,46 +395,12 @@
canvas?.addEventListener('mousemove', function (event) {
const rect = canvas.getBoundingClientRect()
const mouseX = event.clientX - rect.left
const mouseY = event.clientY - rect.top
mouseTempX = event.clientX - rect.left
mouseTempY = event.clientY - rect.top
if (mouseX <= canvasInstance.getBoundryInScreen(3) || mouseX >= canvasInstance.getBoundryInScreen(1)) return
if (mouseY <= canvasInstance.getBoundryInScreen(0) || mouseY >= canvasInstance.getBoundryInScreen(2)) return
// Clear the canvas
ctx.clearRect(0, 0, width, height)
if (outOfBoundry(mouseTempX, mouseTempY) === true) return
// Draw the x and y axes with tick marks
drawXAxis(Number(x.range[0]), Number(x.range[1]), xTickPixels, canvasStore.canvas.x.channel, ctx)
drawYAxis(Number(y.range[0]), Number(y.range[1]), yTickPixels, canvasStore.canvas.y.channel, ctx)
// Draw the x and y axis pointers
drawXAxisPointer(mouseX, ctx)
drawYAxisPointer(mouseY, ctx)
for (const selectionRect of canvasInstance.selectedSave) {
ctx.lineWidth = 5
ctx.strokeRect(
(selectionRect[0] / rect.width) * width,
(selectionRect[1] / rect.height) * height,
((selectionRect[2] - selectionRect[0]) / rect.width) * width,
((selectionRect[3] - selectionRect[1]) / rect.height) * height,
)
}
if (isDragging || (mouseEndX !== -1 && mouseEndY !== -1)) {
if (isDragging === true) {
mouseEndX = mouseX
mouseEndY = mouseY
}
ctx.lineWidth = 5
ctx.strokeRect(
(mouseStartX / rect.width) * width,
(mouseStartY / rect.height) * height,
((mouseEndX - mouseStartX) / rect.width) * width,
((mouseEndY - mouseStartY) / rect.height) * height,
)
}
reDraw()
})
})
@@ -66,7 +66,7 @@
import { useCanvasStore } from '@/stores/data-analysis/canvas'
import { useDASettingStore } from '@/stores/data-analysis/data-analysis'
import { useFileViewStore } from '@/stores/data-analysis/file-view'
import { Ref, ref } from 'vue'
import { Ref, ref, computed } from 'vue'
const emit = defineEmits(['filter-data'])
@@ -102,6 +102,9 @@
const lineOrScatter = ref(false)
// const xOption = computed(() => channelStore.xAxisOptions)
// const yOption = computed(() => channelStore.yAxisOptions)
/* Start */
const filterData = function () {
/* reset specify chart */
@@ -134,7 +137,10 @@
option: channelStore.xAxisSelected.unit,
})
canvasStore.canvas.x.channel = JSON.parse(JSON.stringify(channelStore.xAxisSelected))
const xChannel = JSON.parse(JSON.stringify(channelStore.xAxisSelected))
canvasStore.canvas.x.channel = xChannel
canvasStore.canvas.x.selectUnit = xChannel.defaultUnit
canvasStore.canvas.x.unit = xChannel.unit
/* set y-axis label */
chart.yAxisManager.setAxisLabel({
@@ -143,7 +149,10 @@
option: channelStore.yAxisSelected.unit,
})
canvasStore.canvas.y.channel = JSON.parse(JSON.stringify(channelStore.yAxisSelected))
const yChannel = JSON.parse(JSON.stringify(channelStore.yAxisSelected))
canvasStore.canvas.y.channel = yChannel
canvasStore.canvas.y.selectUnit = yChannel.defaultUnit
canvasStore.canvas.y.unit = yChannel.unit
emit('filter-data', {
pattern: {
+4
View File
@@ -49,6 +49,9 @@ import '@hyjiacan/vue-slideout/dist/slideout.css'
import VueGoodTable from 'vue-good-table-next'
import 'vue-good-table-next/dist/vue-good-table-next.css'
import contextmenu from 'v-contextmenu'
import 'v-contextmenu/dist/themes/default.css'
const app = createApp(App)
app.use(stores)
@@ -57,6 +60,7 @@ app.use(i18n)
app.use(createVuestic({ config: vuesticGlobalConfig }))
app.use(Slideout)
app.use(VueGoodTable)
app.use(contextmenu)
app.component('EChart', ECharts)
+34 -3
View File
@@ -40,6 +40,7 @@ class Canvas {
this.yTickPixels = this.getTickPixels(this.innerHeight, this.numTicks)
// axis setting
this.x = {
selectUnit: '',
range: ['0', '0'],
unit: [],
scale: 1,
@@ -47,6 +48,7 @@ class Canvas {
channel: [],
}
this.y = {
selectUnit: '',
range: ['0', '0'],
unit: [],
scale: 1,
@@ -58,6 +60,15 @@ class Canvas {
this.metaIds = []
}
reset() {
this.metaIds.length = 0
this.selectedSave.length = 0
}
resetSelected() {
this.selectedSave.length = 0
}
getTickPixels(size: number, numTicks: number) {
const tickPixels = []
for (let i = 0; i <= numTicks; i++) {
@@ -107,9 +118,29 @@ class Canvas {
)
}
reset() {
this.metaIds.length = 0
this.selectedSave.length = 0
getXText(value) {
if (this.x.selectUnit !== '') {
const scaleValue = value / this.x.unit[this.x.selectUnit]
return String(this.numberIntoSigFig(scaleValue)) + ' ' + this.x.selectUnit
}
}
getYText(value) {
if (this.y.selectUnit !== '') {
const scaleValue = value / this.y.unit[this.y.selectUnit]
return String(this.numberIntoSigFig(scaleValue)) + ' ' + this.y.selectUnit
}
}
numberIntoSigFig(value: number) {
// 整數
if (Math.floor(Math.abs(value)) > 0) {
return value.toFixed(3)
}
// 小數
else {
return value.toExponential(3)
}
}
}