- add right click context menu
This commit is contained in:
Generated
+5
@@ -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",
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user