繼折線圖柱狀圖的tooltip自動輪播之后,需求又加了餅圖的tooltip自動輪播,
涉及的原因有頁面上布局的位置有限,餅圖加內容比較多的label展示的話會很費位置,導致餅子太小,其次,bizcharts的label比較長的情況下,formatter只是格式化數據,導致內容過長,使用HTMLTemplate雖然可以多行展示,但是如果餅圖數據不美好的情況下,會導致label疊加在一起,bizcharts只計算了又一行數據的情況下label的位置不疊加,唉

而tooltip自動輪播完美的解決了這些問題
針對theta類型的餅圖:(后續補充polar類型)
1.關於坐標系官網是這樣說的
注意:坐標軸不展示,但是還是要寫的;

坐標系講解可見官網
https://bizcharts.net/product/bizcharts/category/7/page/25
需要注意坐標系起始位置

2.找tooltip輪播的三個點

3.有兩種方式,一種是selected選中tooltip展示,第二種是actived后tooltip展示,下面代碼中兩種方式都有,項目中選擇了后者
方式不同,Geom的參數也需要對應着改
select={false}
active={[true, { highlight: true }]}
4.代碼和部分注釋如下
import React, { Component } from 'react';
import { Chart, Geom, Axis, Tooltip, Coord, Label, Legend, View, Guide, Shape } from 'bizcharts';
import DataSet from '@antv/data-set';
const { DataView } = DataSet;
export default class Basic extends Component {
constructor() {
super();
this.state = {
tooltipStuff: true, // tooltip是否輪播
mockData: [] // 頁面數據
}
}
componentDidMount() {
this.setState({
mockData: [
{ type: 'type1', value: 250, percent: 25 },
{ type: 'type2', value: 500, percent: 50 },
{ type: 'type3', value: 250, percent: 25 },
]
})
}
onGetG2InstanceTooltips = (chart, data) => {
let basePercent = 0;
let pointList = [];
const outerRadius = 0.5, innerRadius = 0.45;
// 坐標系的內外半徑和data都可以從chart的屬性中找到,為了省事我的代碼里是寫死的
const coord = chart.get('coord')
data.map((item, index) => {
pointList.push({ index: index, point: this.getThetaPiePoint(basePercent, item['newPercent'], coord, outerRadius, innerRadius), data: item })
basePercent += item['newPercent']
})
this.setState({ tooltipStuff: true }, () => {
this.onActivedPointInterval(pointList, chart)
})
}
getThetaPiePoint = (basePercent, percent, coord, outerRadius, innerRadius) => {
const { radius, circleCentre } = coord // circleCentre 圓環圓心所在坐標
const middleRadius = (outerRadius, innerRadius) / 2 // 找圓環中間的半徑
const middleLength = middleRadius * radius / outerRadius // 獲取圓環上新的點的半徑
const angle = Math.PI * 2 * (basePercent + percent / 2) - Math.PI / 2 // 角度 Math.PI * 2(占比 / 2) - Math.PI / 2 圓環的角度開始的位置在手表的12點中位置
const x1 = circleCentre.x + middleLength * Math.cos(angle) // x1 = x0 + r*cos(a)
const y1 = circleCentre.y + middleLength * Math.sin(angle) // y1 = y0 + r*sin(a)
// 取的點是geom每一塊的中心的點,如圖
return { x: x1, y: y1 }
}
// tooltip 輪播與Geom的交互有兩種:select效果,active效果
// 方案一:select效果
onSelectedPointInterval = (pointList, chart) => {
let i = 0
this.selectedInterval = setInterval(() => {
if (!!this.state.tooltipStuff) {
++i;
if (i > pointList.length - 1) {
i = -1
} else {
const geoms = chart.get('geoms')[0]
const items = geoms.get('data')
geoms.setSelected(items[pointList[i].index])
chart.showTooltip(pointList[i].point)
}
}
}, 1000 * 3);
}
// 方案二:active效果,項目中由於每一塊chart占用的空間比較小,所以采用了這種方式
onActivedPointInterval = (pointList, chart) => {
let i = 0
this.activeInterval = setInterval(() => {
if (!!this.state.tooltipStuff) {
++i;
if (i > pointList.length - 1) {
i = -1
} else {
const geoms = chart.get('geoms')[0]
const shapes = geoms.getShapes();
// _id 是bizcharts用來區分執行動畫的,所以不能再<Chart/> 中加入 {animate:false},在這里用來表示geom的每一項,跟Geom的color屬性傳遞的字段一致,如 _id:"chart-geom0-1-#64d5ec"
const shapeItemIndex = shapes.findIndex(item => item._id.includes(pointList[i].data.color))
geoms.setShapesActived([shapes[shapeItemIndex]]) // 需要傳入數組
chart.showTooltip(pointList[i].point)
}
}
}, 1000 * 3);
}
// 鼠標移入
onPlotMoveTooltips = (ev) => {
this.setState({ tooltipStuff: false })
}
// 鼠標移出
onPlotLeaveTooltips = (ev) => {
this.setState({ tooltipStuff: true })
}
render() {
const dv = new DataView()
// 后台返回的percent頁面展示需要用,所以我定義了一個計算圓環百分比的newPercent,根據value計算出來的,避免了小數位數等問題
dv.source(this.state.mockData).transform({
type: 'percent',
field: 'value',
dimension: 'type',
as: 'newPercent'
})
const cols = {
percent: { formatter: (val) => `${(val * 100).toFixed(2)}%` }
}
const itemColor = [
{ field: 'type1', color: '#e9b05c' },
{ field: 'type2', color: '#5b6bfe' },
{ field: 'type3', color: '#64d5ec' },
]
itemColorMap = (type) => {
return itemColor.find(item => item.field === type)["color"]
}
return (
<div>
{
!!data && data.length > 0 ?
<Chart height={400} data={dv} scale={cols} forceFit
onGetG2Instance={(chart, data) => this.onGetG2InstanceTooltips(chart, dv['rows'])}
onPlotMove={(ev) => this.onPlotMoveTooltips(ev)}
onPlotLeave={(ev) => this.onPlotLeaveTooltips(ev)}>
<Coord type="theta" radius={0.5} innerRadius={0.45} />
<Axis name="type" />
<Axis name="newPercent" />
<Tooltip
crosshairs={{ type: "cross", style: { stroke: 'rgba(0,0,0,0)' } }}
showTitle={false} />
<Geom type="line" position="year*value" size={2} />
<Geom
type="intervalStack"
position="newPercent"
color={["type", (type => { itemColorMap(type) })]}
opacity={1}
select={false}
active={[true, { highlight: true }]}
tooltip={["type*value*percent", (type, value, percent) => { return { name: type, value: `${value}(${percent.toFixed(2)}%)` } }]} />
</Chart> : null
}
</div>
)
}
}
