如图所示,pie的,根据需要,pie需要偏移:
center: ['30%', '50%']
这种情况下title如何才能保证相对饼图居中呢,echarts的宽度是自适应的.
如图所示,pie的,根据需要,pie需要偏移:
center: ['30%', '50%']
这种情况下title如何才能保证相对饼图居中呢,echarts的宽度是自适应的.
graphic:{
type:"text",
left:"center",
top:"center",
style:{
text:'236',
textAlign:"center",
fill:"#fff",
fontSize:16
}
},
这么写下试下呢 我这边可以实现自适应
graphic: [{
type: 'group',
left: '15%',
top: '35%',
bounding: 'raw',
children: [{
type: 'text',
style: {
text:data.value,
fontSize: 8,
fill: "#27D9C8",
textVerticalAlign: 'middle',
textAlign: 'center'
}
}]
}
],
不建议这样做,我这种方式label是一个叠一个的,不推荐,建议html直接定位做
目的就是在饼图中间加一个说明文本,想实现一个自适应水平居中的效果,不一定要用title来实现,可以选择使用label,同时设置hover时,不隐藏label即可
pie设置偏移可以用left 50%这样来实现,label设置多行,可以用富文本来做
参考代码
series: [
{
name: 'hello test',
left: '-50%',
type: 'pie',
radius: ['50%', '70%'],
center: ['50%', '50%'],
avoidLabelOverlap: false,
label: {
show: true,
position: 'center',
formatter: () => '{count|4425}\n{name|hello}',
rich: {
count: {
fontSize: 24,
padding: [0, 0, 5, 0],
color: '#49DEFF',
textVerticalAlign: 'middle'
},
name: {
fontSize: 12,
}
}
},
emphasis: {
label: {
show: true
}
},
labelLine: {
show: false
},
data
}
]
、、、
我觉得非常有必要分享下解决这个问题的方法,搜了不少文章,但都没能真正解决。
好了说了一堆屁话,以下是组件
import { useState, useEffect, useCallback, useRef } from "react";
import * as echarts from 'echarts';
import './index.less';
export type RingChartPropsType = {
id: string,
style: React.CSSProperties,
color: string[],
title?: titlePropsType | undefined,
legend?: echarts.LegendComponentOption | echarts.LegendComponentOption[],
series?: echarts.SeriesOption | echarts.SeriesOption[],
titleText?:{text?:string, textStyle?:React.CSSProperties, subtext?:string, subtextStyle?:React.CSSProperties};
};
type titlePropsType = {
text: string,
top: string,
left: string,
};
type EChartsOption = echarts.EChartsOption;
const RingChart = (props: RingChartPropsType) => {
const { id, style, color, title, legend, series } = props;
const [titleStyle, setTitleStyle] = useState({});
const contRef = useRef<HTMLDivElement>(null);
const handleEcharts = () => {
const dom = document.getElementById(id)!;
const charts = echarts.init(dom);
return charts;
}
const option: EChartsOption = {
color: color,
title: title,
legend: legend,
series: series,
};
useEffect(() => {
const myChart = handleEcharts();
myChart.setOption(option);
setLayout();
}, [props]);
const setLayout = useCallback(() => {
const cont = contRef.current;
if (!cont) return;
const width = cont.offsetWidth - (parseFloat(props.style?.paddingRight ?? 0));
const height = cont.offsetHeight - (parseFloat(props.style?.paddingBottom ?? 0));
const typeSeries = props.series as echarts.SeriesOption;
const minSize = Math.min(width, height);
//默认不能更改
const [centerX, centerY] = typeSeries.center || ['50%', '50%'];
const [iRadius] = typeSeries.radius || ['40%', '70%'];
const fRadius = typeof iRadius === 'string' ? parseFloat(iRadius) / 100 * minSize : iRadius;
const titleSize = fRadius;
const titleStyle = {
textAlign:'center',
width: titleSize,
height: titleSize,
top: '50%',
marginTop:-titleSize/2,
left: '50%',
marginLeft:-titleSize/2,
};
//left优先于right
if(typeSeries.left){
if (typeof typeSeries.left === 'string') {
const left = 0.5 * width * parseFloat(typeSeries.left) / 100;
titleStyle.marginLeft += left;
}
if (typeof typeSeries.left === 'number') {
titleStyle.marginLeft += 0.5 * typeSeries.left;
}
}else{
if (typeof typeSeries.right === 'string') {
const left = 0.5 * width * parseFloat(typeSeries.right) / 100;
titleStyle.marginLeft -= left;
}
if (typeof typeSeries.right === 'number') {
const left = 0.5 * typeSeries.right;
titleStyle.marginLeft -= left;
}
}
//top优先于bottom
if(typeSeries.top){
if (typeof typeSeries.top === 'string') {
const top = 0.5 * height * parseFloat(typeSeries.top) / 100;
titleStyle.marginTop += top;
}
if (typeof typeSeries.top === 'number') {
titleStyle.marginTop += 0.5 * typeSeries.top;
}
}else{
if (typeof typeSeries.bottom === 'string') {
const bottom = 0.5 * height * parseFloat(typeSeries.bottom) / 100;
titleStyle.marginTop -= bottom;
}
if (typeof typeSeries.bottom === 'number') {
const bottom = 0.5 * typeSeries.bottom;
titleStyle.marginTop -= bottom;
}
}
setTitleStyle({ ...titleStyle });
}, [props]);
return <div style={ { ...style } } ref={ contRef }>
<div style={{position:'relative', height: '100%', width: '100%'}}>
{props.titleText && <div style={ { position: 'absolute', ...titleStyle } }>
<div style={{width:'100%', height:'100%', display:'flex', justifyContent:'center', alignItems:'center', flexDirection:'column'}}>
<span style={{fontSize:16, color:'#000', ...props.titleText.textStyle}}>{props.titleText.text}</span>
<div style={{fontSize:24, lineHeight:'20px', fontWeight:'bold', color:'#000', ...props.titleText.subtextStyle}}>{props.titleText.subtext}</div>
</div>
</div>}
<div id={ id } style={ { height: '100%', width: '100%'} }></div>
</div>
</div>
}
export default RingChart;
使用
const pieOption:RingChartPropsType = {
id:'pie',
style:{ height: '40%', width: '100%' },
color:['#f59a23', '#70b603'],
legend:{
bottom: '2%',
left: 'center',
icon: 'circle',
},
titleText:{
text:'已存储量',
subtext:transforByte(dataAssets.assetsEnd+dataAssets.assetsSource)
},
series:{
type:'pie',
radius:['46%', '75%'],
label:{
show:true,
position:'inside',
formatter:'{percent|{d}%}',
rich:{
percent:{
fontSize: 14,
color:'#fffffffe'
},
}
},
data:[
{ value: dataAssets.assetsEnd, name: `已发布数据 ${transforByte(dataAssets.assetsEnd)}` },
{ value: dataAssets.assetsSource, name: `原始数据 ${transforByte(dataAssets.assetsSource)}` },
],
}
仅配置titleText
即可,可以兼容series[left|right|top|bottom]
标量与百分比。
主要思路就是利用传统html元素居中的实现方式,前提要知道pie的中心点。
因为电脑截图会被加密,所以图片就不上传了。
希望对大家有帮助。
我也遇到了这个问题,最后自己想出来了,可以设置padding为负值(应该是标题宽度的一半)。


left的偏移量应该和饼图的中心点位置一致。