NEZ-2064 feat : 通过d3js 实现 pie chart
This commit is contained in:
@@ -1,6 +1,20 @@
|
||||
<template>
|
||||
<div :ref="`chart-canvas-${chartId}`" style="height: 100%; width: 100%">
|
||||
<div :id="`chart-canvas-${chartId}`" class="chart__canvas chart-svg"></div>
|
||||
<div
|
||||
:class="legendPlacement"
|
||||
ref="pie-chart-box"
|
||||
class="nz-chart__component nz-chart__component--time-series">
|
||||
<div :ref="`chart-canvas-${chartId}`" style="height: 100%; width: 100%">
|
||||
<div style="height: 85%; width: 100%">
|
||||
<div :id="`chart-canvas-${chartId}`" class="chart__canvas chart-svg"></div>
|
||||
</div>
|
||||
<chart-legend
|
||||
v-if="hasLegend"
|
||||
:chart-data="chartData"
|
||||
:chart-info="chartInfo"
|
||||
:legends="dataset"
|
||||
:is-fullscreen="isFullscreen"
|
||||
@pieData="pieData"
|
||||
></chart-legend>
|
||||
<div
|
||||
:class="`chart-canvas-tooltip-${chartId}`"
|
||||
:id="`chart-canvas-tooltip-${chartId}`"
|
||||
@@ -27,6 +41,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -38,6 +53,8 @@ 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'
|
||||
import legend from '@/components/chart/chart/legend'
|
||||
import { chartLegendPlacement } from '@/components/common/js/constants'
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
@@ -65,6 +82,9 @@ export default {
|
||||
chartOption: Object,
|
||||
isFullscreen: Boolean
|
||||
},
|
||||
components: {
|
||||
chartLegend: legend
|
||||
},
|
||||
mounted () {
|
||||
this.colorList = initColor(20)
|
||||
this.initChart()
|
||||
@@ -82,7 +102,7 @@ export default {
|
||||
this.chartOption.series[0],
|
||||
this.chartData
|
||||
)[0].data
|
||||
this.drawArcPie()
|
||||
this.drawArcPie(this.dataset)
|
||||
}, 200)
|
||||
})
|
||||
},
|
||||
@@ -100,11 +120,15 @@ export default {
|
||||
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)
|
||||
const type = 'pie'
|
||||
const color = this.colorList[colorIndex]
|
||||
// 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,
|
||||
type: type,
|
||||
color: color,
|
||||
realValue: value,
|
||||
showValue: showValue,
|
||||
name: legend.name,
|
||||
@@ -128,7 +152,7 @@ export default {
|
||||
},
|
||||
|
||||
// 绘制饼图
|
||||
drawArcPie () {
|
||||
drawArcPie (data) {
|
||||
this.$nextTick(() => {
|
||||
d3.select(`#chart-canvas-${this.chartId}`).selectAll('svg').remove()// 清空作图区域
|
||||
// 重新赋值宽高
|
||||
@@ -139,7 +163,7 @@ export default {
|
||||
} catch (error) {
|
||||
}
|
||||
// 如果数据全为0 则设置默认值(否则图表不显示)
|
||||
let dataset = lodash.cloneDeep(this.dataset)
|
||||
let dataset = lodash.cloneDeep(data)
|
||||
if (dataset.every(item => item.value == 0)) {
|
||||
dataset = dataset.map(item => {
|
||||
return {
|
||||
@@ -159,7 +183,7 @@ export default {
|
||||
const pie = d3.pie().value(function (d) {
|
||||
return d.value
|
||||
})
|
||||
const piedata = pie(this.dataset)
|
||||
const piedata = pie(data)
|
||||
const arc = d3
|
||||
.arc()
|
||||
.innerRadius(this.innerRadius)
|
||||
@@ -184,34 +208,63 @@ export default {
|
||||
// 边界线
|
||||
// .attr('stroke', 'white')
|
||||
// 颜色
|
||||
.attr('fill', (d, i) => this.colorList[i])
|
||||
.attr('fill', (d, i) => {
|
||||
if (d.data.color) {
|
||||
return d.data.color
|
||||
} else {
|
||||
return this.colorList[i]
|
||||
}
|
||||
})
|
||||
|
||||
// 文字
|
||||
arcs
|
||||
.append('foreignObject')
|
||||
.attr('y', d => { // y轴居中减文字大小的一半
|
||||
const y = arc.centroid(d)[1]
|
||||
return y - Math.sqrt(2) / 2 * (this.outerRadius / 2) + Math.floor(this.outerRadius / 18)
|
||||
return y - Math.sqrt(2) / 2 * (this.outerRadius / 2) + Math.ceil(this.outerRadius / 16)
|
||||
})
|
||||
.attr('transform', (d, i) => {
|
||||
return 'translate(' + (arc.centroid(d)[0] - Math.abs(arc.centroid(d)[0]) - Math.floor(this.outerRadius / 18)) + ',' + (0) + ')' // x轴为最左侧 //x轴居中减文字大小的一半
|
||||
return 'translate(' + (arc.centroid(d)[0] - Math.abs(arc.centroid(d)[0]) - Math.ceil(this.outerRadius / 16)) + ',' + (0) + ')' // x轴为最左侧 //x轴居中减文字大小的一半
|
||||
})
|
||||
.style('font-size', () => {
|
||||
return Math.floor(this.outerRadius / 9)
|
||||
.style('font-size', (i) => {
|
||||
if (Math.ceil(this.outerRadius / 8) > 30) {
|
||||
return 30
|
||||
} else {
|
||||
return Math.ceil(this.outerRadius / 8)
|
||||
}
|
||||
})
|
||||
.attr('width', function (d, i) {
|
||||
.attr('width', (d, i) => {
|
||||
if ((d.endAngle - d.startAngle) < 0.25) {
|
||||
return 0
|
||||
} else {
|
||||
return Math.abs(arc.centroid(d)[0]) * 2
|
||||
}
|
||||
})
|
||||
.attr('height', function (d, i) {
|
||||
return Math.abs(arc.centroid(d)[1])
|
||||
.attr('height', (d, i) => {
|
||||
if (Math.ceil(this.outerRadius / 8) > 30) {
|
||||
return 90
|
||||
} else {
|
||||
return Math.ceil(this.outerRadius / 8) * 3
|
||||
}
|
||||
// return Math.abs(arc.centroid(d)[1]) - Math.ceil(this.outerRadius / 10)
|
||||
})
|
||||
// .attr('height', '20px')
|
||||
.style('line-height', '20px')
|
||||
.style('text-align', 'center')
|
||||
.style('padding-left', () => {
|
||||
if (this.isFullscreen) {
|
||||
return 20
|
||||
} else {
|
||||
return 5
|
||||
}
|
||||
})
|
||||
.style('padding-right', (d, i) => {
|
||||
const path = document.getElementsByClassName('path')[i]
|
||||
const w = path.getBoundingClientRect().width
|
||||
if (((d.endAngle - d.startAngle) < 0.25) || (Math.abs(arc.centroid(d)[0]) * 2 < w / 2)) {
|
||||
return 0
|
||||
} else {
|
||||
return (Math.abs(arc.centroid(d)[0]) * 2 - w / 3) / 2
|
||||
}
|
||||
})
|
||||
.style('line-height', '16px')
|
||||
.html((d) => {
|
||||
return this.drawText(d)
|
||||
})
|
||||
@@ -253,7 +306,7 @@ export default {
|
||||
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%;height: 100%;text-overflow: ellipsis;white-space: nowrap;overflow:hidden;text-align:center;display: flex;align-items: center;justify-content: center;">
|
||||
<p style="width: 100%;height: 100%;text-overflow: ellipsis;white-space: nowrap;overflow:hidden;text-align:center;line-height: 150%">
|
||||
<span>${str}</span>
|
||||
</p>
|
||||
<p style="width: 80%;height: 100%;text-overflow: ellipsis;white-space: nowrap;overflow:hidden;text-align:center;display: flex;align-items: center;justify-content: center;">
|
||||
@@ -264,14 +317,14 @@ export default {
|
||||
node.data.mapping.color &&
|
||||
node.data.mapping.color.icon
|
||||
};font-size:1em;"></i>
|
||||
<span style="color:#000">${valueStr}</span>
|
||||
<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%;height: 100%;text-overflow: ellipsis;white-space: nowrap;overflow:hidden;text-align:center;display: flex;align-items: center;justify-content: center;">
|
||||
<div style="color:#000;width:100%;height: 100%;display: flex;align-items: center;justify-content: center;flex-direction: column;cursor: pointer">
|
||||
<p style="width: 80%;height: 100%;text-overflow: ellipsis;white-space: nowrap;overflow:hidden;text-align:center;display: flex;align-items: center;justify-content: center;line-height: 150%">
|
||||
<i class="${
|
||||
node.data.mapping && node.data.mapping.icon
|
||||
}" style="color: ${
|
||||
@@ -279,14 +332,14 @@ export default {
|
||||
node.data.mapping.color &&
|
||||
node.data.mapping.color.icon
|
||||
};font-size:1em;"></i>
|
||||
<span style="color:#000">${str}</span>
|
||||
<span style="color:#000;text-overflow: ellipsis;white-space: nowrap;overflow:hidden;display:inline-block">${str}</span>
|
||||
</p>
|
||||
</div>
|
||||
`
|
||||
} else if (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%;height: 100%;text-overflow: ellipsis;white-space: nowrap;overflow:hidden;text-align:center;display: flex;align-items: center;justify-content: center;">
|
||||
<p style="width: 80%;height: 100%;text-overflow: ellipsis;white-space: nowrap;overflow:hidden;text-align:center;display: flex;align-items: center;justify-content: center;line-height: 150%">
|
||||
<i class="${
|
||||
node.data.mapping && node.data.mapping.icon
|
||||
}" style="color: ${
|
||||
@@ -294,7 +347,7 @@ export default {
|
||||
node.data.mapping.color &&
|
||||
node.data.mapping.color.icon
|
||||
};font-size:1em;"></i>
|
||||
<span style="color:#000">${valueStr}</span>
|
||||
<span style="color:#000;text-overflow: ellipsis;white-space: nowrap;overflow:hidden;display:inline-block">${valueStr}</span>
|
||||
</p>
|
||||
</div>
|
||||
`
|
||||
@@ -346,7 +399,7 @@ export default {
|
||||
},
|
||||
resize () {
|
||||
setTimeout(() => {
|
||||
this.drawArcPie()
|
||||
this.drawArcPie(this.dataset)
|
||||
}, 50)
|
||||
},
|
||||
clearCache () {
|
||||
@@ -356,10 +409,38 @@ export default {
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.clearCache()
|
||||
},
|
||||
hasLegend () {
|
||||
try {
|
||||
return [chartLegendPlacement.bottom, chartLegendPlacement.left, chartLegendPlacement.right].indexOf(this.chartInfo.param.legend.placement) > -1
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
},
|
||||
legendPlacement () {
|
||||
try {
|
||||
switch (this.chartInfo.param.legend.placement) {
|
||||
case 'left':
|
||||
case 'right':
|
||||
case 'bottom': {
|
||||
return `nz-chart__component--${this.chartInfo.param.legend.placement}`
|
||||
}
|
||||
default: return ''
|
||||
}
|
||||
} catch (e) {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
pieData (data) {
|
||||
this.drawArcPie(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style scoped>
|
||||
.legend-container{
|
||||
padding-left: 30px;
|
||||
}
|
||||
</style>>
|
||||
</style>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
:key="index"
|
||||
:class="{'row--inactive': isGrey[index]}"
|
||||
class="legend--table-row"
|
||||
@click="clickLegend(item.name, index)"
|
||||
@click="clickLegend(item.name, index,item)"
|
||||
>
|
||||
<div :title="item.alias ? item.alias : item.name" class="legend--table-cell">
|
||||
<span :style="{background: item.color}" class="legend-shape"></span>{{item.alias ? item.alias : item.name}}
|
||||
@@ -98,6 +98,10 @@ export default {
|
||||
this.clickLegendTreemap(legendName, index, hasGrey, curIsGrey, currentIsTheOnlyOneHighlight)
|
||||
return
|
||||
}
|
||||
if (this.chartInfo.type === 'pie') {
|
||||
this.clickLegendPie(legendName, index, hasGrey, curIsGrey, currentIsTheOnlyOneHighlight)
|
||||
return
|
||||
}
|
||||
|
||||
if (echarts) {
|
||||
// 判断timeSeries类型图表 先取消多表联动
|
||||
@@ -161,6 +165,17 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
clickLegendPie (legendName, index, hasGrey, curIsGrey, currentIsTheOnlyOneHighlight) {
|
||||
if (!hasGrey) { // 1.除当前legend外全置灰
|
||||
this.isGrey = this.isGrey.map((g, i) => i !== index)
|
||||
} else if (currentIsTheOnlyOneHighlight) { // 2.全高亮
|
||||
this.isGrey = this.isGrey.map(() => false)
|
||||
} else { // 对应高亮
|
||||
this.$set(this.isGrey, index, !this.isGrey[index])
|
||||
}
|
||||
const data = this.legends.filter((item, i) => !this.isGrey[i])
|
||||
this.$emit('pieData', data)
|
||||
},
|
||||
clickLegendBar (legendName, index, hasGrey, curIsGrey, currentIsTheOnlyOneHighlight) {
|
||||
const echarts = getChart(this.chartId)
|
||||
if (echarts) {
|
||||
|
||||
Reference in New Issue
Block a user