首先确保在项目中引入了echarts和echarts-gl
"echarts": "^4.9.0",
"echarts-gl": "^1.1.2"

剩下的配置好optionData的数据,交给代码

<template>
<div class="water-eval-container">
<div class="cityGreenLand-charts" id="cityGreenLand-charts">
</div>
</div>
</template> <script>
import echarts from 'echarts'
import 'echarts-gl';
export default {
name: "cityGreenLand",
components: {},
data() {
return {
optionData: [{
name: '林地面积统计',
value: 10000,
itemStyle: {
color: '#22c4ff',
}
}, {
name: '草地面积统计',
value: 12116,
itemStyle: {
color: '#aaff00'
}
}, {
name: '耕地地面积统计',
value: 16616,
itemStyle: {
color: '#ffaaff'
}
}],
}
},
mounted() {
this.$nextTick(function() {
this.init();
});
},
methods: {
init() {
//构建3d饼状图
let myChart = echarts.init(document.getElementById('cityGreenLand-charts'));
// 传入数据生成 option
this.option = this.getPie3D(this.optionData, 0.8);
myChart.setOption(this.option);
//是否需要label指引线,如果要就添加一个透明的2d饼状图并调整角度使得labelLine和3d的饼状图对齐,并再次setOption
this.option.series.push({
name: 'pie2d',
type: 'pie',
labelLine:{
length:10,
length2:10
},
startAngle: -20 , //起始角度,支持范围[0, 360]。
clockwise: false,//饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式
radius: ['20%', '50%'],
center: ['50%', '50%'],
data: this.optionData,
itemStyle:{
opacity:0
}
});
myChart.setOption(this.option);
this.bindListen(myChart);
}, getPie3D(pieData, internalDiameterRatio) {
//internalDiameterRatio:透明的空心占比
let that = this;
let series = [];
let sumValue = 0;
let startValue = 0;
let endValue = 0;
let legendData = [];
let legendBfb = [];
let k = 1 - internalDiameterRatio;
pieData.sort((a, b) => {
return (b.value - a.value);
});
// 为每一个饼图数据,生成一个 series-surface 配置
for (let i = 0; i < pieData.length; i++) {
sumValue += pieData[i].value;
let seriesItem = {
name: typeof pieData[i].name === 'undefined' ? `series${i}` : pieData[i].name,
type: 'surface',
parametric: true,
wireframe: {
show: false
},
pieData: pieData[i],
pieStatus: {
selected: false,
hovered: false,
k: k
},
center: ['10%', '50%']
}; if (typeof pieData[i].itemStyle != 'undefined') {
let itemStyle = {};
typeof pieData[i].itemStyle.color != 'undefined' ? itemStyle.color = pieData[i].itemStyle.color : null;
typeof pieData[i].itemStyle.opacity != 'undefined' ? itemStyle.opacity = pieData[i].itemStyle.opacity : null;
seriesItem.itemStyle = itemStyle;
}
series.push(seriesItem);
} // 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数,
// 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。
legendData = [];
legendBfb = [];
for (let i = 0; i < series.length; i++) {
endValue = startValue + series[i].pieData.value;
series[i].pieData.startRatio = startValue / sumValue;
series[i].pieData.endRatio = endValue / sumValue;
series[i].parametricEquation = this.getParametricEquation(series[i].pieData.startRatio, series[i].pieData.endRatio,
false, false, k, series[i].pieData.value);
startValue = endValue;
let bfb = that.fomatFloat(series[i].pieData.value / sumValue, 4);
legendData.push({
name: series[i].name,
value: bfb
});
legendBfb.push({
name: series[i].name,
value: bfb
});
}
let boxHeight = this.getHeight3D(series, 26);//通过传参设定3d饼/环的高度,26代表26px
// 准备待返回的配置项,把准备好的 legendData、series 传入。
let option = {
legend: {
data: legendData,
orient: 'horizontal',
left: 10,
top: 10,
itemGap: 10,
textStyle: {
color: '#A1E2FF',
},
show: true,
icon: "circle",
formatter: function(param) {
let item = legendBfb.filter(item => item.name == param)[0];
let bfs = that.fomatFloat(item.value * 100, 2) + "%";
return `${item.name} ${bfs}`;
}
},
labelLine: {
show: true,
lineStyle: {
color: '#7BC0CB'
}
},
label: {
show: true,
position: 'outside',
rich: {
b: {
color: '#7BC0CB',
fontSize: 12,
lineHeight: 20
},
c: {
fontSize: 16,
},
},
formatter: '{b|{b} \n}{c|{c}}{b| 亩}', },
tooltip: {
formatter: params => {
if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'pie2d') {
let bfb = ((option.series[params.seriesIndex].pieData.endRatio - option.series[params.seriesIndex].pieData.startRatio) *
100).toFixed(2);
return `${params.seriesName}<br/>` +
`<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>` +
`${ bfb }%`;
}
}
},
xAxis3D: {
min: -1,
max: 1
},
yAxis3D: {
min: -1,
max: 1
},
zAxis3D: {
min: -1,
max: 1
},
grid3D: {
show: false,
boxHeight: boxHeight, //圆环的高度
viewControl: { //3d效果可以放大、旋转等,请自己去查看官方配置
alpha: 40, //角度
distance: 300,//调整视角到主体的距离,类似调整zoom
rotateSensitivity: 0, //设置为0无法旋转
zoomSensitivity: 0, //设置为0无法缩放
panSensitivity: 0, //设置为0无法平移
autoRotate: false //自动旋转
}
},
series: series
};
return option;
}, //获取3d丙图的最高扇区的高度
getHeight3D(series, height) {
series.sort((a, b) => {
return (b.pieData.value - a.pieData.value);
})
return height * 25 / series[0].pieData.value;
}, // 生成扇形的曲面参数方程,用于 series-surface.parametricEquation
getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, h) {
// 计算
let midRatio = (startRatio + endRatio) / 2;
let startRadian = startRatio * Math.PI * 2;
let endRadian = endRatio * Math.PI * 2;
let midRadian = midRatio * Math.PI * 2;
// 如果只有一个扇形,则不实现选中效果。
if (startRatio === 0 && endRatio === 1) {
isSelected = false;
}
// 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3)
k = typeof k !== 'undefined' ? k : 1 / 3;
// 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0)
let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
// 计算高亮效果的放大比例(未高亮,则比例为 1)
let hoverRate = isHovered ? 1.05 : 1;
// 返回曲面参数方程
return {
u: {
min: -Math.PI,
max: Math.PI * 3,
step: Math.PI / 32
},
v: {
min: 0,
max: Math.PI * 2,
step: Math.PI / 20
},
x: function(u, v) {
if (u < startRadian) {
return offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
if (u > endRadian) {
return offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
},
y: function(u, v) {
if (u < startRadian) {
return offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
if (u > endRadian) {
return offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
},
z: function(u, v) {
if (u < -Math.PI * 0.5) {
return Math.sin(u);
}
if (u > Math.PI * 2.5) {
return Math.sin(u) * h * .1;
}
return Math.sin(v) > 0 ? 1 * h * .1 : -1;
}
};
}, fomatFloat(num, n) {
var f = parseFloat(num);
if (isNaN(f)) {
return false;
}
f = Math.round(num * Math.pow(10, n)) / Math.pow(10, n); // n 幂
var s = f.toString();
var rs = s.indexOf('.');
//判定如果是整数,增加小数点再补0
if (rs < 0) {
rs = s.length;
s += '.';
}
while (s.length <= rs + n) {
s += '0';
}
return s;
}, bindListen(myChart) {
// 监听鼠标事件,实现饼图选中效果(单选),近似实现高亮(放大)效果。
let that = this;
let selectedIndex = '';
let hoveredIndex = '';
// 监听点击事件,实现选中效果(单选)
myChart.on('click', function(params) {
// 从 option.series 中读取重新渲染扇形所需的参数,将是否选中取反。
let isSelected = !that.option.series[params.seriesIndex].pieStatus.selected;
let isHovered = that.option.series[params.seriesIndex].pieStatus.hovered;
let k = that.option.series[params.seriesIndex].pieStatus.k;
let startRatio = that.option.series[params.seriesIndex].pieData.startRatio;
let endRatio = that.option.series[params.seriesIndex].pieData.endRatio;
// 如果之前选中过其他扇形,将其取消选中(对 option 更新)
if (selectedIndex !== '' && selectedIndex !== params.seriesIndex) {
that.option.series[selectedIndex].parametricEquation = that.getParametricEquation(that.option.series[
selectedIndex].pieData
.startRatio, that.option.series[selectedIndex].pieData.endRatio, false, false, k, that.option.series[
selectedIndex].pieData
.value);
that.option.series[selectedIndex].pieStatus.selected = false;
}
// 对当前点击的扇形,执行选中/取消选中操作(对 option 更新)
that.option.series[params.seriesIndex].parametricEquation = that.getParametricEquation(startRatio, endRatio,
isSelected,
isHovered, k, that.option.series[params.seriesIndex].pieData.value);
that.option.series[params.seriesIndex].pieStatus.selected = isSelected;
// 如果本次是选中操作,记录上次选中的扇形对应的系列号 seriesIndex
isSelected ? selectedIndex = params.seriesIndex : null;
// 使用更新后的 option,渲染图表
myChart.setOption(that.option);
});
// 监听 mouseover,近似实现高亮(放大)效果
myChart.on('mouseover', function(params) {
// 准备重新渲染扇形所需的参数
let isSelected;
let isHovered;
let startRatio;
let endRatio;
let k;
// 如果触发 mouseover 的扇形当前已高亮,则不做操作
if (hoveredIndex === params.seriesIndex) {
return;
// 否则进行高亮及必要的取消高亮操作
} else {
// 如果当前有高亮的扇形,取消其高亮状态(对 option 更新)
if (hoveredIndex !== '') {
// 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 false。
isSelected = that.option.series[hoveredIndex].pieStatus.selected;
isHovered = false;
startRatio = that.option.series[hoveredIndex].pieData.startRatio;
endRatio = that.option.series[hoveredIndex].pieData.endRatio;
k = that.option.series[hoveredIndex].pieStatus.k;
// 对当前点击的扇形,执行取消高亮操作(对 option 更新)
that.option.series[hoveredIndex].parametricEquation = that.getParametricEquation(startRatio, endRatio,
isSelected,
isHovered, k, that.option.series[hoveredIndex].pieData.value);
that.option.series[hoveredIndex].pieStatus.hovered = isHovered;
// 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
hoveredIndex = '';
}
// 如果触发 mouseover 的扇形不是透明圆环,将其高亮(对 option 更新)
if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'pie2d') {
// 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 true。
isSelected = that.option.series[params.seriesIndex].pieStatus.selected;
isHovered = true;
startRatio = that.option.series[params.seriesIndex].pieData.startRatio;
endRatio = that.option.series[params.seriesIndex].pieData.endRatio;
k = that.option.series[params.seriesIndex].pieStatus.k;
// 对当前点击的扇形,执行高亮操作(对 option 更新)
that.option.series[params.seriesIndex].parametricEquation = that.getParametricEquation(startRatio, endRatio,
isSelected, isHovered, k, that.option.series[params.seriesIndex].pieData.value + 5);
that.option.series[params.seriesIndex].pieStatus.hovered = isHovered;
// 记录上次高亮的扇形对应的系列号 seriesIndex
hoveredIndex = params.seriesIndex;
}
// 使用更新后的 option,渲染图表
myChart.setOption(that.option);
}
});
// 修正取消高亮失败的 bug
myChart.on('globalout', function() {
// 准备重新渲染扇形所需的参数
let isSelected;
let isHovered;
let startRatio;
let endRatio;
let k;
if (hoveredIndex !== '') {
// 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 true。
isSelected = that.option.series[hoveredIndex].pieStatus.selected;
isHovered = false;
k = that.option.series[hoveredIndex].pieStatus.k;
startRatio = that.option.series[hoveredIndex].pieData.startRatio;
endRatio = that.option.series[hoveredIndex].pieData.endRatio;
// 对当前点击的扇形,执行取消高亮操作(对 option 更新)
that.option.series[hoveredIndex].parametricEquation = that.getParametricEquation(startRatio, endRatio,
isSelected,
isHovered, k, that.option.series[hoveredIndex].pieData.value);
that.option.series[hoveredIndex].pieStatus.hovered = isHovered;
// 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
hoveredIndex = '';
}
// 使用更新后的 option,渲染图表
myChart.setOption(that.option);
});
}
}
}
</script>
<style lang="less">
.water-eval-container {
width: 100%;
height: 100%;
}
.cityGreenLand-charts {
height: 200px;
width: 400px;
}
</style>

3D饼/环Echarts图的实现的更多相关文章

  1. 【js类库Raphaël】基于svg中的path画40%表示的环型图

     一.可供参考的文档资料. raphaeljs官网:http://raphaeljs.com/ w3c关于path的介绍:http://www.w3.org/TR/2003/REC-SVG11-200 ...

  2. 绘制3D的托卡马克位形图的matlab脚本文件 ThreeD.m

    % 绘制3D的托卡马克位形图, (V 0.1 by Jiale Chan for Y. H. Huang) % Dee Formula % 特征参数     rzero = 2.0;     rmax ...

  3. 带锁的3D切割轮播图

    3D切割轮播图. 加入锁,限制点击太快次数 <!DOCTYPE html><html><head lang="en"> <meta cha ...

  4. 3d照片环效果(修改版--添加了x轴y轴双向转动和修复模糊度的bug)

    今天用用前两天总结的css3新效果写了一个3d照片环的效果,其中还有些bug大家可以看一看,一起改进. <!DOCTYPE html> <html lang="en&quo ...

  5. FusionCharts 3D帕累托图

    1.设计3D帕累托图的页面 Pareto3D.html: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN&q ...

  6. FusionCharts 3D帕累托图报错

    今天我在设计3D帕累托图时,是由原来的2D帕累托图页面重命名而来,但是当我重命名后发现HTML文件打不开,而且还报错,真不知道是什么原因引起的.因此,我就将这个错误截图,保存下来,希望以后能够解决,或 ...

  7. js访3d上下轮播图

    js/css访3d上下轮播图 (附件) <!DOCTYPE html> <html> <head> <meta charset="utf-8&quo ...

  8. jQuery 3D圆盘旋转焦点图 支持鼠标滚轮

    之前我们分享过很多炫酷实用的jQuery焦点图插件了,今天介绍的这款jQuery焦点图非常特别,所有图片围成一个圆圈,组成一个立体视觉的圆盘,并且可以旋转选择圆盘中的图片.另外,这款jQuery 3D ...

  9. 基础篇:4.1)规范化:3d工程图纸出图步骤详解

    本章目的:按照工程图出图步骤,更方便出具规范的工程图. 1.工程出图步骤 这是作者个人归纳的步骤,供同行业工程师参考完善. 以solidworks为例,工程出图步骤如下:1.1)打开绘制的3d零件图, ...

随机推荐

  1. 对接快递100&聚水潭API

    对接快递100&聚水潭API 入我相思门,知我相思苦. 简介:对接第三方平台快递100&聚水潭API的简要总结. 1.感悟 个人感觉快递100的API更友好一些,比如有SDK可以调用: ...

  2. 未来直播 “神器”,像素级视频分割是如何实现的 | CVPR 冠军技术解读

    被誉为计算机视觉领域 "奥斯卡" 的 CVPR 刚刚落下帷幕,2021 年首届 "新内容 新交互" 全球视频云创新挑战赛正火热进行中,这两场大赛都不约而同地将关 ...

  3. 【死磕JVM】给同事讲了一遍GC后,他要去面试,年轻人,就是容易冲动!

    前言 在一个风和日丽的中午,和同事小勇一起走在公司楼下的小公园里面,看到很多的小姐姐,心想什么时候能够和这些小姐姐一起讨论人生呀,美滋滋,嘿嘿嘿. 收起你的哈喇子好不好,小勇总是在这个时候发出声音,挺 ...

  4. 如何使用Topshelf与.NET泛型主机建立Windows服务

    1 前置阅读 在阅读本文章之前,你可以先阅读: Topshelf一个用于使用.NET构建Windows服务框架 2 使用 2.1 创建应用程序 首先,创建一个新的控制台应用程序并从nuget获取Top ...

  5. PAT (Advanced Level) Practice 1031 Hello World for U (20 分) 凌宸1642

    PAT (Advanced Level) Practice 1031 Hello World for U (20 分) 凌宸1642 题目描述: Given any string of N (≥5) ...

  6. python工业互联网应用实战11—客户端UI

    这个章节我们将演示用户端界面的开发,当前演示界面还是采用先实现基本功能再逐步完善的"敏捷"模式.首先聚焦在功能逻辑方面实现普通用户与系统的交互,普通用户通过url能查看到当前任务的 ...

  7. Dynamics CRM修改密码界面

    我们再实施Dynamics CRM的过程中经常会被客户吐槽没有一个修改密码的页面.市面上也有一些人通过自己操作AD库进行修改密码的解决方案不过多多少少会有一些BUG存在.其实ADFS提供了一个修改密码 ...

  8. 周爱民带你深入剖析JavaScript核心原理

    作为前端工程师必备技能,JavaScript 的重要性不言而喻.虽然易上手,但却有着诸多复杂微妙的机制,想要真正掌握绝非易事. 专栏面向JavaScript语言的实际应用者与深度爱好者,以讲述Java ...

  9. Java面向对象7大设计原则

    目录 单一职责原则 SRP 开闭原则 OCP 里氏替换原则 LSP 依赖倒置原则 DIP 接口隔离原则 ISP 组合复用原则 CRP 迪米特法则 LOD 单一职责原则 SRP 一个类只有一个引起修改变 ...

  10. linux中[gcc -shared -fPIC]的含义

    linux在gcc编译时加上 -shared 参数时,目的是使源码编译成动态库 .so 文件: 而-fPIC的作用是 告知编译器 生成位置无关代码(编译产生的代码没有绝对位置,只有相对位置):从而可以 ...