NEZ-2064 peaf : 通过d3js 实现 pie chart 未完成
This commit is contained in:
@@ -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,
|
||||
|
||||
360
nezha-fronted/src/components/chart/chart/chartPieD3.vue
Normal file
360
nezha-fronted/src/components/chart/chart/chartPieD3.vue
Normal 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>
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -420,6 +420,7 @@ export const chartType = {
|
||||
topology: 'topology',
|
||||
map: 'map',
|
||||
hexagon: 'hexagon',
|
||||
PieD3: 'pie',
|
||||
topologyLink: 'topologyLink'
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user