From d9c63c9bcef826a0aefda102e0ee0f16c1b607a9 Mon Sep 17 00:00:00 2001 From: Xu Zhimeng Date: Wed, 26 Jul 2023 19:35:36 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=20Beta=20Gamma=20Ene?= =?UTF-8?q?rgy=20Calibration=20=E5=BC=B9=E7=AA=97=E4=B8=AD=E6=89=80?= =?UTF-8?q?=E6=9C=89=E4=BA=A4=E4=BA=92=E9=80=BB=E8=BE=91=E5=8F=8A=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=AF=B9=E6=8E=A5=EF=BC=8C=E4=BF=AE=E5=A4=8DResultDis?= =?UTF-8?q?play=E4=B8=ADConcerntration=E8=83=8C=E6=99=AF=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E5=9B=BE=E8=A1=A8interval=E8=AE=A1?= =?UTF-8?q?=E7=AE=97=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/chartHelper.js | 22 + .../components/BetaDetectorCalibration.vue | 598 +++++++++++++----- .../components/GammaDetectorCalibration.vue | 188 +++++- .../BetaGammaEnergyCalibrationModal/index.vue | 2 +- .../components/Modals/LoadFromDBModal.vue | 3 + .../components/ResultDisplay.vue | 41 +- .../components/SpectrumLineChart.vue | 7 +- src/views/spectrumAnalysis/index.vue | 23 +- 8 files changed, 675 insertions(+), 209 deletions(-) diff --git a/src/utils/chartHelper.js b/src/utils/chartHelper.js index 35ee96b..3909f91 100644 --- a/src/utils/chartHelper.js +++ b/src/utils/chartHelper.js @@ -17,4 +17,26 @@ export function getXAxisAndYAxisByPosition(chart, offsetX, offsetY, seriesIndex return [xAxis, yAxis] } return null +} + +/** + * 将图表导出为图片 + * @param {import("echarts").ECharts} chartInstance + * @param {'png' | 'jpeg' | 'svg'} type + */ +export function exportEchartImg(chartInstance, type = 'png') { + const dataURL = chartInstance.getDataURL({ + type, + pixelRatio: 2, + backgroundColor: '#022024' + }); + + const link = document.createElement('a') + link.style.display = 'none' + link.href = dataURL + link.setAttribute('download', 'export.png') + document.body.appendChild(link) + link.click() + document.body.removeChild(link) //下载完成移除元素 + } \ No newline at end of file diff --git a/src/views/spectrumAnalysis/components/Modals/BetaGammaModals/BetaGammaEnergyCalibrationModal/components/BetaDetectorCalibration.vue b/src/views/spectrumAnalysis/components/Modals/BetaGammaModals/BetaGammaEnergyCalibrationModal/components/BetaDetectorCalibration.vue index bf52c3a..2941277 100644 --- a/src/views/spectrumAnalysis/components/Modals/BetaGammaModals/BetaGammaEnergyCalibrationModal/components/BetaDetectorCalibration.vue +++ b/src/views/spectrumAnalysis/components/Modals/BetaGammaModals/BetaGammaEnergyCalibrationModal/components/BetaDetectorCalibration.vue @@ -1,123 +1,168 @@ @@ -125,6 +170,8 @@ import CustomChart from '@/components/CustomChart/index.vue' import TitleOverBorder from '@/views/spectrumAnalysis/components/TitleOverBorder.vue' import { getAction } from '@/api/manage' +import { cloneDeep } from 'lodash' +import { exportEchartImg, getXAxisAndYAxisByPosition } from '@/utils/chartHelper' const initialBetaGammaChartOption = { grid: { @@ -133,20 +180,6 @@ const initialBetaGammaChartOption = { right: 10, bottom: 45 }, - tooltip: { - trigger: 'item', - formatter: params => { - const [b, g, c] = params.value - return `Beta: ${b}
Gamma: ${g}
Count: ${c}` - }, - axisPointer: { - animation: false, - type: 'cross', - lineStyle: { - type: 'dashed' - } - } - }, xAxis: { name: 'Beta Channel', nameTextStyle: { @@ -209,7 +242,7 @@ const initialBetaGammaChartOption = { }, series: { type: 'scatter', - symbolSize: 5, + symbolSize: 2, data: [], itemStyle: { color: '#fff' @@ -223,6 +256,19 @@ const initialGammaGatedChartOption = { right: 15, bottom: 50 }, + tooltip: { + trigger: 'axis', + axisPointer: { + lineStyle: { + color: '#099D24' + } + }, + formatter: params => { + const [channel] = params[0].value + return `
Channel: ${channel}
` + }, + className: 'figure-chart-option-tooltip' + }, xAxis: { min: 0, max: 256, @@ -288,7 +334,21 @@ const initialGammaGatedChartOption = { color: '#04ADD9' }, symbol: 'none', - data: [] + data: [], + markLine: { + symbol: 'none', + label: { + show: false + }, + animation: false, + emphasis: { + disabled: true + }, + lineStyle: { + color: '#f00' + }, + data: [] + } } } @@ -298,6 +358,20 @@ const initialFigureChartOption = { right: 15, bottom: 50 }, + tooltip: { + trigger: 'axis', + axisPointer: { + lineStyle: { + color: '#099D24' + } + }, + formatter: params => { + const [channel, energy] = params[0].value + return `
Channel: ${channel}
+
Energy: ${energy.toFixed(3)}
` + }, + className: 'figure-chart-option-tooltip' + }, xAxis: { min: 0, max: 256, @@ -355,7 +429,7 @@ const initialFigureChartOption = { fontSize: 14, color: '#5b9cba' }, - nameGap: 25 + nameGap: 55 }, series: { type: 'line', @@ -397,8 +471,10 @@ const columns = [ }, { title: 'S', - dataIndex: 'sValue', - align: 'center' + align: 'center', + scopedSlots: { + customRender: 'operation' + } } ] @@ -413,33 +489,43 @@ export default { this.columns = columns return { - betaGammaChartOption: initialBetaGammaChartOption, - gammaGatedChartOption: initialGammaGatedChartOption, - figureChartOption: initialFigureChartOption, - list: [ - { - channel: 'channel', - energy: 'energy', - fwhmC: 'fwhmC', - fwhmKev: 'fwhmKev', - sValue: 'sValue' - }, - { - channel: 'channel', - energy: 'energy', - fwhmC: 'fwhmC', - fwhmKev: 'fwhmKev', - sValue: 'sValue' - }, - { - channel: 'channel', - energy: 'energy', - fwhmC: 'fwhmC', - fwhmKev: 'fwhmKev', - sValue: 'sValue' - } - ], - isLoading: false + betaGammaChartOption: cloneDeep(initialBetaGammaChartOption), + gammaGatedChartOption: cloneDeep(initialGammaGatedChartOption), + figureChartOption: cloneDeep(initialFigureChartOption), + + list: [], + isLoading: false, + + gammaEnergy: [], + gammaGatedBetaSpectrum: [], + gammaChannelWidth: 5, // 左上角 Gamma Channel Width + betaGammaInfo: {}, // 左上角 鼠标悬停在散点图上时的channel和energy信息 + + markLineVisible: false, + markLinePosition: { + top: 0 + }, + + rectVisible: false, + rectPosition: { + top: 0 + }, + + tooltipVisible: false, + tooltipPosition: { + top: 0, + left: 0 + }, + + channelAndEnergyModel: {}, + + c2e: {}, + e2c: {}, + + newCalibrationFuncModel: [], + + newCalibrationIsAppliedTo: '2', + recalculateROICountsFor: [] } }, created() { @@ -460,6 +546,22 @@ export default { }) console.log('%c [ res ]-462', 'font-size:13px; background:pink; color:#bf2c9f;', res) if (res.success) { + const { CToE, EToC, betaEnergy, gammaEnergy, gammaGatedBetaSpectrum, histogramData } = res.result + this.c2e = CToE + this.e2c = EToC + + this.betaGammaChartOption.series.data = histogramData.map(({ b, g, c }) => [b, g, c]) + this.gammaEnergy = gammaEnergy + this.gammaGatedBetaSpectrum = gammaGatedBetaSpectrum + + const gammaEnergyValue = betaEnergy.map(item => item[0]) + const gammaEnergyMax = Math.ceil(Math.max(...gammaEnergyValue)) + const gammaEnergyMin = Math.floor(Math.min(...gammaEnergyValue)) + const gammaEnergyInterval = Math.ceil(((gammaEnergyMax - gammaEnergyMin) / 4) * 1.1) + this.figureChartOption.yAxis.max = gammaEnergyInterval * 4 + this.figureChartOption.yAxis.min = gammaEnergyMin + this.figureChartOption.yAxis.interval = Math.ceil((gammaEnergyMax * 1.1) / 4) + this.figureChartOption.series.data = gammaEnergyValue.map((item, index) => [index, item]) } else { this.$message.error(res.message) } @@ -468,6 +570,126 @@ export default { } finally { this.isLoading = false } + }, + + // 点击左上角散点图,设置红线 + handleBetaGammaChartClick(param) { + const { offsetX, offsetY } = param + const point = getXAxisAndYAxisByPosition(this.$refs.betaGammaChartRef.getChartInstance(), offsetX, offsetY) + if (point) { + this.markLinePosition.top = offsetY + this.markLineVisible = true + + // 设置 gamma-gated beta spectrum + const yAxis = parseInt(point[1].toFixed()) + + this.currEnergy = this.gammaEnergy[yAxis][0].toFixed(2) // 设置当前选中位置的Energy + this.channelAndEnergyModel = {} + + const currGammaGatedBetaSpectrum = this.gammaGatedBetaSpectrum[yAxis] + const max = Math.max(...currGammaGatedBetaSpectrum) + const interval = Math.ceil((max / 4) * 1.1) + this.gammaGatedChartOption.yAxis.max = interval * 4 + this.gammaGatedChartOption.yAxis.interval = interval + this.gammaGatedChartOption.series.data = currGammaGatedBetaSpectrum.map((item, index) => [index, item]) + } + }, + + // 绿框跟随鼠标移动 + handleBetaGammaChartMouseMove(param) { + const { offsetX, offsetY } = param + const point = getXAxisAndYAxisByPosition(this.$refs.betaGammaChartRef.getChartInstance(), offsetX, offsetY) + if (point) { + this.rectPosition.top = offsetY + this.rectVisible = true + + if (this.gammaEnergy && this.gammaEnergy.length) { + // 设置 Channel 和 Energy + const yAxis = parseInt(point[1].toFixed()) + const energy = this.gammaEnergy[yAxis][0].toFixed(2) + this.betaGammaInfo = { + channel: yAxis, + energy + } + } + } + }, + + // Gamma Gated Beta Spectrum: QC 图表点击 + handleGammaGatedSpectrumChartClick(param) { + const { offsetX, offsetY } = param + const point = getXAxisAndYAxisByPosition(this.$refs.gammaGatedChartRef.getChartInstance(), offsetX, offsetY) + if (point) { + const xAxis = parseInt(point[0].toFixed()) + this.gammaGatedChartOption.series.markLine.data = [{ xAxis }] + + this.tooltipChannel = xAxis + this.tooltipPosition.top = offsetY + if (xAxis > 187) { + this.tooltipPosition.left = offsetX - 125 + } else { + this.tooltipPosition.left = offsetX + 20 + } + this.tooltipVisible = true + this.channelAndEnergyModel.channel = xAxis + this.channelAndEnergyModel.energy = this.currEnergy + } + }, + + // 增加新的Channel 和 Energy 到表格里 + handleAddChannelAndEnergy() { + const { channel, energy } = this.channelAndEnergyModel + + if (!channel || !energy) { + return + } + + this.list.push({ + channel, + energy + }) + + this.channelAndEnergyModel = {} + }, + + // 删除表格里的单项 + handleDel(index) { + this.list.splice(index, 1) + }, + + // 下载图表图片 + handleSnapshot(chartRef) { + const chartInstance = chartRef.getChartInstance() + exportEchartImg(chartInstance) + }, + + // 点击Reset Button 重置 + handleReset() { + this.newCalibrationFuncModel = [] + }, + + // 点击Fitting按钮执行重新计算 + handleFitting() {}, + + /** + * 返回的科学计数法的字符串处理 + * @param {string} str + */ + scientificNotationStr2Fixed(str) { + if (str) { + const arr = str.split('E') + const start = arr[0] + const end = arr[1] + return `${Number(start).toPrecision(6)}${end ? 'e' + end : ''}` + } + return '' + } + }, + computed: { + rectHeight() { + const { top, bottom } = initialBetaGammaChartOption.grid + const totalHeight = 427 - top - bottom + return (totalHeight / 256) * this.gammaChannelWidth } } } @@ -502,6 +724,26 @@ p { .beta-gamma-chart { height: 427px; + position: relative; + + .markline { + position: absolute; + left: 55px; + width: 442px; + height: 1px; + background-color: red; + pointer-events: none; + } + + .rect { + position: absolute; + left: 55px; + width: 442px; + border: 1px solid #0f0; + background-color: rgba(0, 255, 0, 0.4); + transform: translateY(-50%); + pointer-events: none; + } } } @@ -526,6 +768,10 @@ p { align-items: center; .ant-input { + width: 120px; + } + + .ant-btn { width: 100px; } } @@ -595,6 +841,17 @@ p { .ant-input { width: 70px; } + + .func { + display: flex; + + span { + &:nth-child(2) { + flex: 1; + text-align: center; + } + } + } } &-btns { @@ -637,4 +894,37 @@ p { } } } + +.custom-tool-tip { + position: absolute; + border-style: solid; + white-space: nowrap; + z-index: 99999; + box-shadow: rgba(0, 0, 0, 0.2) 1px 2px 10px; + border-width: 1px; + border-radius: 4px; + padding: 10px; + border-color: rgb(255, 255, 255); + pointer-events: none; + background-color: #00aa7f; + border-color: #00aa7f; + + .channel { + color: #fff; + } +} + + diff --git a/src/views/spectrumAnalysis/components/Modals/BetaGammaModals/BetaGammaEnergyCalibrationModal/components/GammaDetectorCalibration.vue b/src/views/spectrumAnalysis/components/Modals/BetaGammaModals/BetaGammaEnergyCalibrationModal/components/GammaDetectorCalibration.vue index baaa13b..4eed3ad 100644 --- a/src/views/spectrumAnalysis/components/Modals/BetaGammaModals/BetaGammaEnergyCalibrationModal/components/GammaDetectorCalibration.vue +++ b/src/views/spectrumAnalysis/components/Modals/BetaGammaModals/BetaGammaEnergyCalibrationModal/components/GammaDetectorCalibration.vue @@ -11,19 +11,31 @@ :option="gammaSpectrumChartOption" @zr:click="handleGammaSpectrumChartClick" /> - Snapshot + Snapshot + +
+
Channel: {{ tooltipChannel }}
+
+
- + - + - Add + Add
+ > + +

Figure of Gamma Detector Calibration

- - Snapshot + + Snapshot
@@ -71,8 +87,9 @@ C to E : E = - + *C + - *C 2 + + + *C + + *C 2

@@ -82,29 +99,29 @@
- Reset Button - Fitting + Reset Button + Fitting