NEZ-2064 peaf : 通过d3js 实现 pie chart 未完成

This commit is contained in:
likexuan
2022-07-26 17:58:16 +08:00
parent 33694828f0
commit 5f17af2e88
4 changed files with 379 additions and 3 deletions

View File

@@ -17,7 +17,7 @@
:showAllData="showAllData"
@chartIsNoData="chartIsNoData"
></chart-time-series>
<chart-pie
<!-- <chart-pie
:ref="'chart' + chartInfo.id"
v-if="isChartPie(chartInfo.type)"
:chart-data="chartData"
@@ -25,7 +25,7 @@
:chart-option="chartOption"
:is-fullscreen="isFullscreen"
@chartIsNoData="chartIsNoData"
></chart-pie>
></chart-pie> -->
<chart-bubble
:ref="'chart' + chartInfo.id"
v-if="isChartBubble(chartInfo.type)"
@@ -53,6 +53,15 @@
:is-fullscreen="isFullscreen"
@chartIsNoData="chartIsNoData"
></chartHexagonD3>
<chartPieD3
:ref="'chart'+chartInfo.id"
v-if="isPieD3(chartInfo.type)"
:chart-data="chartData"
:chart-info="chartInfo"
:chart-option="chartOption"
:is-fullscreen="isFullscreen"
@chartIsNoData="chartIsNoData"
></chartPieD3>
<chart-url
:ref="'chart' + chartInfo.id"
v-if="isUrl(chartInfo.type)"
@@ -218,9 +227,10 @@ import chartTreemap from './chart/chartTreemap'
import chartUrl from './chart/chartUrl'
import chartValue from './chart/chartValue'
import chartHexagonD3 from './chart/chartHexagonD3'
import chartPieD3 from './chart/chartPieD3'
import chartMap from './chart/chartMap'
import chartTopology from './chart/chartTopology'
import { getOption, isTimeSeries, isHexagon, isUrl, isText, isChartPie, isChartBubble, isChartBar, isTreemap, isLog, isStat, isDiagram, isGroup, isAutotopology, isMap, isAssetInfo, isEndpointInfo, isTable, isGauge, isClock, isTopology } from './chart/tools'
import { getOption, isTimeSeries, isHexagon, isPieD3, isUrl, isText, isChartPie, isChartBubble, isChartBar, isTreemap, isLog, isStat, isDiagram, isGroup, isAutotopology, isMap, isAssetInfo, isEndpointInfo, isTable, isGauge, isClock, isTopology } from './chart/tools'
import lodash from 'lodash'
export default {
@@ -247,6 +257,7 @@ export default {
chartUrl,
chartValue,
chartHexagonD3,
chartPieD3,
chartMap,
chartTopology
},
@@ -305,6 +316,7 @@ export default {
methods: {
isTimeSeries,
isHexagon,
isPieD3,
isChartPie,
isChartBubble,
isChartBar,

View File

@@ -0,0 +1,360 @@
<template>
<div :ref="`chart-canvas-${chartId}`" style="height: 100%; width: 100%">
<div :id="`chart-canvas-${chartId}`" class="chart__canvas chart-svg"></div>
<div
:class="`chart-canvas-tooltip-${chartId}`"
:id="`chart-canvas-tooltip-${chartId}`"
class="chart-canvas-tooltip"
:style="{ left: tooltip.x + 'px', top: tooltip.y + 'px' }"
v-if="tooltip.show"
>
<div class="chart-canvas-tooltip-title tooltip-title">
{{ tooltip.title }}
</div>
<div class="chart-canvas-tooltip-content">
<div>value</div>
<div>
<div
v-if="tooltip.mapping && tooltip.mapping.icon"
style="display: inline-block"
>
<i
:class="tooltip.mapping.icon"
:style="{ color: tooltip.mapping.color.icon }"
></i>
</div>
<div style="display: inline-block">{{ tooltip.value }}</div>
</div>
</div>
</div>
</div>
</template>
<script>
import * as d3 from 'd3'
import lodash from 'lodash'
import chartMixin from '@/components/chart/chartMixin'
import chartDataFormat from '@/components/chart/chartDataFormat'
import { getMetricTypeValue } from '@/components/common/js/tools'
import { initColor } from '@/components/chart/chart/tools'
export default {
data () {
return {
timer: null,
pieTimer: null,
width: 330,
height: 300,
innerRadius: 0,
dataset: [],
colorList: [],
tooltip: {
x: 0,
y: 0,
title: 0,
value: 0,
mapping: {},
show: false
}
}
},
mixins: [chartMixin],
props: {
chartInfo: Object,
chartData: Array,
chartOption: Object,
isFullscreen: Boolean
},
mounted () {
this.colorList = initColor(20)
this.initChart()
},
methods: {
initChart () {
this.clearCache().then(() => {
if (this.timer) {
clearTimeout(this.timer)
this.timer = null
}
this.timer = setTimeout(() => {
this.dataset = this.initPieData(
this.chartInfo,
this.chartOption.series[0],
this.chartData
)[0].data
this.drawArcPie(this.dataset)
}, 200)
})
},
initPieData (chartInfo, seriesTemplate, originalDatas) {
let colorIndex = 0
const decimals = this.chartInfo.param.decimals || 2
const s = lodash.cloneDeep(seriesTemplate)
s.data = []
this.isNoData = true
originalDatas.forEach((originalData, expressionIndex) => {
originalData.forEach((data, dataIndex) => {
this.isNoData = false
if (s) {
const value = getMetricTypeValue(
data.values,
chartInfo.param.statistics
)
const showValue = chartDataFormat
.getUnit(chartInfo.unit ? chartInfo.unit : 2)
.compute(value, null, -1, decimals)
const mapping = this.selectMapping(
value,
chartInfo.param.valueMapping,
chartInfo.param.enable && this.chartInfo.param.enable.valueMapping
)
// eslint-disable-next-line vue/no-mutating-props
mapping &&
this.chartOption.color &&
(this.chartOption.color[colorIndex] = mapping.color.bac)
const legend = this.handleLegend(
chartInfo,
data,
expressionIndex,
dataIndex,
colorIndex
)
s.data.push({
value: value,
realValue: value,
showValue: showValue,
name: legend.name,
alias: legend.alias,
labels: data.metric,
seriesIndex: expressionIndex,
dataIndex: dataIndex,
mapping: mapping,
label: {
...s.label,
formatter: this.pieFormatterLabel,
color: mapping ? mapping.color.text : '#000000'
}
})
colorIndex++
}
})
})
this.$emit('chartIsNoData', this.isNoData)
return [s]
},
drawArcPie (dataset) {
// 半径
const outerRadius = Math.min(this.width, this.height) / 3
// 画布
const svg = d3
.select(`#chart-canvas-${this.chartId}`)
.append('svg')
.attr('width', this.width)
.attr('height', this.height)
// 绘圆
const pie = d3.pie().value(function (d) {
return d.value
})
const piedata = pie(dataset)
const arc = d3
.arc()
.innerRadius(this.innerRadius)
.outerRadius(outerRadius)
// 图形在画布中位置
const arcs = svg
.selectAll('g')
.data(piedata)
.enter()
.append('g')
.attr(
'transform',
'translate(' + this.width / 2 + ',' + (this.height / 2 + 20) + ')'
)
arcs
.append('path')
.attr('d', function (d) {
return arc(d)
})
// 边界线
// .attr('stroke', 'white')
// 颜色
.attr('fill', (d, i) => this.colorList[i])
// 文字
// arcs.append('foreignObject').html((d) => {
// return this.drawText(d)
// })
arcs.append('foreignObject')
// .attr('transform', function (d) {
// const x = arc.centroid(d)[0]
// const y = arc.centroid(d)[1]
// return 'translate(' + (this.width / 2 + x) + ',' + (this.heigh / 2 + y) + ')'
// })
// .attr('width', function () {
// return 50
// })
// .attr('height', function () {
// return 60
// })
.style('font-size', function () {
return 12
})
.html((d) => {
return this.drawText(d)
})
arcs.on('mouseenter', this.bubbleEnter)
arcs.on('mousemove', this.bubbleMove)
arcs.on('mouseleave', this.bubbleLeave)
},
// 处理文本
drawText (node) {
console.log(node, '90')
console.log(this.dataset, '100')
console.log(this.chartInfo.param.text)
let str = ''
let valueStr = ''
if (this.chartInfo.param.text === 'all') {
str += node.data.alias
valueStr =
node.data.mapping && node.data.mapping.display
? this.handleDisplay(node.data.mapping.display, {
...node.data.labels,
value: node.data.showValue
})
: node.data.showValue
}
if (this.chartInfo.param.text === 'value' || !this.chartInfo.param.text) {
valueStr =
node.data.mapping && node.data.mapping.display
? this.handleDisplay(node.data.mapping.display, {
...node.data.labels,
value: node.data.showValue
})
: node.data.showValue
}
if (this.chartInfo.param.text === 'legend') {
str += node.data.alias
}
if (this.chartInfo.param.text === 'none') {
str += ''
}
if (str && valueStr) {
return `
<div style="width:100%;height: 100%;display: flex;align-items: center;justify-content: center;flex-direction: column;cursor: pointer;">
<p style="width: 80%;text-overflow: ellipsis;white-space: nowrap;overflow:hidden;text-align:center">
<span>${str}</span>
</p>
<p style="width: 80%;text-overflow: ellipsis;white-space: nowrap;overflow:hidden;text-align:center">
<i class="${
node.data.mapping && node.data.mapping.icon
}" style="color: ${
node.data.mapping &&
node.data.mapping.color &&
node.data.mapping.color.icon
};font-size:1em;"></i>
<span>${valueStr}</span>
</p>
</div>
`
} else if (str) {
return `
<div style="width:100%;height: 100%;display: flex;align-items: center;justify-content: center;flex-direction: column;cursor: pointer;">
<p style="width: 80%;text-overflow: ellipsis;white-space: nowrap;overflow:hidden;text-align:center">
<i class="${
node.data.mapping && node.data.mapping.icon
}" style="color: ${
node.data.mapping &&
node.data.mapping.color &&
node.data.mapping.color.icon
};font-size:1em;"></i>
<span>${str}</span>
</p>
</div>
`
} else if (valueStr) {
console.log(valueStr, '89')
return `111111
<div style="width:100%;height: 100%;display: flex;align-items: center;justify-content: center;flex-direction: column;cursor: pointer;">
<p style="width: 80%;text-overflow: ellipsis;white-space: nowrap;overflow:hidden;text-align:center">
<i class="${
node.data.mapping && node.data.mapping.icon
}" style="color: ${
node.data.mapping &&
node.data.mapping.color &&
node.data.mapping.color.icon
};font-size:1em;"></i>
<span>${valueStr}</span>
</p>
</div>
`
}
},
bubbleEnter (e, node) {
// 移入六边形
this.tooltip.title = node.data.alias
this.tooltip.value = node.data.showValue
this.tooltip.mapping = node.data.mapping
this.tooltip.show = true
this.setPosition(e)
},
bubbleMove (e) {
// 六边形内移动
if (this.tooltip.show) {
this.setPosition(e)
}
},
bubbleLeave () {
this.tooltip.show = false
},
setPosition (e) {
const windowWidth = window.innerWidth // 窗口宽度
const windowHeight = window.innerHeight // 窗口高度
const box = document.getElementById(
`chart-canvas-tooltip-${this.chartId}`
)
if (box) {
const boxWidth = box.offsetWidth
const boxHeight = box.offsetHeight
if (e.pageX < windowWidth / 2) {
// 说明鼠标在左边放不下提示框
this.tooltip.x = e.pageX + 15
} else {
this.tooltip.x = e.pageX - boxWidth - 15
}
if (e.pageY + 50 + boxHeight < windowHeight) {
// 说明鼠标上面放不下提示框
this.tooltip.y = e.pageY + 15
} else {
this.tooltip.y = e.pageY - boxHeight - 10
}
} else {
this.tooltip.y = e.pageY + 15
this.tooltip.x = e.pageX + 15
}
},
clearCache () {
return new Promise((resolve) => {
resolve()
})
},
resize () {
if (this.pieTimer) {
clearTimeout(this.pieTimer)
this.pieTimer = null
}
this.pieTimer = setTimeout(() => {
this.getLayout()
.then((layout) => {
this.initPieData(layout)
})
.catch(() => {})
}, 50)
},
beforeDestroy () {
this.clearCache()
}
}
}
</script>
<style>
</style>

View File

@@ -65,6 +65,9 @@ export function isTimeSeries (type) {
export function isHexagon (type) {
return type === chartType.hexagon
}
export function isPieD3 (type) {
return type === chartType.PieD3
}
export function isChartPie (type) {
return type === chartType.pie
}

View File

@@ -420,6 +420,7 @@ export const chartType = {
topology: 'topology',
map: 'map',
hexagon: 'hexagon',
PieD3: 'pie',
topologyLink: 'topologyLink'
}