AnalysisSystemForRadionucli.../src/views/spectrumAnalysis/gamma-analysis.vue

1322 lines
38 KiB
Vue
Raw Normal View History

2023-06-28 19:25:11 +08:00
<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>
<a-popover
overlayClassName="popover-with-icon"
:visible="nuclideLibraryVisible"
@click="handleChangeNuclideVisible"
placement="bottom"
>
<div class="pop-over-with-icon">
<span class="text"> Nuclide Library </span>
<img src="@/assets/images/global/select-down.png" alt="" />
</div>
<a-spin slot="content" :spinning="isLoadingNuclide">
<nuclide-library :list="nuclideLibraryList" @dblclick="handleNuclideDblClick" />
</a-spin>
</a-popover>
<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:dblclick="handleChartDblClick"
@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>
<nuclide-review-modal
v-model="nuclideReview.visible"
:sampleId="sample.sampleId"
:channel="currChannel"
:nuclide="nuclideReview.nuclide"
/>
2023-06-28 19:25:11 +08:00
</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 NuclideLibrary from './components/SubOperators/NuclideLibrary.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'
import NuclideReviewModal from './components/Modals/AnalyzeInteractiveToolModal/components/NuclideReviewModal.vue'
2023-06-28 19:25:11 +08:00
// 初始配置
const initialOption = {
grid: {
top: 40,
left: 60,
right: 50,
containLabel: true,
2023-06-28 19:25:11 +08:00
},
title: {
text: '',
left: 'center',
bottom: 10,
textStyle: {
color: '#8FD4F8',
rich: {
a: {
padding: [0, 20, 0, 0],
fontSize: 16,
},
},
},
2023-06-28 19:25:11 +08:00
},
tooltip: {
trigger: 'axis',
axisPointer: {
lineStyle: {
color: '#3CAEBB',
width: 1,
type: 'solid',
},
},
formatter: undefined,
className: 'figure-chart-option-tooltip',
2023-06-28 19:25:11 +08:00
},
xAxis: {
name: 'Channel',
nameTextStyle: {
color: '#8FD4F8',
fontSize: 16,
align: 'right',
verticalAlign: 'top',
padding: [30, 0, 0, 0],
},
2023-06-28 19:25:11 +08:00
axisLine: {
lineStyle: {
color: '#ade6ee',
},
2023-06-28 19:25:11 +08:00
},
splitLine: {
show: false,
2023-06-28 19:25:11 +08:00
},
axisLabel: {
textStyle: {
color: '#ade6ee',
},
2023-06-28 19:25:11 +08:00
},
min: 1,
max: 'dataMax',
animation: false,
axisLabel: {
formatter: (value) => {
return parseInt(value)
},
},
2023-06-28 19:25:11 +08:00
},
yAxis: {
name: 'Counts',
type: 'value',
2023-06-28 19:25:11 +08:00
nameTextStyle: {
color: '#8FD4F8',
fontSize: 16,
2023-06-28 19:25:11 +08:00
},
axisLine: {
show: true,
lineStyle: {
color: '#ade6ee',
},
2023-06-28 19:25:11 +08:00
},
splitLine: {
show: true,
lineStyle: {
color: 'rgba(173, 230, 238, .2)',
},
2023-06-28 19:25:11 +08:00
},
axisLabel: {
textStyle: {
color: '#ade6ee',
},
},
min: 1,
max: 'dataMax',
animation: false,
axisLabel: {
formatter: (value) => {
return value.toFixed(1)
},
},
2023-06-28 19:25:11 +08:00
},
series: [],
brush: {},
2023-06-28 19:25:11 +08:00
}
// 缩略图配置
const thumbnailOption = {
grid: {
top: 0,
left: 5,
right: 5,
bottom: 0,
2023-06-28 19:25:11 +08:00
},
xAxis: {
type: 'category',
axisLine: {
show: false,
2023-06-28 19:25:11 +08:00
},
splitLine: {
show: false,
2023-06-28 19:25:11 +08:00
},
axisLabel: {
show: false,
},
min: 1,
max: 'dataMax',
2023-06-28 19:25:11 +08:00
},
yAxis: {
type: 'value',
2023-06-28 19:25:11 +08:00
axisLine: {
show: false,
2023-06-28 19:25:11 +08:00
},
splitLine: {
show: false,
2023-06-28 19:25:11 +08:00
},
axisLabel: {
show: false,
},
min: 1,
max: 'dataMax',
2023-06-28 19:25:11 +08:00
},
series: [],
2023-06-28 19:25:11 +08:00
}
const graphAssistance = {
axisType: 'Channel',
Baseline: true,
SCAC: true,
Lc: true,
2023-06-28 19:25:11 +08:00
}
export default {
props: {
sample: {
type: Object,
},
2023-06-28 19:25:11 +08:00
},
components: {
CustomChart,
PopOverWithIcon,
DetailedInfomation,
QcFlags,
GraphAssistance,
NuclideLibrary,
ButtonWithSwitchIcon,
NuclideReviewModal,
2023-06-28 19:25:11 +08:00
},
data() {
return {
isLoading: false,
isLoadingNuclide: false,
option: cloneDeep(initialOption),
opts: {
notMerge: false,
},
thumbnailOption: cloneDeep(thumbnailOption),
detailedInfomation: [],
qcFlags: [],
graphAssistance: cloneDeep(graphAssistance),
nuclideLibraryVisible: false,
channelPeakGroup: [],
energyPeakGroup: [],
nuclideLibraryList: [], // 当前鼠标点击选中的channel
peakInfomationTooltip: {
// Peak Infomation的位置
visible: false,
content: '',
top: 0,
left: 0,
},
nuclideReview: {
visible: false,
nuclide: '',
},
currChannel: -1,
2023-06-28 19:25:11 +08:00
}
},
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)
2023-06-28 19:25:11 +08:00
},
mounted() {
this.option.brush = { toolbox: [] }
},
2023-06-28 19:25:11 +08:00
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)
}
},
2023-09-11 11:01:23 +08:00
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)
}
},
2023-09-11 11:01:23 +08:00
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 }],
},
}
)
)
2023-09-11 11:01:23 +08:00
// 右上角缩略图推入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,
}
)
)
2023-09-11 11:01:23 +08:00
// 推入LcLine线
series.push(
buildLineSeries(
'LcLine',
channelLcLine.pointlist && channelLcLine.pointlist.map(({ x, y }) => [x, y]),
channelLcLine.color,
{
zlevel: 3,
}
)
)
2023-09-11 11:01:23 +08:00
// 推入Scac线
series.push(
buildLineSeries(
'ScacLine',
channelScacLine.pointlist && channelScacLine.pointlist.map(({ x, y }) => [x, y]),
channelScacLine.color,
{
zlevel: 4,
}
)
)
2023-09-11 11:01:23 +08:00
// 推入基线控制点
series.push({
name: 'BaseLine_Ctrl_Point',
type: 'scatter',
data: shapeChannelData.map(({ size, color, point: { x, y } }) => {
return {
value: [x, y],
2023-09-11 11:01:23 +08:00
itemStyle: {
color: 'transparent',
borderColor: color,
borderWidth: size / 2,
},
}
}),
emphasis: {
disabled: true,
},
animation: false,
zlevel: 5,
})
2023-09-11 11:01:23 +08:00
// 推入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
2023-09-11 11:01:23 +08:00
},
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
}
}
},
handleChangeNuclideVisible() {
this.nuclideLibraryVisible = !this.nuclideLibraryVisible
},
// 根据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)
}
},
// 双击还原
handleChartDblClick() {
this.handleReset()
},
// 获取 Nuclide Library 数据
async getSelPosNuclide(channel) {
this.currChannel = channel
try {
this.isLoadingNuclide = true
const { sampleId, inputFileName: fileName } = this.sample
const { success, result, message } = await getAction('/gamma/getSelPosNuclide', {
sampleId,
channel,
fileName,
})
if (success) {
const { possible } = result
this.nuclideLibraryList = possible
} else {
this.$message.error(message)
}
} catch (error) {
this.list = []
console.error(error)
} finally {
this.isLoadingNuclide = false
}
},
// Nuclide Library 单项双击
handleNuclideDblClick(nuclide) {
this.nuclideLibraryVisible = false
this.nuclideReview.nuclide = nuclide
this.nuclideReview.visible = true
},
2023-06-28 19:25:11 +08:00
resize() {
this.$refs.chartRef.resize()
this.$refs.thumbnailChartRef.resize()
this.closePeakInfomationTooltip()
2023-06-28 19:25:11 +08:00
},
// 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
},
2023-06-28 19:25:11 +08:00
/**
* 向某一个方向移动标记线
* @param { 'left'| 'right' } direction
*/
moveMarkLine(direction) {
const prevAxis = this.option.series[0].markLine.data[0].xAxis
2023-06-28 19:25:11 +08:00
// 获取每一段 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
})
let find = null
if (direction == 'right') {
// 找到第一个比prevAxis大的xAxis
find = maxXAxises.find((xAxis) => xAxis > prevAxis)
if (find) {
this.option.series[0].markLine.data[0].xAxis = find
}
} else if (direction == 'left') {
// 找到第一个比prevAxis小的xAxis
find = maxXAxises.reverse().find((xAxis) => xAxis < prevAxis)
if (find) {
this.option.series[0].markLine.data[0].xAxis = find
}
}
if (find) {
this.getSelPosNuclide(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 = []
2023-09-12 19:48:15 +08:00
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'
},
2023-06-28 19:25:11 +08:00
},
watch: {
sample: {
2023-09-11 11:01:23 +08:00
handler(newVal, oldVal) {
console.log('newValnewVal', newVal)
2023-09-11 11:01:23 +08:00
if (newVal.sampleId) {
this.getSampleDetail()
} else {
this.getSampleDetail_file()
}
},
immediate: true,
},
},
2023-06-28 19:25:11 +08:00
}
</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;
}
2023-06-28 19:25:11 +08:00
&-chart {
width: 100%;
2023-06-28 19:25:11 +08:00
height: 100%;
position: relative;
overflow: hidden;
2023-06-28 19:25:11 +08:00
}
&-thumbnail {
position: absolute;
top: 50px;
right: 10px;
width: 500px;
height: 20%;
background-color: #153e44;
2023-06-28 19:25:11 +08:00
}
}
</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>