feat: 完成2D图表矩形框功能,对接Result Display字段

This commit is contained in:
Xu Zhimeng 2023-07-21 16:50:56 +08:00
parent 728e557006
commit 145b61d9c0
2 changed files with 279 additions and 72 deletions

View File

@ -46,44 +46,9 @@ import CustomChart from '@/components/CustomChart/index.vue'
import Custom3DChart from '@/components/Custom3DChart/index.vue'
import ColorPalette from './ColorPalette.vue'
import { getXAxisAndYAxisByPosition } from '@/utils/chartHelper.js'
import * as echarts from 'echarts'
const buttons = ['2D', '3D Surface', '3D Scatter']
function renderItem(params, api) {
console.log('%c [ params, api ]-54', 'font-size:13px; background:pink; color:#bf2c9f;', params, api)
const categoryIndex = api.value(0)
console.log('%c [ categoryIndex ]-56', 'font-size:13px; background:pink; color:#bf2c9f;', categoryIndex)
const start = api.coord([api.value(1), categoryIndex])
console.log('%c [ start ]-58', 'font-size:13px; background:pink; color:#bf2c9f;', start)
const end = api.coord([api.value(2), categoryIndex])
console.log('%c [ end ]-60', 'font-size:13px; background:pink; color:#bf2c9f;', end)
const height = api.size([0, 1])[1] * 0.6
console.log('%c [ height ]-62', 'font-size:13px; background:pink; color:#bf2c9f;', height)
const rectShape = echarts.graphic.clipRectByRect(
{
x: start[0],
y: start[1] - height / 2,
width: end[0] - start[0],
height: height
},
{
x: params.coordSys.x,
y: params.coordSys.y,
width: params.coordSys.width,
height: params.coordSys.height
}
)
return (
rectShape && {
type: 'rect',
transition: ['shape'],
shape: rectShape,
style: api.style()
}
)
}
// 2D
const twoDOption = {
grid: {
@ -166,29 +131,26 @@ const twoDOption = {
max: 256,
interval: 64
},
series: [
{
type: 'scatter',
symbolSize: 5,
data: [],
itemStyle: {
color: '#fff'
}
series: {
type: 'scatter',
symbolSize: 5,
data: [],
itemStyle: {
color: '#fff'
},
{
type: 'custom',
renderItem: renderItem,
itemStyle: {
opacity: 0.8
},
encode: {
x: [1, 2],
y: 0
},
data: [[]]
markLine: {
silent: true,
symbol: 'none',
data: [],
animation: false,
lineStyle: {
type: 'solid',
width: 2
}
}
],
brush: {}
},
brush: {},
animation: false
}
//3D Surface
@ -379,7 +341,7 @@ export default {
handleChange(index) {
this.active = index
// v-showresize0, resize
// v-show(Unzoom)resize0, resize
if (this.active == 0) {
this.$nextTick(() => {
this.resize()
@ -395,6 +357,7 @@ export default {
this.twoDOption.yAxis.max = 256
this.emitRangeChange([0, 256, 0, 256])
this.reDrawRect()
},
resize() {
@ -457,19 +420,35 @@ export default {
const [x1, y2, x2, y1] = [...point1, ...point2] //
this.twoDOption.xAxis.min = x1
this.twoDOption.xAxis.max = x2
this.twoDOption.yAxis.min = y1
this.twoDOption.yAxis.max = y2
const rangeNumberFunc = this.rangeNumber(0, 256)
this.twoDOption.xAxis.min = rangeNumberFunc(x1)
this.twoDOption.xAxis.max = rangeNumberFunc(x2)
this.twoDOption.yAxis.min = rangeNumberFunc(y1)
this.twoDOption.yAxis.max = rangeNumberFunc(y2)
this.emitRangeChange([x1, x2, y1, y2])
this.reDrawRect()
}
this.clearBrush(chart)
},
/**
* 限定数字在一定范围
* @param {Number} min
* @param {Number} max
*/
rangeNumber(min, max) {
return num => {
return num > max ? max : num < min ? min : num
}
},
//
emitRangeChange(range) {
console.log('%c [ range ]-452', 'font-size:13px; background:pink; color:#bf2c9f;', range)
this.$emit('rangeChange', range)
},
@ -489,7 +468,232 @@ export default {
}
},
//
//
reDrawRect() {
const rectList = []
this.boundaryData.forEach(({ minX, maxX, minY, maxY, color }) => {
// rect
const rect = [
[minX, minY],
[maxX, minY],
[maxX, maxY],
[minX, maxY]
]
rectList.push(...this.drawOneRect(rect, color))
})
this.twoDOption.series.markLine.data = rectList
},
/**
* 绘制一个矩形框区域
* 矩形框在这里的实现是由几条线段围起来的但由于线段在超出图表区域显示有问题故作了以下处理
* @param {*} rect 左下 右下 右上 左上 的顺序
*/
drawOneRect(rect, color) {
const rectList = []
const {
xAxis: { min: minX, max: maxX },
yAxis: { min: minY, max: maxY }
} = this.twoDOption
const inchartPoints = this.getInChartPoints(rect)
const outchartPoints = rect.filter(pointItem => !inchartPoints.includes(pointItem))
//
if (inchartPoints.length == 2) {
const [point1, point2] = inchartPoints
const isVerticleLine = this.isVerticleLine(point1, point2)
// 线
if (isVerticleLine) {
const find = outchartPoints.find(outcharPoint => point1[1] == outcharPoint[1]) //
//
const isLeft = find[0] <= point1[0]
/**
* 如果在左边推入左边俩点构成矩形
* y
* |________________
* | |
* |________________|
* |
* | x
**/
if (isLeft) {
inchartPoints.forEach(point => {
rectList.push(this.generateLineDataByTwoPoints([minX, point[1]], point))
})
rectList.push(this.generateLineDataByTwoPoints(point1, point2))
}
//
else {
inchartPoints.forEach(point => {
rectList.push(this.generateLineDataByTwoPoints([maxX, point[1]], point))
})
rectList.push(this.generateLineDataByTwoPoints(point1, point2))
}
}
// 线
else {
const find = outchartPoints.find(outcharPoint => point1[0] == outcharPoint[0]) //
//
const isBottom = find[1] <= point1[1]
/**
* 如果在下边推入下边俩点构成矩形
**/
if (isBottom) {
inchartPoints.forEach(point => {
rectList.push(this.generateLineDataByTwoPoints([point[0], minY], point))
})
rectList.push(this.generateLineDataByTwoPoints(point1, point2))
}
//
else {
inchartPoints.forEach(point => {
rectList.push(this.generateLineDataByTwoPoints([point[0], maxY], point))
})
rectList.push(this.generateLineDataByTwoPoints(point1, point2))
}
}
}
//
else if (inchartPoints.length == 1) {
const point = inchartPoints[0]
const isLeft = !!outchartPoints.find(outPoint => outPoint[0] < point[0])
const isBottom = !!outchartPoints.find(outPoint => outPoint[1] < point[1])
//
if (isLeft && isBottom) {
rectList.push(this.generateLineDataByTwoPoints(point, [minX, point[1]]))
rectList.push(this.generateLineDataByTwoPoints(point, [point[0], minY]))
}
//
if (isLeft && !isBottom) {
rectList.push(this.generateLineDataByTwoPoints(point, [minX, point[1]]))
rectList.push(this.generateLineDataByTwoPoints(point, [point[0], maxY]))
}
//
if (!isLeft && !isBottom) {
rectList.push(this.generateLineDataByTwoPoints(point, [maxX, point[1]]))
rectList.push(this.generateLineDataByTwoPoints(point, [point[0], maxY]))
}
//
if (!isLeft && isBottom) {
rectList.push(this.generateLineDataByTwoPoints(point, [maxX, point[1]]))
rectList.push(this.generateLineDataByTwoPoints(point, [point[0], minY]))
}
}
//
else if (inchartPoints.length == 4) {
//
rect.forEach((point, index) => {
if (index == rect.length - 1) {
rectList.push(this.generateLineDataByTwoPoints(point, rect[0]))
} else {
rectList.push(this.generateLineDataByTwoPoints(point, rect[index + 1]))
}
})
}
//
else {
//
const xAxisList = rect.map(item => item[0]).filter(xAxis => xAxis > minX && xAxis < maxX)
const leftBottomPoint = rect[0]
const rightBottomPoint = rect[1]
const rightTopPoint = rect[3]
const minYAxis = rightBottomPoint[1]
const maYAxis = rightTopPoint[1]
// 线
if (xAxisList.length == 4 && minYAxis < minY && maYAxis > maxY) {
const minAxis = Math.min(...xAxisList)
const maxAxis = Math.max(...xAxisList)
rectList.push(this.generateLineDataByTwoPoints([minAxis, minY], [minAxis, maxY]))
rectList.push(this.generateLineDataByTwoPoints([maxAxis, minY], [maxAxis, maxY]))
}
// 线
else if (xAxisList.length == 2 && minYAxis < minY && maYAxis > maxY) {
const xAxis = xAxisList[0]
rectList.push(this.generateLineDataByTwoPoints([xAxis, minY], [xAxis, maxY]))
}
//
const yAxisList = rect.map(item => item[1]).filter(xAxis => xAxis > minY && xAxis < maxY)
const minXAxis = leftBottomPoint[0]
const maxXAxis = rightBottomPoint[0]
// 线
if (yAxisList.length == 4 && minXAxis < minX && maxXAxis > maxX) {
const minAxis = Math.min(...yAxisList)
const maxAxis = Math.max(...yAxisList)
rectList.push(this.generateLineDataByTwoPoints([minX, minAxis], [maxX, minAxis]))
rectList.push(this.generateLineDataByTwoPoints([minX, maxAxis], [maxX, maxAxis]))
}
// 线
else if (yAxisList.length == 2 && minXAxis < minX && maxXAxis > maxX) {
const yAxis = yAxisList[0]
rectList.push(this.generateLineDataByTwoPoints([minX, yAxis], [maxX, yAxis]))
}
}
//
rectList.forEach(item => {
item[0].lineStyle = {
color
}
})
return rectList
},
/**
* 获取在框选范围内的点列表
* @param { Array<Array<number>> } rectInfo
*/
getInChartPoints(rectInfo) {
const {
xAxis: { min: minX, max: maxX },
yAxis: { min: minY, max: maxY }
} = this.twoDOption
return rectInfo.filter(point => {
const [xAxis, yAxis] = point
return xAxis >= minX && xAxis <= maxX && yAxis >= minY && yAxis <= maxY
})
},
/**
* 根据俩点判断是横向还是纵向
* x坐标相同则是纵向否则横向
*/
isVerticleLine(point1, point2) {
return point1[0] == point2[0] ? true : false
},
/**
* 根据两个点生成一个markLine直线
*/
generateLineDataByTwoPoints(point1, point2) {
return [
{
xAxis: point1[0],
yAxis: point1[1]
},
{
xAxis: point2[0],
yAxis: point2[1]
}
]
},
//
getRandomColor() {
const r = Math.floor(Math.random() * 256) // 0 255
const g = Math.floor(Math.random() * 256)
const b = Math.floor(Math.random() * 256)
return `rgb(${r}, ${g}, ${b})`
},
//
interpolateColor(color1, color2, percentage) {
const r = color1.r + (color2.r - color1.r) * percentage
const g = color1.g + (color2.g - color1.g) * percentage
@ -502,7 +706,7 @@ export default {
histogramDataList: {
handler(newVal) {
this.active = 0
this.twoDOption.series[0].data = newVal.filter(item => item.c).map(item => [item.b, item.g, item.c]) // 2D Scatter
this.twoDOption.series.data = newVal.filter(item => item.c).map(item => [item.b, item.g, item.c]) // 2D Scatter
},
immediate: true
},
@ -525,8 +729,11 @@ export default {
// 2D
boundary: {
handler(newVal) {
console.log('%c [ ]-462', 'font-size:13px; background:pink; color:#bf2c9f;', newVal)
this.twoDOption.series[1].data = newVal.map(({ minX, minY, maxX, maxY }) => [minX, minY, maxX, maxY])
newVal.forEach(item => {
item.color = this.getRandomColor()
})
this.boundaryData = newVal
this.reDrawRect()
},
immediate: true
},
@ -540,9 +747,9 @@ export default {
val / this.maxCount
)
this.twoDOption.series[0].itemStyle.color = `rgb(${r}, ${g}, ${b})`
this.twoDOption.series.itemStyle.color = `rgb(${r}, ${g}, ${b})`
} else {
this.twoDOption.series[0].itemStyle.color = '#fff'
this.twoDOption.series.itemStyle.color = '#fff'
}
},
immediate: true

View File

@ -11,7 +11,7 @@
</template>
<template slot="uncertainty" slot-scope="text">
<div class="uncertainty color-box">
{{ text }}
+/-{{ text }}
</div>
</template>
<template slot="mdc" slot-scope="text">
@ -34,7 +34,7 @@
</template>
<template slot="uncertainty" slot-scope="text">
<div class="uncertainty color-box">
{{ text }}
+/-{{ text }}
</div>
</template>
<template slot="mdc" slot-scope="text">
@ -61,13 +61,13 @@ const columns = [
},
{
title: 'Isotope',
dataIndex: 'isotope',
dataIndex: 'nuclideName',
ellipsis: true,
width: 76
},
{
title: 'Concentration',
dataIndex: 'concentration',
dataIndex: 'conc',
scopedSlots: {
customRender: 'concentration'
},
@ -75,7 +75,7 @@ const columns = [
},
{
title: 'Uncertainty',
dataIndex: 'uncertainty',
dataIndex: 'concErr',
scopedSlots: {
customRender: 'uncertainty'
},