NEZ-2769 feat:dashboard增加 Rose chart(玫瑰图)图表类型

This commit is contained in:
zyh
2023-04-21 09:59:31 +08:00
parent 57469d2bcf
commit f0d369e98a
13 changed files with 477 additions and 31 deletions

View File

@@ -721,7 +721,6 @@
pointer-events: none !important; pointer-events: none !important;
} }
} }
.foreign{ .foreign{
overflow: visible; overflow: visible;
.foreign-label-wrap{ .foreign-label-wrap{
@@ -733,15 +732,13 @@
align-items: center; align-items: center;
} }
} }
.funnel-label{ .funnel-label{
cursor: pointer; cursor: pointer;
pointer-events: auto; pointer-events: auto;
line-height: 16px; line-height: 16px;
color: $--color-text-primary; color: $--color-text-primary;
} }
.doughnut-label,.rose-label{
.doughnut-label{
cursor: pointer; cursor: pointer;
pointer-events: auto; pointer-events: auto;
font-size: 12px; font-size: 12px;

View File

@@ -136,6 +136,7 @@ export default {
case 'gauge' : case 'gauge' :
case 'pie' : case 'pie' :
case 'doughnut' : case 'doughnut' :
case 'rose' :
case 'treemap' : case 'treemap' :
case 'log' : case 'log' :
case 'hexagon' : case 'hexagon' :

View File

@@ -36,6 +36,15 @@
:is-fullscreen="isFullscreen" :is-fullscreen="isFullscreen"
@chartIsNoData="chartIsNoData" @chartIsNoData="chartIsNoData"
></chart-doughnut> ></chart-doughnut>
<chart-rose
:ref="'chart' + chartInfo.id"
v-if="isRose(chartInfo.type)"
:chart-data="chartData"
:chart-info="chartInfo"
:chart-option="chartOption"
:is-fullscreen="isFullscreen"
@chartIsNoData="chartIsNoData"
></chart-rose>
<chart-bar <chart-bar
:ref="'chart' + chartInfo.id" :ref="'chart' + chartInfo.id"
v-if="isChartBar(chartInfo.type)" v-if="isChartBar(chartInfo.type)"
@@ -249,6 +258,7 @@ import chartLog from './chart/chartLog'
import chartNoData from './chart/chartNoData' import chartNoData from './chart/chartNoData'
import chartPie from './chart/chartPie' import chartPie from './chart/chartPie'
import chartDoughnut from './chart/chartDoughnut' import chartDoughnut from './chart/chartDoughnut'
import chartRose from './chart/chartRose'
import chartStat from './chart/chartStat' import chartStat from './chart/chartStat'
import chartTable from './chart/chartTable' import chartTable from './chart/chartTable'
import chartText from './chart/chartText' import chartText from './chart/chartText'
@@ -263,7 +273,7 @@ import chartBubble from './chart/chartBubble'
import chartRank from './chart/chartRank' import chartRank from './chart/chartRank'
import chartSankey from './chart/chartSankey' import chartSankey from './chart/chartSankey'
import chartFunnel from './chart/chartFunnelNew' import chartFunnel from './chart/chartFunnelNew'
import { getOption, isTimeSeries, isHexagon, isUrl, isText, isChartPie, isDoughnut, isChartBar, isTreemap, isLog, isStat, isDiagram, isGroup, isAutotopology, isMap, isAssetInfo, isEndpointInfo, isTable, isGauge, isClock, isTopology, isChartBubble, isChartRank, isSankey, isFunnel } from './chart/tools' import { getOption, isTimeSeries, isHexagon, isUrl, isText, isChartPie, isDoughnut, isRose, isChartBar, isTreemap, isLog, isStat, isDiagram, isGroup, isAutotopology, isMap, isAssetInfo, isEndpointInfo, isTable, isGauge, isClock, isTopology, isChartBubble, isChartRank, isSankey, isFunnel } from './chart/tools'
import lodash from 'lodash' import lodash from 'lodash'
export default { export default {
@@ -282,6 +292,7 @@ export default {
chartNoData, chartNoData,
chartPie, chartPie,
chartDoughnut, chartDoughnut,
chartRose,
chartStat, chartStat,
chartTable, chartTable,
chartText, chartText,
@@ -354,6 +365,7 @@ export default {
isHexagon, isHexagon,
isChartPie, isChartPie,
isDoughnut, isDoughnut,
isRose,
isChartBar, isChartBar,
isUrl, isUrl,
isText, isText,

View File

@@ -2,16 +2,16 @@
<div <div
:class="legendPlacement" :class="legendPlacement"
ref="doughnut-chart-box" ref="doughnut-chart-box"
class="nz-chart__component nz-chart__component--time-series" class="nz-chart__component"
> >
<div :id="`chart-canvas-${chartId}`" class="chart__canvas"></div> <div :id="`chart-canvas-${chartId}`" class="chart__canvas" style="overflow: hidden;"></div>
<chart-legend <chart-legend
v-if="hasLegend" v-if="hasLegend"
:chart-data="chartData" :chart-data="chartData"
:chart-info="chartInfo" :chart-info="chartInfo"
:legends="legends" :legends="legends"
:is-fullscreen="isFullscreen" :is-fullscreen="isFullscreen"
@clickLegendDoughnut="clickLegendDoughnut" @clickLegendD3="clickLegendD3"
></chart-legend> ></chart-legend>
<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-${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"> <div class="chart-canvas-tooltip-title tooltip-title">
@@ -120,7 +120,7 @@ export default {
const mapping = this.selectMapping(value, chartInfo.param.valueMapping, chartInfo.param.enable && this.chartInfo.param.enable.valueMapping) const mapping = this.selectMapping(value, chartInfo.param.valueMapping, chartInfo.param.enable && this.chartInfo.param.enable.valueMapping)
const legend = this.handleLegend(chartInfo, data, expressionIndex, dataIndex, colorIndex) const legend = this.handleLegend(chartInfo, data, expressionIndex, dataIndex, colorIndex)
this.doughnutData.push({ this.doughnutData.push({
value: value, value: Number(value),
realValue: value, realValue: value,
showValue: showValue, showValue: showValue,
name: legend.name, name: legend.name,
@@ -141,7 +141,6 @@ export default {
this.$emit('chartIsNoData', this.isNoData) this.$emit('chartIsNoData', this.isNoData)
}, },
drawDoughnutChart (animate) { drawDoughnutChart (animate) {
this.dispose()
const svgDom = document.getElementById(`chart-canvas-${this.chartId}`) const svgDom = document.getElementById(`chart-canvas-${this.chartId}`)
if (!svgDom) { if (!svgDom) {
return false return false
@@ -160,8 +159,17 @@ export default {
const width = svgDom.getBoundingClientRect().width const width = svgDom.getBoundingClientRect().width
const height = svgDom.getBoundingClientRect().height const height = svgDom.getBoundingClientRect().height
this.svg = d3.select(`#chart-canvas-${this.chartId}`).append('svg').attr('height', height).attr('width', width).attr('viewBox', [-width / 2, -height / 2, width, height]).style('display', 'block') let chart
const chart = this.svg.append('g') if (this.svg) {
chart = this.svg.select('g')
} else {
this.svg = d3.select(`#chart-canvas-${this.chartId}`).append('svg').style('display', 'block')
chart = this.svg.append('g')
}
this.svg
.attr('width', width)
.attr('height', height)
.attr('viewBox', [-width / 2, -height / 2, width, height])
const outerRadius = (Math.min(width, height) / 2) * 0.6 // outer radius of pie, in pixels const outerRadius = (Math.min(width, height) / 2) * 0.6 // outer radius of pie, in pixels
const innerRadius = outerRadius * 0.67 // inner radius of pie, in pixels (non-zero for donut) const innerRadius = outerRadius * 0.67 // inner radius of pie, in pixels (non-zero for donut)
@@ -174,15 +182,15 @@ export default {
const arcs = pie(doughnutData) const arcs = pie(doughnutData)
function doughnutOver (e, d) { function doughnutOver (e, d) {
d3.select(chart.selectAll('path').nodes()[d.index]) chart.select('.path-' + d.index)
.transition() .transition()
.attr('d', d3.arc() .attr('d', d3.arc()
.innerRadius(innerRadius) .innerRadius(innerRadius)
.outerRadius(outerRadius * 1.05) .outerRadius(outerRadius * 1.06)
) )
} }
function doughnutOut (e, d) { function doughnutOut (e, d) {
d3.select(chart.selectAll('path').nodes()[d.index]) chart.select('.path-' + d.index)
.transition() .transition()
.attr('d', d3.arc() .attr('d', d3.arc()
.innerRadius(innerRadius) .innerRadius(innerRadius)
@@ -190,28 +198,30 @@ export default {
) )
} }
const that = this
// 图形 // 图形
chart.selectAll('path') chart.selectAll('path')
.data(arcs) .data(arcs.filter(function (d) {
return d.data.value
}))
.join('path') .join('path')
.attr('fill', d => d.data.background) .attr('fill', d => d.data.background)
.attr('d', arc) .attr('d', arc)
.attr('class', (d) => 'path-' + d.index)
.style('cursor', 'pointer') .style('cursor', 'pointer')
.classed('no-events', true) .classed('no-events', true)
.on('mouseover', doughnutOver) .on('mouseover', doughnutOver)
.on('mouseout', doughnutOut) .on('mouseout', doughnutOut)
.on('mouseenter', that.doughnutEnter) .on('mouseenter', this.doughnutEnter)
.on('mousemove', that.doughnutMove) .on('mousemove', this.doughnutMove)
.on('mouseleave', that.doughnutLeave) .on('mouseleave', this.doughnutLeave)
.transition().duration(animate === true ? 600 : 0) .transition().duration(animate === true ? 600 : 0)
.attrTween('d', (d) => { .attrTween('d', function (d) {
let currentArc = this._current let currentArc = this._current
if (!currentArc) { if (!currentArc) {
currentArc = { startAngle: 0, endAngle: 0 } currentArc = { startAngle: 0, endAngle: 0 }
} }
const i = d3.interpolate(currentArc, d) const i = d3.interpolate(currentArc, d)
this._current = i(0) // 当饼图更新时,从当前角度过渡到新角度 this._current = i(1) // 当饼图更新时,从当前角度过渡到新角度
return function (t) { return function (t) {
return arc(i(t)) return arc(i(t))
} }
@@ -243,6 +253,7 @@ export default {
d3.select(this).classed('no-events', false) d3.select(this).classed('no-events', false)
}) })
}, },
// 处理label // 处理label
formatterLabel ({ data }) { formatterLabel ({ data }) {
let str = '' let str = ''
@@ -327,7 +338,7 @@ export default {
this.tooltip.x = e.pageX + 15 this.tooltip.x = e.pageX + 15
} }
}, },
clickLegendDoughnut (isGrey) { clickLegendD3 (isGrey) {
const data = this.doughnutData.filter((item, i) => !isGrey[i]) const data = this.doughnutData.filter((item, i) => !isGrey[i])
this.selectData = this.$loadsh.cloneDeep(data) this.selectData = this.$loadsh.cloneDeep(data)
this.drawDoughnutChart(true) this.drawDoughnutChart(true)

View File

@@ -2,7 +2,7 @@
<div <div
:class="legendPlacement" :class="legendPlacement"
ref="pie-chart-box" ref="pie-chart-box"
class="nz-chart__component nz-chart__component--time-series" @mouseenter="mouseEnterChart" class="nz-chart__component" @mouseenter="mouseEnterChart"
@mouseleave="mouseLeaveChart" @mouseleave="mouseLeaveChart"
> >
<div :id="`chart-canvas-${chartId}`" class="chart__canvas"></div> <div :id="`chart-canvas-${chartId}`" class="chart__canvas"></div>

View File

@@ -0,0 +1,395 @@
<template>
<div
:class="legendPlacement"
ref="rose-chart-box"
class="nz-chart__component"
>
<div :id="`chart-canvas-${chartId}`" class="chart__canvas" style="overflow: hidden;"></div>
<chart-legend
v-if="hasLegend"
:chart-data="chartData"
:chart-info="chartInfo"
:legends="legends"
:is-fullscreen="isFullscreen"
@clickLegendD3="clickLegendD3"
></chart-legend>
<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 chartFormat from '@/components/chart/chartFormat'
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 {
name: 'chart-rose',
components: {
chartLegend: legend
},
mixins: [chartMixin, chartFormat],
props: {
chartInfo: Object,
chartData: Array,
chartOption: Object,
isFullscreen: Boolean
},
computed: {
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 ''
}
}
},
data () {
return {
colorList: [],
isInit: true, // 是否是初始化初始化时为true图表初始化结束后设为false
chartId: '',
roseData: [],
selectData: [],
tooltip: {
x: 0,
y: 0,
title: 0,
value: 0,
mapping: {},
show: false
},
svg: null
}
},
methods: {
initChart (animate) {
this.legends = []
this.initRoseData(this.chartInfo, this.chartData)
this.selectData = this.$loadsh.cloneDeep(this.roseData)
if (this.isNoData) {
return
}
/* 使用setTimeout延迟渲染图表避免样式错乱 */
setTimeout(() => {
this.drawRoseChart(animate)
this.isInit = false
}, 200)
},
initRoseData (chartInfo, originalDatas) {
this.roseData = []
let colorIndex = 0
const decimals = this.chartInfo.param.decimals || 2
this.isNoData = true
originalDatas.forEach((originalData, expressionIndex) => {
originalData.forEach((data, dataIndex) => {
this.isNoData = false
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 legend = this.handleLegend(chartInfo, data, expressionIndex, dataIndex, colorIndex)
this.roseData.push({
value: Number(value),
realValue: value,
showValue: showValue,
name: legend.name,
alias: legend.alias,
labels: {
...data.metric,
legend: legend.alias
},
seriesIndex: expressionIndex,
dataIndex: dataIndex,
mapping: mapping,
background: mapping ? mapping.color.bac : this.colorList[colorIndex]
})
colorIndex++
})
})
this.$emit('chartIsNoData', this.isNoData)
},
drawRoseChart (animate) {
const svgDom = document.getElementById(`chart-canvas-${this.chartId}`)
if (!svgDom) {
return false
}
// 如果数据全为0 则设置默认值(否则图表不显示)
let roseData = lodash.cloneDeep(this.selectData)
if (roseData.every(item => item.value == 0)) {
roseData = roseData.map(item => {
return {
...item,
value: 100
}
})
}
const width = svgDom.getBoundingClientRect().width
const height = svgDom.getBoundingClientRect().height
let chart
if (this.svg) {
chart = this.svg.select('g')
} else {
this.svg = d3.select(`#chart-canvas-${this.chartId}`).append('svg').style('display', 'block')
chart = this.svg.append('g')
}
this.svg.attr('width', width)
.attr('height', height)
.attr('viewBox', [-width / 2, -height / 2, width, height])
const outerRadius = (Math.min(width, height) / 2) * 0.6 // outer radius of pie, in pixels
const innerRadius = 20 // inner radius of pie, in pixels (non-zero for donut)
const padAngle = 0 // angular separation between wedges
const radius = 4
const scale = d3.scaleRadial()
.domain([0, d3.max(roseData, d => d.value)])
.range([innerRadius, outerRadius])
const arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(d => {
return scale(d.data.value)
})
.cornerRadius(radius)
const pie = d3.pie()
.padAngle(padAngle)
.sort((a, b) => b.value - a.value)
.value(d => d.value)
const arcs = pie(roseData)
function roseOver (e, d) {
chart.select('.path-' + d.index)
.transition()
.attr('d', d3.arc()
.innerRadius(innerRadius)
.outerRadius(d => {
return scale(d.data.value) * 1.06
})
.cornerRadius(radius)
)
}
function roseOut (e, d) {
chart.select('.path-' + d.index)
.transition()
.attr('d', d3.arc()
.innerRadius(innerRadius)
.outerRadius(d => scale(d.data.value))
.cornerRadius(radius)
)
}
// 图形
chart.selectAll('path')
.data(arcs.filter(function (d) {
return d.data.value
}))
.join('path')
.attr('fill', d => d.data.background)
.attr('d', arc)
.attr('class', (d) => 'path-' + d.index)
.style('cursor', 'pointer')
.classed('no-events', true)
.on('mouseover', roseOver)
.on('mouseout', roseOut)
.on('mouseenter', this.roseEnter)
.on('mousemove', this.roseMove)
.on('mouseleave', this.roseLeave)
.transition().duration(animate === true ? 600 : 0)
.attrTween('d', function (d) {
let currentArc = this._current
if (!currentArc) {
currentArc = { startAngle: 0, endAngle: 0 }
}
const i = d3.interpolate(currentArc, d)
this._current = i(1) // 当饼图更新时,从当前角度过渡到新角度
const arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(scale(d.value))
.cornerRadius(radius)
return function (t) {
return arc(i(t))
}
})
.on('end', function () {
d3.select(this).classed('no-events', false)
})
// 文本
chart
.selectAll('foreignObject')
.data(arcs)
.join('foreignObject')
.attr('transform', d => `translate(${arc.centroid(d)})`)
.attr('class', 'foreign')
.classed('no-events', true)
.on('mouseover', roseOver)
.on('mouseout', roseOut)
.on('mouseenter', this.roseEnter)
.on('mousemove', this.roseMove)
.on('mouseleave', this.roseLeave)
.style('opacity', 0)
.html((d) => {
return d.endAngle - d.startAngle > 0.25 ? this.formatterLabel(d) : ''
})
.transition('opacity').duration(animate === true ? 600 : 0)
.style('opacity', 1)
.on('end', function () {
d3.select(this).classed('no-events', false)
})
},
// 处理label
formatterLabel ({ data }) {
let str = ''
let valueStr = ''
if (this.chartInfo.param.text === 'all') {
str += data.alias
valueStr = data.mapping && data.mapping.display ? this.handleDisplay(data.mapping.display, { ...data.labels, value: data.showValue }) : data.showValue
}
if (this.chartInfo.param.text === 'value' || !this.chartInfo.param.text) {
valueStr = data.mapping && data.mapping.display ? this.handleDisplay(data.mapping.display, { ...data.labels, value: data.showValue }) : data.showValue
}
if (this.chartInfo.param.text === 'legend') {
str += data.alias
}
if (this.chartInfo.param.text === 'none') {
str += ''
}
if (str && valueStr) {
return `<div class="foreign-label-wrap">
<p class="rose-label" style="color: ${data.mapping && data.mapping.color && data.mapping.color.text};">
<span>${str}</span>
</p>
<p class="rose-label" style="color: ${data.mapping && data.mapping.color && data.mapping.color.text};">
<i class="${data.mapping && data.mapping.icon}" style="color: ${data.mapping && data.mapping.color && data.mapping.color.icon};font-size:1em;"></i>
<span>${valueStr}</span>
</p>
</div>
`
} else if (str) {
return `<div class="foreign-label-wrap">
<p class="rose-label" style="color: ${data.mapping && data.mapping.color && data.mapping.color.text};">
<i class="${data.mapping && data.mapping.icon}" style="color: ${data.mapping && data.mapping.color && data.mapping.color.icon};font-size:1em;"></i>
<span>${str}</span>
</p>
</div>
`
} else if (valueStr) {
return `<div class="foreign-label-wrap">
<p class="rose-label" style="color: ${data.mapping && data.mapping.color && data.mapping.color.text};">
<i class="${data.mapping && data.mapping.icon}" style="color: ${data.mapping && data.mapping.color && data.mapping.color.icon};font-size:1em;"></i>
<span>${valueStr}</span>
</p>
</div>
`
}
},
roseEnter (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)
},
roseMove (e) { // 气泡内移动
if (this.tooltip.show) {
this.tooltip.show = true
this.setPosition(e)
}
},
roseLeave () { // 移出气泡
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
}
},
clickLegendD3 (isGrey) {
const data = this.roseData.filter((item, i) => !isGrey[i])
this.selectData = this.$loadsh.cloneDeep(data)
this.drawRoseChart(true)
},
resize () {
setTimeout(() => {
this.drawRoseChart(false)
}, 50)
},
dispose () {
if (this.svg) {
this.svg.selectAll('path').on('mouseover', null)
this.svg.selectAll('path').on('mouseout', null)
this.svg.selectAll('path').on('mouseenter', null)
this.svg.selectAll('path').on('mousemove', null)
this.svg.selectAll('path').on('mouseleave', null)
this.svg.selectAll('foreignObject').on('mouseover', null)
this.svg.selectAll('foreignObject').on('mouseout', null)
this.svg.selectAll('foreignObject').on('mouseenter', null)
this.svg.selectAll('foreignObject').on('mousemove', null)
this.svg.selectAll('foreignObject').on('mouseleave', null)
this.svg.remove()
this.svg = null
}
}
},
mounted () {
this.colorList = initColor(20)
this.chartInfo.loaded && this.initChart(true)
},
beforeDestroy () {
this.dispose()
}
}
</script>

View File

@@ -139,8 +139,8 @@ export default {
this.clickLegendTreemap(legendName, index, hasGrey, curIsGrey, currentIsTheOnlyOneHighlight) this.clickLegendTreemap(legendName, index, hasGrey, curIsGrey, currentIsTheOnlyOneHighlight)
return return
} }
if (this.chartInfo.type === 'doughnut') { if (this.chartInfo.type === 'doughnut' || this.chartInfo.type === 'rose') {
this.clickLegendDoughnut(legendName, index, hasGrey, curIsGrey, currentIsTheOnlyOneHighlight) this.clickLegendD3(legendName, index, hasGrey, curIsGrey, currentIsTheOnlyOneHighlight)
return return
} }
@@ -232,7 +232,7 @@ export default {
}) })
} }
}, },
clickLegendDoughnut (legendName, index, hasGrey, curIsGrey, currentIsTheOnlyOneHighlight) { clickLegendD3 (legendName, index, hasGrey, curIsGrey, currentIsTheOnlyOneHighlight) {
if (!hasGrey) { // 1.除当前legend外全置灰 if (!hasGrey) { // 1.除当前legend外全置灰
this.isGrey = this.isGrey.map((g, i) => i !== index) this.isGrey = this.isGrey.map((g, i) => i !== index)
} else if (currentIsTheOnlyOneHighlight) { // 2.全高亮 } else if (currentIsTheOnlyOneHighlight) { // 2.全高亮
@@ -240,7 +240,7 @@ export default {
} else { // 对应高亮 } else { // 对应高亮
this.$set(this.isGrey, index, !this.isGrey[index]) this.$set(this.isGrey, index, !this.isGrey[index])
} }
this.$emit('clickLegendDoughnut', this.isGrey) this.$emit('clickLegendD3', this.isGrey)
}, },
// 四舍五入保留2位小数不够位数则用0替补 // 四舍五入保留2位小数不够位数则用0替补
keepTwoDecimalFull (num) { keepTwoDecimalFull (num) {

View File

@@ -76,6 +76,9 @@ export function isChartPie (type) {
export function isDoughnut (type) { export function isDoughnut (type) {
return type === chartType.doughnut return type === chartType.doughnut
} }
export function isRose (type) {
return type === chartType.rose
}
export function isChartBar (type) { export function isChartBar (type) {
return type === chartType.bar return type === chartType.bar
} }

View File

@@ -289,6 +289,10 @@ export const chart = {
value: 'doughnut', value: 'doughnut',
label: i18n.t('dashboard.dashboard.chartForm.typeVal.doughnut.label') label: i18n.t('dashboard.dashboard.chartForm.typeVal.doughnut.label')
}, },
{
value: 'rose',
label: i18n.t('dashboard.dashboard.chartForm.typeVal.rose.label')
},
{ {
value: 'table', value: 'table',
label: i18n.t('dashboard.dashboard.chartForm.typeVal.table.label') label: i18n.t('dashboard.dashboard.chartForm.typeVal.table.label')
@@ -475,6 +479,7 @@ export const chartType = {
gauge: 'gauge', gauge: 'gauge',
pie: 'pie', pie: 'pie',
doughnut: 'doughnut', doughnut: 'doughnut',
rose: 'rose',
treemap: 'treemap', treemap: 'treemap',
log: 'log', log: 'log',
text: 'text', text: 'text',

View File

@@ -1272,7 +1272,8 @@ export default {
case 'treemap': case 'treemap':
case 'pie': case 'pie':
case 'doughnut': case 'doughnut':
if (this.oldType === 'bar' || this.oldType === 'treemap' || this.oldType === 'pie' || this.oldType === 'doughnut') { case 'rose':
if (this.oldType === 'bar' || this.oldType === 'treemap' || this.oldType === 'pie' || this.oldType === 'doughnut' || this.oldType === 'rose') {
break break
} }
this.chartConfig.param = { this.chartConfig.param = {

View File

@@ -56,6 +56,7 @@ export default {
case 'gauge': case 'gauge':
case 'pie': case 'pie':
case 'doughnut': case 'doughnut':
case 'rose':
return false return false
default: return false default: return false
} }
@@ -74,6 +75,7 @@ export default {
case 'gauge': case 'gauge':
case 'pie': case 'pie':
case 'doughnut': case 'doughnut':
case 'rose':
case 'bubble': case 'bubble':
case 'rank': case 'rank':
case 'sankey': case 'sankey':
@@ -90,6 +92,7 @@ export default {
case 'treemap': case 'treemap':
case 'pie': case 'pie':
case 'doughnut': case 'doughnut':
case 'rose':
case 'bar': case 'bar':
return true return true
case 'table': case 'table':
@@ -113,6 +116,7 @@ export default {
case 'treemap': case 'treemap':
case 'pie': case 'pie':
case 'doughnut': case 'doughnut':
case 'rose':
case 'bar': case 'bar':
return false return false
default: return false default: return false
@@ -141,6 +145,7 @@ export default {
case 'treemap': case 'treemap':
case 'pie': case 'pie':
case 'doughnut': case 'doughnut':
case 'rose':
case 'bubble': case 'bubble':
case 'rank': case 'rank':
case 'sankey': case 'sankey':
@@ -156,6 +161,7 @@ export default {
case 'treemap': case 'treemap':
case 'pie': case 'pie':
case 'doughnut': case 'doughnut':
case 'rose':
case 'stat': case 'stat':
case 'hexagon': case 'hexagon':
case 'gauge': case 'gauge':
@@ -174,6 +180,7 @@ export default {
case 'treemap': case 'treemap':
case 'pie': case 'pie':
case 'doughnut': case 'doughnut':
case 'rose':
case 'stat': case 'stat':
case 'hexagon': case 'hexagon':
case 'gauge': case 'gauge':
@@ -210,6 +217,7 @@ export default {
case 'treemap': case 'treemap':
case 'pie': case 'pie':
case 'doughnut': case 'doughnut':
case 'rose':
case 'stat': case 'stat':
case 'hexagon': case 'hexagon':
case 'gauge': case 'gauge':

View File

@@ -251,6 +251,10 @@ export default {
id: 'doughnut', id: 'doughnut',
name: this.$t('dashboard.dashboard.chartForm.typeVal.doughnut.label') name: this.$t('dashboard.dashboard.chartForm.typeVal.doughnut.label')
}, },
{
id: 'rose',
name: this.$t('dashboard.dashboard.chartForm.typeVal.rose.label')
},
{ {
id: 'bubble', id: 'bubble',
name: this.$t('dashboard.dashboard.chartForm.typeVal.bubble.label') name: this.$t('dashboard.dashboard.chartForm.typeVal.bubble.label')
@@ -314,6 +318,10 @@ export default {
id: 'doughnut', id: 'doughnut',
name: this.$t('dashboard.dashboard.chartForm.typeVal.doughnut.label') name: this.$t('dashboard.dashboard.chartForm.typeVal.doughnut.label')
}, },
{
id: 'rose',
name: this.$t('dashboard.dashboard.chartForm.typeVal.rose.label')
},
{ {
id: 'bubble', id: 'bubble',
name: this.$t('dashboard.dashboard.chartForm.typeVal.bubble.label') name: this.$t('dashboard.dashboard.chartForm.typeVal.bubble.label')

View File

@@ -894,6 +894,10 @@ export default {
id: 'doughnut', id: 'doughnut',
name: this.$t('dashboard.dashboard.chartForm.typeVal.doughnut.label') name: this.$t('dashboard.dashboard.chartForm.typeVal.doughnut.label')
}, },
{
id: 'rose',
name: this.$t('dashboard.dashboard.chartForm.typeVal.rose.label')
},
{ {
id: 'bubble', id: 'bubble',
name: this.$t('dashboard.dashboard.chartForm.typeVal.bubble.label') name: this.$t('dashboard.dashboard.chartForm.typeVal.bubble.label')
@@ -1006,7 +1010,8 @@ export default {
case 'treemap': case 'treemap':
case 'pie': case 'pie':
case 'doughnut': case 'doughnut':
if (this.oldType === 'bar' || this.oldType === 'treemap' || this.oldType === 'pie' || this.oldType === 'doughnut') { case 'rose':
if (this.oldType === 'bar' || this.oldType === 'treemap' || this.oldType === 'pie' || this.oldType === 'doughnut' || this.oldType === 'rose') {
break break
} }
this.chartConfig.param = { this.chartConfig.param = {