最近开发中,突然来了一个echarts还要很快开发出来。。
要老命了,遭老罪了。。
先看需求图
思考了半天还是有点思路,前端画图不就是搭积木嘛。
1. 中间蓝色阴影部分用canvas来做
2. 获取容器和饼图在页面上的位置,绘制梯形
3. 使用2个mask作为饼图圆心,用于遮挡echarts中心位置的梯形canvas
首先获取容器和饼图在页面上的位置
获取图表实例中的扇形图坐标
难点在于绘制梯形,我们需要获取到梯形在饼图中的四个顶点
然后利用定位将mask部分,放在饼图中间遮挡住多余的梯形
废话不多说直接上代码
html部分
<template>
<div ref="chartRef" v-resize="chart" class="chart"></div>
<div class="mask"></div>
<div class="mask2"></div>
<canvas class="canvasImg" ref="canvas" width="200" height="300"></canvas>
</template>
js 部分
<script setup>
import { ref, onMounted, nextTick } from 'vue';
import * as echarts from 'echarts';
const props = defineProps({
electircData: { type: Array, default: [] }, // 电量结构占比值
legendData: { type: Array, default: [] }, // 电量结构占比值
allData: { type: String, default: false }, // 总数值
unit: { type: String, default: false } // 单位
})
const chartRef = ref(null);
let chart;
// 后端返回数据。。。
let legendData = []
// echarts部分。。。。
legendData = [...props.electircData, ...props.legendData]
const canvas = ref(null)
onMounted(() => {
chart = echarts.init(chartRef.value);
const option = {
// animation: true,
tooltip: {
trigger: 'item',
show: false
},
legend: {
show: false
},
graphic: [
{
type: 'text',// 类型,可以是文字、图片或其它类型
id: 'text1',
left: '16%',
top: '27%',
style: {
text: props.allData,
fill: '#7fabf0', // 文字的颜色
fontSize: 18,
fontWeight: 600
}
},
{
type: 'text',// 类型,可以是文字、图片或其它类型
id: 'text2',
left: '18%',
top: '33%',
style: {
text: props.unit,
fill: '#d9dadc', // 文字的颜色
fontSize: 12
}
},
{
type: 'text',// 类型,可以是文字、图片或其它类型
id: 'text3',
left: '17%',
top: '76%',
style: {
text: props.allData,
fill: '#7fabf0', // 文字的颜色
fontSize: 16,
fontWeight: 600
}
},
{
type: 'text',// 类型,可以是文字、图片或其它类型
id: 'text4',
left: '18%',
top: '82%',
style: {
text: props.unit,
fill: '#d9dadc', // 文字的颜色
fontSize: 12
}
}
],
color: ['#8fb6f2', '#ebc17e', '#8fb6f2', '#a7cdff', '#f9c956', '#3BA272'],
series: [
{
name: 'Access From',
type: 'pie',
radius: ['30%', '45%'],
center: ['25%', '30%'],
itemStyle: {
itemWidth: 200,
itemHeight: 300
},
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: false,
fontSize: 10,
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: props.electircData
},
{
name: 'Access From',
type: 'pie',
radius: ['20%', '35%'],
center: ['25%', '80%'],
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: false,
fontSize: 10,
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: props.legendData
}
]
};
chart.setOption(option);
const pieCenters = [];
// 监听饼图动画执行完成之后再绘制
chart.on('finished', () => {
getSectorPosition();
cavansMap();
})
// 绘制t形对比区
const cavansMap = async () => {
await nextTick()
const ctx = canvas.value.getContext('2d');
// 定义梯形的四个点
const topLeft = { x: pieCenters[0].left, y: pieCenters[0].y };
const topRight = { x: pieCenters[0].right, y: pieCenters[0].y };
const bottomLeft = { x: pieCenters[1].left, y: pieCenters[1].y };
const bottomRight = { x: pieCenters[1].right, y: pieCenters[1].y };
// 开始绘制梯形
ctx.beginPath();
ctx.moveTo(topLeft.x, topLeft.y); // 移动到梯形的左上角
ctx.lineTo(topRight.x, topRight.y); // 画线到右上角
ctx.lineTo(bottomRight.x, bottomRight.y); // 画线到右下角
ctx.lineTo(bottomLeft.x, bottomLeft.y); // 画线到左下角
ctx.closePath(); // 关闭路径,画到起点
// 填充区
ctx.fillStyle = '#dfeafb';
ctx.fill();
}
function resizeCanvas() {
// 获取容器的尺寸
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
// 重新绘制内容(可选)
cavansMap();
}
// 获取容器和饼图在页面上的位置
const getSectorPosition = () => {
const container = chart.getDom();
if (container && chart) {
// 获取图表实例中的扇形图坐标
const seriesData = chart.getOption().series;
seriesData.forEach((series, index) => {
let tmp = chart._chartsViews[index]._data._itemLayouts[0]
const x = tmp.cx;
const y = tmp.cy;
const left = tmp.cx - tmp.r
const right = tmp.cx + tmp.r
// 存储坐标
pieCenters.push({ index: index + 1, x, y, left, right });
});
}
};
// 初始化 Canvas 尺寸
window.addEventListener('resize', resizeCanvas);
})
</script>
css部分
<style scoped lang="scss">
.chart {
width: 300px;
height: 360px;
z-index: 3;
}
.mask {
position: absolute;
width: 110px;
height: 70px;
border-radius: 40px;
top: 92px;
left: 20px;
z-index: 2;
background-color: white;
}
.mask2 {
position: absolute;
width: 92px;
height: 70px;
border-radius: 40px;
top: 251px;
left: 32px;
z-index: 2;
background-color: white;
}
.canvasImg {
position: absolute;
top: 0px;
// left: 65px;
z-index: 1;
}
</style>
自适应什么的来不及做,先应付一下测试小姐姐,完结撒花!!!
标签:const,映射,两饼,pieCenters,props,false,type,echarts,left From: https://blog.csdn.net/longshehui/article/details/142483170