AnalysisSystemForRadionucli.../src/views/spectrumAnalysis/gamma-analysis.vue
任珮宇 8fa955e4f4 Merge branch 'feature-spectrum-analysis' into feature-analysis-RLR-renpy
# Conflicts:
#	src/api/manage.js
#	src/views/spectrumAnalysis/gamma-analysis.vue
#	src/views/spectrumAnalysis/index.vue
2023-09-15 16:25:47 +08:00

1269 lines
36 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="gamma-analysis">
<a-spin :spinning="isLoading">
<!-- 二级交互栏 -->
<div class="spectrum-analysis-sub-operators">
<pop-over-with-icon placement="bottomLeft">
Detailed-Information
<detailed-infomation slot="content" :data="detailedInfomation" />
</pop-over-with-icon>
<pop-over-with-icon placement="bottomLeft">
QC Flags
<qc-flags slot="content" :data="qcFlags" />
</pop-over-with-icon>
<pop-over-with-icon>
Graph Assistance
<graph-assistance
v-if="!isLoading"
slot="content"
@change="handleGraphAssistanceChange"
@reset="handleReset"
/>
</pop-over-with-icon>
<pop-over-with-icon>
Nuclide Library
<nuclear-library slot="content" :list="nuclideLibraryList" />
</pop-over-with-icon>
<div class="peak-info">
<button-with-switch-icon @change="handlePeakInfoChange" @click="handleTogglePeak"></button-with-switch-icon>
</div>
</div>
<!-- 二级交互栏结束 -->
<!-- 主体部分 -->
<div class="gamma-analysis-main">
<div class="gamma-analysis-chart">
<CustomChart
ref="chartRef"
:option="option"
:opts="opts"
@zr:click="handleChartClick"
@zr:mousedown="handleMouseDown"
@zr:mouseup="handleMouseUp"
@brushEnd="handleBrushEnd"
style="height: 100%"
/>
<!-- 右上角缩略图 -->
<div class="gamma-analysis-thumbnail">
<CustomChart
ref="thumbnailChartRef"
:option="thumbnailOption"
@zr:click="handleThumbnailChartClick"
style="height: 100%"
/>
</div>
<!-- 缩略图结束 -->
<!-- 自定义tooltip用于展示Peak Infomation -->
<div
v-if="peakInfomationTooltip.visible"
class="peak-infomation-tooltip"
:style="{
top: peakInfomationTooltip.top + 'px',
left: peakInfomationTooltip.left + 'px',
}"
>
<div class="peak-infomation-tooltip-content" v-html="peakInfomationTooltip.content"></div>
</div>
<!-- tooltip结束 -->
</div>
</div>
<!-- 主体部分结束 -->
</a-spin>
</div>
</template>
<script>
import CustomChart from '@/components/CustomChart/index.vue'
import PopOverWithIcon from './components/SubOperators/PopOverWithIcon.vue'
import DetailedInfomation from './components/SubOperators/DetailedInfomation.vue'
import QcFlags from './components/SubOperators/QcFlags.vue'
import GraphAssistance from './components/SubOperators/GraphAssistance.vue'
import NuclearLibrary from './components/SubOperators/NuclearLibrary.vue'
import ButtonWithSwitchIcon from './components/SubOperators/ButtonWithSwitchIcon.vue'
import { getAction } from '@/api/manage'
import Response from './response.json'
import { buildLineSeries, findSeriesByName, getXAxisAndYAxisByPosition, rangeNumber } from '@/utils/chartHelper'
import { cloneDeep } from 'lodash'
import axios from 'axios'
// 初始配置
const initialOption = {
grid: {
top: 40,
left: 60,
right: 50,
containLabel: true,
},
title: {
text: '',
left: 'center',
bottom: 10,
textStyle: {
color: '#8FD4F8',
rich: {
a: {
padding: [0, 20, 0, 0],
fontSize: 16,
},
},
},
},
tooltip: {
trigger: 'axis',
axisPointer: {
lineStyle: {
color: '#3CAEBB',
width: 1,
type: 'solid',
},
},
formatter: undefined,
className: 'figure-chart-option-tooltip',
},
xAxis: {
name: 'Channel',
nameTextStyle: {
color: '#8FD4F8',
fontSize: 16,
align: 'right',
verticalAlign: 'top',
padding: [30, 0, 0, 0],
},
axisLine: {
lineStyle: {
color: '#ade6ee',
},
},
splitLine: {
show: false,
},
axisLabel: {
textStyle: {
color: '#ade6ee',
},
},
min: 1,
max: 'dataMax',
animation: false,
axisLabel: {
formatter: (value) => {
return parseInt(value)
},
},
},
yAxis: {
name: 'Counts',
type: 'value',
nameTextStyle: {
color: '#8FD4F8',
fontSize: 16,
},
axisLine: {
show: true,
lineStyle: {
color: '#ade6ee',
},
},
splitLine: {
show: true,
lineStyle: {
color: 'rgba(173, 230, 238, .2)',
},
},
axisLabel: {
textStyle: {
color: '#ade6ee',
},
},
min: 1,
max: 'dataMax',
animation: false,
axisLabel: {
formatter: (value) => {
return value.toFixed(1)
},
},
},
series: [],
brush: {},
}
// 缩略图配置
const thumbnailOption = {
grid: {
top: 0,
left: 5,
right: 5,
bottom: 0,
},
xAxis: {
type: 'category',
axisLine: {
show: false,
},
splitLine: {
show: false,
},
axisLabel: {
show: false,
},
min: 1,
max: 'dataMax',
},
yAxis: {
type: 'value',
axisLine: {
show: false,
},
splitLine: {
show: false,
},
axisLabel: {
show: false,
},
min: 1,
max: 'dataMax',
},
series: [],
}
const graphAssistance = {
axisType: 'Channel',
Baseline: true,
SCAC: true,
Lc: true,
}
export default {
props: {
sample: {
type: Object,
},
},
components: {
CustomChart,
PopOverWithIcon,
DetailedInfomation,
QcFlags,
GraphAssistance,
NuclearLibrary,
ButtonWithSwitchIcon,
},
data() {
return {
isLoading: false,
option: cloneDeep(initialOption),
opts: {
notMerge: false,
},
thumbnailOption: cloneDeep(thumbnailOption),
detailedInfomation: [],
qcFlags: [],
graphAssistance: cloneDeep(graphAssistance),
channelPeakGroup: [],
energyPeakGroup: [],
nuclideLibraryList: [], // 当前鼠标点击选中的channel
peakInfomationTooltip: {
// Peak Infomation的位置
visible: false,
content: '',
top: 0,
left: 0,
},
}
},
created() {
this.option.title.text = '{a|Channel:0} {a|Energy:0} {a|Counts:0} {a|Detectability:0}'
this.$bus.$on('colorChange', this.handleColorChange)
this.$bus.$on('gammaRefresh', this.handleRefresh)
this.$bus.$on('accept', this.handleAccept)
},
destroyed() {
this.$bus.$off('colorChange', this.handleColorChange)
this.$bus.$off('gammaRefresh', this.handleRefresh)
this.$bus.$off('accept', this.handleAccept)
},
mounted() {
this.option.brush = { toolbox: [] }
},
methods: {
async getSampleDetail() {
const { dbName, sampleId } = this.sample
try {
this.isLoading = true
this.reset()
// const { success, result, message } = Response
if (this._cancelToken && typeof this._cancelToken == 'function') {
this._cancelToken()
}
const cancelToken = new axios.CancelToken((c) => {
this._cancelToken = c
})
const { success, result, message } = await getAction(
'/gamma/gammaByDB',
{
dbName,
sampleId,
},
cancelToken
)
console.log('%c [ result ]-243', 'font-size:13px; background:pink; color:#bf2c9f;', result)
if (success) {
this.dataProsess(result)
} else {
this.$message.error(message)
}
} catch (error) {
console.error(error)
}
},
async getSampleDetail_file() {
const { inputFileName: fileName } = this.sample
try {
this.isLoading = true
this.option.series = []
this.thumbnailOption.series = []
// const { success, result, message } = Response
const { success, result, message } = await getAction('/gamma/gammaByFile', {
fileName,
})
console.log('%c [ result ]-243', 'font-size:13px; background:pink; color:#bf2c9f;', result)
if (success) {
this.dataProsess(result)
} else {
this.$message.error(message)
}
} catch (error) {
console.error(error)
}
},
dataProsess(result) {
this.isLoading = false
const {
dead_time,
live_time,
real_time,
start_time,
DetailedInformation,
QCFlag,
allData,
shadowChannelChart,
shadowEnergyChart,
shapeChannelData,
shapeEnergyData,
} = result
this.detailedInfomation = DetailedInformation
this.qcFlags = QCFlag
const channelPeakGroup = allData.filter((item) => item.name == 'Peak' && item.group == 'channel')
const energyPeakGroup = allData.filter((item) => item.name == 'Peak' && item.group == 'energy')
const channelBaseLine = allData.find((item) => item.name == 'BaseLine' && item.group == 'channel') || {}
const energyBaseLine = allData.find((item) => item.name == 'BaseLine' && item.group == 'energy')
const channelLcLine = allData.find((item) => item.name == 'Lc' && item.group == 'channel') || {}
const energyLcLine = allData.find((item) => item.name == 'Lc' && item.group == 'energy')
const channelScacLine = allData.find((item) => item.name == 'Scac' && item.group == 'channel') || {}
const energyScacLine = allData.find((item) => item.name == 'Scac' && item.group == 'energy')
this.allEnergy = allData.find((item) => item.name == 'Energy' && item.group == 'energy') || {}
this.allChannel = allData.find((item) => item.name == 'Count' && item.group == 'channel')
// 保存Peak Line
this.channelPeakGroup = channelPeakGroup
this.energyPeakGroup = energyPeakGroup
// 保存 Spectrum Line
this.shadowChannelChart = shadowChannelChart
this.shadowEnergyChart = shadowEnergyChart
// 保存基线
this.channelBaseLine = channelBaseLine
this.energyBaseLine = energyBaseLine
// 保存Lc
this.channelLcLine = channelLcLine
this.energyLcLine = energyLcLine
// 保存Scac
this.channelScacLine = channelScacLine
this.energyScacLine = energyScacLine
// 保存 基线控制点
this.shapeChannelData = shapeChannelData
this.shapeEnergyData = shapeEnergyData
this.option.yAxis.max =
shadowChannelChart.pointlist && Math.ceil(Math.max(...shadowChannelChart.pointlist.map((item) => item.y)) * 1.1)
this.thumbnailOption.yAxis.max =
shadowChannelChart.pointlist && Math.ceil(Math.max(...shadowChannelChart.pointlist.map((item) => item.y)) * 1.1)
const series = []
// 推入Spectrum Line
series.push(
buildLineSeries(
'Spectrum',
shadowChannelChart.pointlist && shadowChannelChart.pointlist.map(({ x, y }) => [x, y]),
shadowChannelChart.color,
{
markLine: {
silent: true,
symbol: 'none',
label: {
show: false,
},
lineStyle: {
color: 'red',
width: 1,
},
data: [{ xAxis: -1 }],
},
}
)
)
// 右上角缩略图推入Spectrum Line
this.thumbnailOption.series.push(
buildLineSeries(
'Spectrum',
shadowChannelChart.pointlist && shadowChannelChart.pointlist.map(({ x, y }) => [x, y]),
shadowChannelChart.color,
{
silent: true,
markLine: {
silent: true,
symbol: 'none',
label: {
show: false,
},
lineStyle: {
type: 'solid',
color: '#1397a3',
width: 1,
},
data: [],
},
}
)
)
// 推入BaseLine
series.push(
buildLineSeries(
'BaseLine',
channelBaseLine.pointlist && channelBaseLine.pointlist.map(({ x, y }) => [x, y]),
channelBaseLine.color,
{
zlevel: 2,
}
)
)
// 推入LcLine线
series.push(
buildLineSeries(
'LcLine',
channelLcLine.pointlist && channelLcLine.pointlist.map(({ x, y }) => [x, y]),
channelLcLine.color,
{
zlevel: 3,
}
)
)
// 推入Scac线
series.push(
buildLineSeries(
'ScacLine',
channelScacLine.pointlist && channelScacLine.pointlist.map(({ x, y }) => [x, y]),
channelScacLine.color,
{
zlevel: 4,
}
)
)
// 推入基线控制点
series.push({
name: 'BaseLine_Ctrl_Point',
type: 'scatter',
data: shapeChannelData.map(({ size, color, point: { x, y } }) => {
return {
value: [x, y],
itemStyle: {
color: 'transparent',
borderColor: color,
borderWidth: size / 2,
},
}
}),
emphasis: {
disabled: true,
},
animation: false,
zlevel: 5,
})
// 推入Peak Line
const peakLines = []
channelPeakGroup.forEach((item, index) => {
peakLines.push(
buildLineSeries(
`Peak_${index}`,
item.pointlist.map(({ x, y }) => [x, y]),
item.color,
{
zlevel: 6,
}
)
)
})
series.push(...peakLines)
this.option.series = series
this.option.tooltip.formatter = this.tooltipFormatter
},
tooltipFormatter(params) {
if (this.isEnergy()) {
const energy = params[0].value[0]
const channel = this.getChannelByEnergy(energy)
return `<div class="channel">Channel: ${channel}</div>
<div class="energy">Energy: ${energy.toFixed(2)}</div>`
} else {
const channel = parseInt(params[0].value[0].toFixed())
const energy = this.allEnergy.pointlist && this.allEnergy.pointlist[channel - 1]
return energy
? `<div class="channel">Channel: ${channel}</div>
<div class="energy">Energy: ${energy.x.toFixed(2)}</div>`
: undefined
}
},
// Graph Assistance 操作
handleGraphAssistanceChange({ type, label, value }) {
// 类型变化
if (type == 'labelChange') {
switch (label) {
case 'Linear':
this.option.yAxis.type = 'value'
this.thumbnailOption.yAxis.type = 'value'
this.handleReset()
break
case 'Log10':
this.option.yAxis.type = 'log'
this.thumbnailOption.yAxis.type = 'log'
this.handleReset()
break
case 'Channel':
case 'Energy':
this.graphAssistance.axisType = label
this.option.xAxis.name = label
this.handleReset()
this.redrawLineBySeriesName(
'BaseLine',
this.energyBaseLine,
this.channelBaseLine,
this.graphAssistance.Baseline
)
this.redrawLineBySeriesName('LcLine', this.energyLcLine, this.channelLcLine, this.graphAssistance.Lc)
this.redrawLineBySeriesName(
'ScacLine',
this.energyScacLine,
this.channelScacLine,
this.graphAssistance.SCAC
)
this.redrawLineBySeriesName('Spectrum', this.shadowEnergyChart, this.shadowChannelChart)
this.redrawCtrlPointBySeriesName()
this.redrawPeakLine()
this.redrawThumbnailChart()
break
case 'Lines':
this.option.series[0].type = 'line'
this.option.series[0].symbol = 'none'
this.thumbnailOption.series[0].type = 'line'
this.thumbnailOption.series[0].symbol = 'none'
break
case 'Scatter':
this.option.series[0].type = 'scatterGL'
this.option.series[0].symbol = 'circle'
this.thumbnailOption.series[0].type = 'scatterGL'
this.thumbnailOption.series[0].symbol = 'circle'
break
}
}
// 值变化
else if (type == 'valueChange') {
this.graphAssistance[label] = value
switch (label) {
case 'Cursor':
// 显示红色竖线
if (value) {
this.option.series[0].markLine.lineStyle.width = 2
} else {
this.option.series[0].markLine.lineStyle.width = 0
}
break
case 'Baseline':
this.redrawLineBySeriesName('BaseLine', this.energyBaseLine, this.channelBaseLine, value)
break
case 'Lc':
this.redrawLineBySeriesName('LcLine', this.energyLcLine, this.channelLcLine, value)
break
case 'SCAC':
this.redrawLineBySeriesName('ScacLine', this.energyScacLine, this.channelScacLine, value)
break
}
}
},
// 根据seriesName重绘线
redrawLineBySeriesName(seriesName, energyData, channelData, isShow = true) {
const series = findSeriesByName(this.option.series, seriesName)
if (isShow) {
const data = this.isEnergy() ? energyData : channelData
series.data = data.pointlist.map(({ x, y }) => [x, y])
} else {
series.data = []
}
},
// 重绘控制点
redrawCtrlPointBySeriesName() {
const series = findSeriesByName(this.option.series, 'BaseLine_Ctrl_Point')
const data = this.isEnergy() ? this.shapeEnergyData : this.shapeChannelData
series.data = data.map(({ size, color, point: { x, y } }) => {
return {
value: [x, y],
itemStyle: {
color: 'transparent',
borderColor: color,
borderWidth: size / 2,
},
}
})
},
// 重绘Peak Line
redrawPeakLine() {
this.option.series = this.option.series.filter((item) => {
return !item.name.includes('Peak_')
})
const data = this.isEnergy() ? this.energyPeakGroup : this.channelPeakGroup
const peakLines = []
data.forEach((item, index) => {
peakLines.push(
buildLineSeries(
`Peak_${index}`,
item.pointlist.map(({ x, y }) => [x, y]),
item.color,
{
zlevel: 6,
}
)
)
})
this.option.series.push(...peakLines)
},
// 重绘右上角的缩略图
redrawThumbnailChart() {
const series = this.thumbnailOption.series[0]
const data = this.isEnergy() ? this.shadowEnergyChart : this.shadowChannelChart
series.data = data.pointlist.map(({ x, y }) => [x, y])
},
// 点击图表,设置红线
handleChartClick(param) {
const { offsetX, offsetY } = param
const point = getXAxisAndYAxisByPosition(this.$refs.chartRef.getChartInstance(), offsetX, offsetY)
if (point) {
const xAxis = point[0]
this.option.series[0].markLine.data[0].xAxis = xAxis
const channel = this.isEnergy() ? this.getChannelByEnergy(xAxis) : parseInt(xAxis.toFixed())
const energy = this.isEnergy()
? xAxis.toFixed(2)
: this.allEnergy.pointlist && this.allEnergy.pointlist[channel - 1].x.toFixed(2)
const counts = this.isEnergy() ? this.allEnergy.pointlist[channel - 1] : this.allChannel.pointlist[channel - 1]
this.option.title.text = `{a|Channel:${channel}} {a|Energy:${energy}} {a|Counts:${counts.y}} {a|Detectability:0}`
this.getSelPosNuclide(channel)
}
},
// 获取 Nuclide Library 数据
async getSelPosNuclide(channel) {
try {
this.loading = true
const { sampleId, inputFileName: fileName } = this.sample
const { success, result, message } = await getAction('/gamma/getSelPosNuclide', {
sampleId,
channel,
fileName,
})
if (success) {
const { identify } = result
this.nuclideLibraryList = identify
} else {
this.$message.error(message)
}
} catch (error) {
this.list = []
console.error(error)
} finally {
this.loading = false
}
},
resize() {
this.$refs.chartRef.resize()
this.$refs.thumbnailChartRef.resize()
this.closePeakInfomationTooltip()
},
// peak info 点击左右方向
handlePeakInfoChange(direction) {
this.moveMarkLine(direction)
},
// 触发Peak Infomation
handleTogglePeak() {
const xAxis = this.option.series[0].markLine.data[0].xAxis
const channel = this.isEnergy() ? this.getChannelByEnergy(xAxis) : parseInt(xAxis.toFixed())
const index = this.channelPeakGroup.findIndex((peakItem) => {
const allX = peakItem.pointlist.map((item) => item.x)
const max = Math.max(...allX)
const min = Math.min(...allX)
return channel >= min && channel <= max
})
if (-1 !== index) {
this.getPeakInfo(index)
} else {
this.closePeakInfomationTooltip()
}
},
// 获取 Peak 峰顶 信息
async getPeakInfo(index) {
try {
const { inputFileName: fileName } = this.sample
const { success, result, message } = await getAction('/gamma/clickPeakInformation', {
fileName,
index,
})
if (success) {
const html = result.replaceAll('\n', '<br>')
const currPeak = this.channelPeakGroup[index]
const { x, y } = currPeak.pointlist.reduce((prev, curr) => {
return prev && prev.y > curr.y ? prev : curr
})
const chart = this.$refs.chartRef.getChartInstance()
const [xPix, yPix] = chart.convertToPixel({ seriesIndex: 0 }, [x, y])
this.peakInfomationTooltip.content = html
this.peakInfomationTooltip.visible = true
this.peakInfomationTooltip.left = xPix
this.peakInfomationTooltip.top = yPix - 20
} else {
this.$message.error(message)
}
} catch (error) {
console.error(error)
}
},
// 关闭Peak Infomation
closePeakInfomationTooltip() {
this.peakInfomationTooltip.visible = false
},
/**
* 向某一个方向移动标记线
* @param { 'left'| 'right' } direction
*/
moveMarkLine(direction) {
const prevAxis = this.option.series[0].markLine.data[0].xAxis
// 获取每一段 Channel 中的最大值
const maxXAxises = this.channelPeakGroup.map((item) => {
const allY = item.pointlist.map((item) => item.y)
const max = item.pointlist.find((point) => point.y == Math.max(...allY))
return max.x
})
if (direction == 'right') {
// 找到第一个比prevAxis大的xAxis
const find = maxXAxises.find((xAxis) => xAxis > prevAxis)
if (find) {
this.option.series[0].markLine.data[0].xAxis = find
}
} else if (direction == 'left') {
// 找到第一个比prevAxis小的xAxis
const find = maxXAxises.reverse().find((xAxis) => xAxis < prevAxis)
if (find) {
this.option.series[0].markLine.data[0].xAxis = find
}
}
},
// 鼠标按下时开启可刷选状态
handleMouseDown() {
const chart = this.$refs.chartRef.getChartInstance()
chart.dispatchAction({
type: 'takeGlobalCursor',
// 如果想变为“可刷选状态”,必须设置。不设置则会关闭“可刷选状态”。
key: 'brush',
brushOption: {
// 参见 brush 组件的 brushType。如果设置为 false 则关闭“可刷选状态”。
brushType: 'rect',
},
})
},
handleMouseUp() {
setTimeout(() => {
const chart = this.$refs.chartRef.getChartInstance()
this.clearBrush(chart)
}, 0)
},
clearBrush(chart) {
// 清理刷选的范围
chart.dispatchAction({
type: 'brush',
areas: [],
})
// 改为不可刷选状态
chart.dispatchAction({
type: 'takeGlobalCursor',
})
},
// 刷选完毕时
handleBrushEnd(param) {
this.closePeakInfomationTooltip()
const chart = this.$refs.chartRef.getChartInstance()
const areas = param.areas[0]
if (areas) {
const range = areas.range
const [[minX, maxX], [minY, maxY]] = range
const point1 = chart.convertFromPixel({ seriesIndex: 0 }, [minX, minY]).map((num) => parseInt(num.toFixed()))
const point2 = chart.convertFromPixel({ seriesIndex: 0 }, [maxX, maxY]).map((num) => parseInt(num.toFixed()))
const xAxisMax = chart.getModel().getComponent('xAxis').axis.scale._extent[1]
const yAxisMax = this.option.yAxis.max
let [x1, y2, x2, y1] = [...point1, ...point2] // 根据解析出的数据确定真实的范围
const xAxisLimit = rangeNumber(1, xAxisMax)
const yAxisLimit = rangeNumber(1, yAxisMax)
x1 = xAxisLimit(x1)
x2 = xAxisLimit(x2)
y1 = yAxisLimit(y1)
y2 = yAxisLimit(y2)
this.option.xAxis.min = x1
this.option.xAxis.max = x2
this.option.yAxis.min = y1
this.option.yAxis.max = y2
if (this.isEnergy()) {
const channel1 = this.getChannelByEnergy(x1)
const channel2 = this.getChannelByEnergy(x2)
this.setThumbnailChartRect(channel1, y2, channel2, y1)
} else {
this.setThumbnailChartRect(x1, y2, x2, y1)
}
const thumbnailChart = this.$refs.thumbnailChartRef.getChartInstance()
const [, maxYPixel] = thumbnailChart.convertToPixel({ seriesIndex: 0 }, [0, y1]) // 方框的上下两条边的yAxis转为pix
const [, minYPixel] = thumbnailChart.convertToPixel({ seriesIndex: 0 }, [0, y2])
const rectHeightPixel = maxYPixel - minYPixel // 计算方框的左右边长(pix)
this.halfHeightPixel = rectHeightPixel / 2
}
this.clearBrush(chart)
},
// 在右上角缩略图中设置范围
setThumbnailChartRect(x1, y2, x2, y1) {
this.thumbnailChartRect = [x1, y2, x2, y1]
const { markLine } = this.thumbnailOption.series[0]
const pointList = [
[
[x1, y1],
[x2, y1],
],
[
[x2, y1],
[x2, y2],
],
[
[x2, y2],
[x1, y2],
],
[
[x1, y2],
[x1, y1],
],
]
const lines = pointList.map((point) => {
return this.generateLineDataByTwoPoints(point[0], point[1])
})
markLine.data = lines
},
// 缩略图点击
handleThumbnailChartClick(param) {
const { offsetX, offsetY } = param
const thumbnailChart = this.$refs.thumbnailChartRef.getChartInstance()
const point = getXAxisAndYAxisByPosition(thumbnailChart, offsetX, offsetY)
if (point && this.thumbnailChartRect && this.thumbnailChartRect.length) {
const [x1, y2, x2, y1] = this.thumbnailChartRect
const halfWidth = Math.ceil((x2 - x1) / 2)
const [, maxYAxisPixel] = thumbnailChart.convertToPixel({ seriesIndex: 0 }, [0, this.thumbnailOption.yAxis.max]) // 缩略图最大值转为pix
const [, minYAxisPixel] = thumbnailChart.convertToPixel({ seriesIndex: 0 }, [0, 1])
let [xAxis, yAxis] = point
const xAxisMax = thumbnailChart.getModel().getComponent('xAxis').axis.scale._extent[1]
const xAxisLimit = rangeNumber(1 + halfWidth, xAxisMax - halfWidth)
const halfHeightPixel = this.halfHeightPixel
const yAxisLimit = rangeNumber(maxYAxisPixel + halfHeightPixel, minYAxisPixel - halfHeightPixel)
xAxis = xAxisLimit(xAxis)
let [, yAxisPixel] = thumbnailChart.convertToPixel({ seriesIndex: 0 }, [0, yAxis])
yAxisPixel = yAxisLimit(yAxisPixel)
const minYAxis = thumbnailChart.convertFromPixel({ seriesIndex: 0 }, [0, yAxisPixel + halfHeightPixel])[1] // 再把y轴最小值从pix转为yAxis
const maxYAxis = thumbnailChart.convertFromPixel({ seriesIndex: 0 }, [0, yAxisPixel - halfHeightPixel])[1]
this.setThumbnailChartRect(xAxis - halfWidth, maxYAxis, xAxis + halfWidth, minYAxis)
if (this.isEnergy()) {
const x1 = parseInt(this.shadowEnergyChart.pointlist[xAxis - halfWidth].x)
const x2 = parseInt(this.shadowEnergyChart.pointlist[xAxis + halfWidth].x)
this.option.xAxis.min = x1
this.option.xAxis.max = x2
} else {
this.option.xAxis.min = xAxis - halfWidth
this.option.xAxis.max = xAxis + halfWidth
}
this.option.yAxis.min = minYAxis
this.option.yAxis.max = maxYAxis
}
},
// 重置
handleReset() {
this.option.xAxis.min = 1
this.option.xAxis.max = 'dataMax'
this.option.yAxis.min = 1
this.option.yAxis.max = Math.ceil(Math.max(...this.shadowChannelChart.pointlist.map((item) => item.y)) * 1.1)
this.thumbnailOption.series[0].markLine.data = []
this.thumbnailChartRect = []
this.closePeakInfomationTooltip()
},
// 从分析工具刷新部分数据
handleRefresh(data) {
const { allData, shadowChannelChart, shadowEnergyChart, shapeChannelData, shapeEnergyData } = data
const channelPeakGroup = allData.filter((item) => item.name == 'Peak' && item.group == 'channel')
const energyPeakGroup = allData.filter((item) => item.name == 'Peak' && item.group == 'energy')
const channelBaseLine = allData.find((item) => item.name == 'BaseLine' && item.group == 'channel')
const energyBaseLine = allData.find((item) => item.name == 'BaseLine' && item.group == 'energy')
const channelLcLine = allData.find((item) => item.name == 'Lc' && item.group == 'channel')
const energyLcLine = allData.find((item) => item.name == 'Lc' && item.group == 'energy')
const channelScacLine = allData.find((item) => item.name == 'Scac' && item.group == 'channel')
const energyScacLine = allData.find((item) => item.name == 'Scac' && item.group == 'energy')
this.allEnergy = allData.find((item) => item.name == 'Energy' && item.group == 'energy')
this.allChannel = allData.find((item) => item.name == 'Count' && item.group == 'channel')
// 保存Peak Line
this.channelPeakGroup = channelPeakGroup
this.energyPeakGroup = energyPeakGroup
// 保存 Spectrum Line
this.shadowChannelChart = shadowChannelChart
this.shadowEnergyChart = shadowEnergyChart
// 保存基线
this.channelBaseLine = channelBaseLine
this.energyBaseLine = energyBaseLine
// 保存Lc
this.channelLcLine = channelLcLine
this.energyLcLine = energyLcLine
// 保存Scac
this.channelScacLine = channelScacLine
this.energyScacLine = energyScacLine
// 保存 基线控制点
this.shapeChannelData = shapeChannelData
this.shapeEnergyData = shapeEnergyData
this.opts.notMerge = true
this.redrawPeakLine()
this.redrawCtrlPointBySeriesName()
this.redrawLineBySeriesName('BaseLine', this.energyBaseLine, this.channelBaseLine, this.graphAssistance.Baseline)
this.redrawLineBySeriesName('LcLine', this.energyLcLine, this.channelLcLine, this.graphAssistance.Lc)
this.redrawLineBySeriesName('ScacLine', this.energyScacLine, this.channelScacLine, this.graphAssistance.SCAC)
this.redrawLineBySeriesName('Spectrum', this.shadowEnergyChart, this.shadowChannelChart)
this.redrawThumbnailChart()
this.$nextTick(() => {
this.resetChartOpts()
})
},
// 分析工具Accept时刷新部分数据
handleAccept() {
console.log('%c [ 分析工具Accept时刷新部分数据 ]-1046', 'font-size:13px; background:pink; color:#bf2c9f;')
},
// 重置图表配置
resetChartOpts() {
this.opts.notMerge = false
this.option.brush = { toolbox: [] }
},
/**
* 根据两个点生成一个markLine直线
*/
generateLineDataByTwoPoints(point1, point2) {
return [
{
xAxis: point1[0],
yAxis: point1[1],
},
{
xAxis: point2[0],
yAxis: point2[1],
},
]
},
getChannelByEnergy(energy) {
let channel = 0
for (let index = 1; index < this.allEnergy.pointlist.length; index++) {
const currEnergy = this.allEnergy.pointlist[index].x
if (currEnergy >= energy) {
const prevEnergy = this.allEnergy.pointlist[index - 1].x
if (currEnergy - energy > energy - prevEnergy.x) {
channel = index
} else {
channel = index + 1
}
break
}
}
return channel
},
// 重置页面信息
reset() {
this.selectedChannel = -1
this.nuclideLibraryList = []
this.closePeakInfomationTooltip()
this.option.series = []
this.thumbnailOption.series = []
this.option.xAxis.name = 'Channel'
this.option.yAxis.type = 'value'
if (this.option.series.length) {
this.option.series[0].type = 'line'
this.option.series[0].symbol = 'none'
this.option.series[0].markLine.lineStyle.width = 2
}
if (this.thumbnailOption.series.length) {
this.thumbnailOption.series[0].type = 'line'
this.thumbnailOption.series[0].symbol = 'none'
}
this.graphAssistance = cloneDeep(graphAssistance)
},
handleColorChange(colorConfig) {
// 如果还没加载完,加载新的
if (this.isLoading) {
this.getSampleDetail()
}
// 否则修改已有颜色
else {
this.changeColor(colorConfig)
}
},
// 修改颜色
changeColor(colorConfig) {
const { Color_Spec, Color_Peak, Color_Lc, Color_Base, Color_Scac, Color_Compare, Color_Strip, Color_Fitbase } =
colorConfig
this.shadowChannelChart.color = Color_Spec
this.shadowEnergyChart.color = Color_Spec
for (let i = 0; i < this.channelPeakGroup.length; i++) {
this.channelPeakGroup[i].color = Color_Peak
this.energyPeakGroup[i].color = Color_Peak
}
this.channelLcLine.color = Color_Lc
this.energyLcLine.color = Color_Lc
this.channelBaseLine.color = Color_Base
this.energyBaseLine.color = Color_Base
this.channelScacLine.color = Color_Scac
this.energyScacLine.color = Color_Scac
this.changeColorBySeriesName('Spectrum', Color_Spec)
this.changePeakLineColor(Color_Peak)
this.changeColorBySeriesName('LcLine', Color_Lc)
this.changeColorBySeriesName('BaseLine', Color_Base)
this.changeColorBySeriesName('ScacLine', Color_Scac)
const thumbnailChartSeries = findSeriesByName(this.thumbnailOption.series, 'Spectrum')
thumbnailChartSeries.itemStyle.color = Color_Spec
},
// 根据series名修改颜色
changeColorBySeriesName(seriesName, color) {
const series = findSeriesByName(this.option.series, seriesName)
series.itemStyle.color = color
},
// 改变Peak的颜色
changePeakLineColor(color) {
this.option.series
.filter((item) => item.name.includes('Peak_'))
.forEach((item) => {
item.itemStyle.color = color
})
},
isEnergy() {
return this.graphAssistance.axisType == 'Energy'
},
},
watch: {
sample: {
handler(newVal, oldVal) {
console.log('newValnewVal', newVal)
if (newVal.sampleId) {
this.getSampleDetail()
} else {
this.getSampleDetail_file()
}
},
immediate: true,
},
},
}
</script>
<style lang="less" scoped>
.gamma-analysis {
height: 100%;
.ant-spin-nested-loading {
height: 100%;
::v-deep {
.ant-spin-container {
height: 100%;
}
}
}
&-main {
height: calc(100% - 51px);
display: flex;
overflow: auto hidden;
position: relative;
}
&-chart {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
&-thumbnail {
position: absolute;
top: 50px;
right: 10px;
width: 500px;
height: 20%;
background-color: #153e44;
}
}
</style>
<style lang="less">
.peak-infomation-tooltip {
position: absolute;
border-style: solid;
white-space: nowrap;
z-index: 9;
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: #55a9fe;
border-color: #55a9fe;
}
</style>