• 用echarts在vue2中实现3d饼图


    先看效果,再看文章:

    一、安装插件

    3d的图不仅用到echarts,还用到了echarts-gl,因此都需要安装一下哦~

    1. npm install echarts
    2. npm install echarts-gl@2.0.9 //可以指定版本,也可不指定

    二、在main.js中引入

    1. import * as echarts from "echarts";
    2. import 'echarts-gl';
    3. Vue.prototype.$echarts = echarts;

    三、在组件中使用

    直接复制粘贴吧,省事

    1. <template>
    2. <div class="ybjgtzz">
    3. <!-- 饼图 -->
    4. <div class="container">
    5. <div class="chartsGl" id="charts"></div>
    6. <!-- 饼图下面的底座 -->
    7. <div class="buttomCharts"></div>
    8. </div>
    9. </div>
    10. </template>
    11. <script>
    12. export default {
    13. name: "Zysjg",
    14. data() {
    15. return {
    16. optionData: [
    17. {
    18. name: '工业',//名称
    19. value: 19,//
    20. itemStyle: {//颜色
    21. color: 'rgba(3, 62, 209,0.5)'
    22. }
    23. }, {
    24. name: '生活',
    25. value: 13,
    26. itemStyle: {
    27. color: 'rgba(61, 222, 207,0.5)',
    28. }
    29. }, {
    30. name: '农业',
    31. value: 15,
    32. itemStyle: {
    33. color: 'rgba(193, 142, 34,0.3)'
    34. }
    35. },
    36. ],
    37. option: {}
    38. };
    39. },
    40. mounted() {
    41. this.$nextTick(() => {
    42. this.init();
    43. });
    44. },
    45. methods: {
    46. //初始化构建
    47. init() {
    48. //构建3d饼状图
    49. let myChart = this.$echarts.init(document.getElementById('charts'));
    50. // 传入数据生成 option ; getPie3D(数据,透明的空心占比(调节中间空心范围的0就是普通饼1就很镂空))
    51. this.option = this.getPie3D(this.optionData, 0.85);
    52. //将配置项设置进去
    53. myChart.setOption(this.option);
    54. //鼠标移动上去特效效果
    55. // this.bindListen(myChart);
    56. },
    57. //配置构建 pieData 饼图数据 internalDiameterRatio:透明的空心占比
    58. getPie3D(pieData, internalDiameterRatio) {
    59. let that = this;
    60. let series = [];
    61. let sumValue = 0;
    62. let startValue = 0;
    63. let endValue = 0;
    64. let legendData = [];
    65. let legendBfb = [];
    66. let k = 1 - internalDiameterRatio;
    67. pieData.sort((a, b) => {
    68. return (b.value - a.value);
    69. });
    70. // 为每一个饼图数据,生成一个 series-surface(参数曲面) 配置
    71. for (let i = 0; i < pieData.length; i++) {
    72. sumValue += pieData[i].value;
    73. let seriesItem = {
    74. //系统名称
    75. name: typeof pieData[i].name === 'undefined' ? `series${i}` : pieData[i].name,
    76. type: 'surface',
    77. //是否为参数曲面(是)
    78. parametric: true,
    79. //曲面图网格线(否)上面一根一根的
    80. wireframe: {
    81. show: false
    82. },
    83. pieData: pieData[i],
    84. pieStatus: {
    85. selected: false,
    86. hovered: false,
    87. k: k
    88. },
    89. //设置饼图在容器中的位置(目前没发现啥用)
    90. center: ['80%', '100%'],
    91. radius: '60%',
    92. };
    93. //曲面的颜色、不透明度等样式。
    94. if (typeof pieData[i].itemStyle != 'undefined') {
    95. let itemStyle = {};
    96. typeof pieData[i].itemStyle.color != 'undefined' ? itemStyle.color = pieData[i].itemStyle.color : null;
    97. typeof pieData[i].itemStyle.opacity != 'undefined' ? itemStyle.opacity = pieData[i].itemStyle.opacity : null;
    98. seriesItem.itemStyle = itemStyle;
    99. }
    100. series.push(seriesItem);
    101. }
    102. // 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数,
    103. // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。
    104. legendData = [];
    105. legendBfb = [];
    106. for (let i = 0; i < series.length; i++) {
    107. endValue = startValue + series[i].pieData.value;
    108. series[i].pieData.startRatio = startValue / sumValue;
    109. series[i].pieData.endRatio = endValue / sumValue;
    110. series[i].parametricEquation = that.getParametricEquation(series[i].pieData.startRatio, series[i].pieData.endRatio,
    111. false, false, k, series[i].pieData.value);
    112. startValue = endValue;
    113. let bfb = that.fomatFloat(series[i].pieData.value / sumValue, 4);
    114. legendData.push({
    115. name: series[i].name,
    116. value: bfb
    117. });
    118. legendBfb.push({
    119. name: series[i].name,
    120. value: bfb
    121. });
    122. }
    123. //(第二个参数可以设置你这个环形的高低程度)
    124. let boxHeight = this.getHeight3D(series, 20);//通过传参设定3d饼/环的高度
    125. // 准备待返回的配置项,把准备好的 legendData、series 传入。
    126. let option = {
    127. //图例组件
    128. legend: {
    129. data: legendData,
    130. //图例列表的布局朝向。
    131. orient: 'horizontal',
    132. center: 0,
    133. bottom: 0,
    134. //图例文字每项之间的间隔
    135. itemGap: 15,
    136. textStyle: {
    137. color: '#A1E2FF',
    138. fontSize: '12px'
    139. },
    140. itemHeight: 10, // 修改icon图形大小
    141. itemWidth: 10, // 修改icon图形大小
    142. show: true,
    143. icon: 'circle',
    144. //格式化图例文本(我是数值什么显示什么)
    145. formatter: function (name) {
    146. var target;
    147. for (var i = 0, l = pieData.length; i < l; i++) {
    148. if (pieData[i].name == name) {
    149. target = pieData[i].value;
    150. }
    151. }
    152. return `${name}: ${target}`;
    153. },
    154. // 这个可以显示百分比那种(可以根据你想要的来配置)
    155. formatter: function (param) {
    156. let item = legendBfb.filter(item => item.name == param)[0];
    157. let bfs = that.fomatFloat(item.value * 100, 2) + "%";
    158. console.log(item.name)
    159. return `${item.name} :${bfs}`;
    160. }
    161. },
    162. //移动上去提示的文本内容(我没来得及改 你们可以根据需求改)
    163. tooltip: {
    164. formatter: params => {
    165. if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'pie2d') {
    166. let bfb = ((option.series[params.seriesIndex].pieData.endRatio - option.series[params.seriesIndex].pieData.startRatio) *
    167. 100).toFixed(2);
    168. return `${params.seriesName}<br/>` +
    169. `<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>` +
    170. `${bfb}`;
    171. }
    172. }
    173. },
    174. labelLine: {
    175. show: true,
    176. lineStyle: {
    177. color: '#7BC0CB',
    178. },
    179. },
    180. label: {
    181. show: true,
    182. position: 'outside',
    183. formatter: '{b} \n{c} {d}%',
    184. },
    185. //这个可以变形
    186. xAxis3D: {
    187. min: -1,
    188. max: 1
    189. },
    190. yAxis3D: {
    191. min: -1,
    192. max: 1
    193. },
    194. zAxis3D: {
    195. min: -1,
    196. max: 1
    197. },
    198. //此处是修改样式的重点
    199. grid3D: {
    200. show: false,
    201. boxHeight: boxHeight, //圆环的高度
    202. //这是饼图的位置
    203. top: '-20.5%',
    204. left: '-4%',
    205. viewControl: { //3d效果可以放大、旋转等,请自己去查看官方配置
    206. alpha: 25, //角度(这个很重要 调节角度的)
    207. distance: 160,//调整视角到主体的距离,类似调整zoom(这是整体大小)
    208. rotateSensitivity: 0, //设置为0无法旋转
    209. zoomSensitivity: 0, //设置为0无法缩放
    210. panSensitivity: 0, //设置为0无法平移
    211. autoRotate: false //自动旋转
    212. }
    213. },
    214. series: series
    215. };
    216. return option;
    217. },
    218. //获取3d丙图的最高扇区的高度
    219. getHeight3D(series, height) {
    220. series.sort((a, b) => {
    221. return (b.pieData.value - a.pieData.value);
    222. })
    223. return height * 25 / series[0].pieData.value;
    224. },
    225. // 生成扇形的曲面参数方程,用于 series-surface.parametricEquation
    226. getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, h) {
    227. // 计算
    228. let midRatio = (startRatio + endRatio) / 2;
    229. let startRadian = startRatio * Math.PI * 2;
    230. let endRadian = endRatio * Math.PI * 2;
    231. let midRadian = midRatio * Math.PI * 2;
    232. // 如果只有一个扇形,则不实现选中效果。
    233. if (startRatio === 0 && endRatio === 1) {
    234. isSelected = false;
    235. }
    236. // 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3
    237. k = typeof k !== 'undefined' ? k : 1 / 3;
    238. // 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0
    239. let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
    240. let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
    241. // 计算高亮效果的放大比例(未高亮,则比例为 1
    242. let hoverRate = isHovered ? 1.05 : 1;
    243. // 返回曲面参数方程
    244. return {
    245. u: {
    246. min: -Math.PI,
    247. max: Math.PI * 3,
    248. step: Math.PI / 32
    249. },
    250. v: {
    251. min: 0,
    252. max: Math.PI * 2,
    253. step: Math.PI / 20
    254. },
    255. x: function (u, v) {
    256. if (u < startRadian) {
    257. return offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
    258. }
    259. if (u > endRadian) {
    260. return offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
    261. }
    262. return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
    263. },
    264. y: function (u, v) {
    265. if (u < startRadian) {
    266. return offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
    267. }
    268. if (u > endRadian) {
    269. return offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
    270. }
    271. return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
    272. },
    273. z: function (u, v) {
    274. if (u < -Math.PI * 0.5) {
    275. return Math.sin(u);
    276. }
    277. if (u > Math.PI * 2.5) {
    278. return Math.sin(u) * h * .1;
    279. }
    280. return Math.sin(v) > 0 ? 1 * h * .1 : -1;
    281. }
    282. };
    283. },
    284. // 监听鼠标事件,实现饼图选中效果(单选),近似实现高亮(放大)效果。
    285. bindListen(myChart) {
    286. let that = this;
    287. let selectedIndex = '';
    288. let hoveredIndex = '';
    289. // 监听点击事件,实现选中效果(单选)
    290. myChart.on('click', function (params) {
    291. // 从 option.series 中读取重新渲染扇形所需的参数,将是否选中取反。
    292. let isSelected = !that.option.series[params.seriesIndex].pieStatus.selected;
    293. let isHovered = that.option.series[params.seriesIndex].pieStatus.hovered;
    294. let k = that.option.series[params.seriesIndex].pieStatus.k;
    295. let startRatio = that.option.series[params.seriesIndex].pieData.startRatio;
    296. let endRatio = that.option.series[params.seriesIndex].pieData.endRatio;
    297. // 如果之前选中过其他扇形,将其取消选中(对 option 更新)
    298. if (selectedIndex !== '' && selectedIndex !== params.seriesIndex) {
    299. that.option.series[selectedIndex].parametricEquation = that.getParametricEquation(that.option.series[
    300. selectedIndex].pieData
    301. .startRatio, that.option.series[selectedIndex].pieData.endRatio, false, false, k, that.option.series[
    302. selectedIndex].pieData
    303. .value);
    304. that.option.series[selectedIndex].pieStatus.selected = false;
    305. }
    306. // 对当前点击的扇形,执行选中/取消选中操作(对 option 更新)
    307. that.option.series[params.seriesIndex].parametricEquation = that.getParametricEquation(startRatio, endRatio,
    308. isSelected,
    309. isHovered, k, that.option.series[params.seriesIndex].pieData.value);
    310. that.option.series[params.seriesIndex].pieStatus.selected = isSelected;
    311. // 如果本次是选中操作,记录上次选中的扇形对应的系列号 seriesIndex
    312. isSelected ? selectedIndex = params.seriesIndex : null;
    313. // 使用更新后的 option,渲染图表
    314. myChart.setOption(that.option);
    315. });
    316. // 监听 mouseover,近似实现高亮(放大)效果
    317. myChart.on('mouseover', function (params) {
    318. // 准备重新渲染扇形所需的参数
    319. let isSelected;
    320. let isHovered;
    321. let startRatio;
    322. let endRatio;
    323. let k;
    324. // 如果触发 mouseover 的扇形当前已高亮,则不做操作
    325. if (hoveredIndex === params.seriesIndex) {
    326. return;
    327. // 否则进行高亮及必要的取消高亮操作
    328. } else {
    329. // 如果当前有高亮的扇形,取消其高亮状态(对 option 更新)
    330. if (hoveredIndex !== '') {
    331. // 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 false
    332. isSelected = that.option.series[hoveredIndex].pieStatus.selected;
    333. isHovered = false;
    334. startRatio = that.option.series[hoveredIndex].pieData.startRatio;
    335. endRatio = that.option.series[hoveredIndex].pieData.endRatio;
    336. k = that.option.series[hoveredIndex].pieStatus.k;
    337. // 对当前点击的扇形,执行取消高亮操作(对 option 更新)
    338. that.option.series[hoveredIndex].parametricEquation = that.getParametricEquation(startRatio, endRatio,
    339. isSelected,
    340. isHovered, k, that.option.series[hoveredIndex].pieData.value);
    341. that.option.series[hoveredIndex].pieStatus.hovered = isHovered;
    342. // 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
    343. hoveredIndex = '';
    344. }
    345. // 如果触发 mouseover 的扇形不是透明圆环,将其高亮(对 option 更新)
    346. if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'pie2d') {
    347. // 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 true
    348. isSelected = that.option.series[params.seriesIndex].pieStatus.selected;
    349. isHovered = true;
    350. startRatio = that.option.series[params.seriesIndex].pieData.startRatio;
    351. endRatio = that.option.series[params.seriesIndex].pieData.endRatio;
    352. k = that.option.series[params.seriesIndex].pieStatus.k;
    353. // 对当前点击的扇形,执行高亮操作(对 option 更新)
    354. that.option.series[params.seriesIndex].parametricEquation = that.getParametricEquation(startRatio, endRatio,
    355. isSelected, isHovered, k, that.option.series[params.seriesIndex].pieData.value + 5);
    356. that.option.series[params.seriesIndex].pieStatus.hovered = isHovered;
    357. // 记录上次高亮的扇形对应的系列号 seriesIndex
    358. hoveredIndex = params.seriesIndex;
    359. }
    360. // 使用更新后的 option,渲染图表
    361. myChart.setOption(that.option);
    362. }
    363. });
    364. // 修正取消高亮失败的 bug
    365. myChart.on('globalout', function () {
    366. // 准备重新渲染扇形所需的参数
    367. let isSelected;
    368. let isHovered;
    369. let startRatio;
    370. let endRatio;
    371. let k;
    372. if (hoveredIndex !== '') {
    373. // 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 true
    374. isSelected = that.option.series[hoveredIndex].pieStatus.selected;
    375. isHovered = false;
    376. k = that.option.series[hoveredIndex].pieStatus.k;
    377. startRatio = that.option.series[hoveredIndex].pieData.startRatio;
    378. endRatio = that.option.series[hoveredIndex].pieData.endRatio;
    379. // 对当前点击的扇形,执行取消高亮操作(对 option 更新)
    380. that.option.series[hoveredIndex].parametricEquation = that.getParametricEquation(startRatio, endRatio,
    381. isSelected,
    382. isHovered, k, that.option.series[hoveredIndex].pieData.value);
    383. that.option.series[hoveredIndex].pieStatus.hovered = isHovered;
    384. // 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
    385. hoveredIndex = '';
    386. }
    387. // 使用更新后的 option,渲染图表
    388. myChart.setOption(that.option);
    389. });
    390. },
    391. //这是一个自定义计算的方法
    392. fomatFloat(num, n) {
    393. var f = parseFloat(num);
    394. if (isNaN(f)) {
    395. return false;
    396. }
    397. f = Math.round(num * Math.pow(10, n)) / Math.pow(10, n); // n 幂
    398. var s = f.toString();
    399. var rs = s.indexOf('.');
    400. //判定如果是整数,增加小数点再补0
    401. if (rs < 0) {
    402. rs = s.length;
    403. s += '.';
    404. }
    405. while (s.length <= rs + n) {
    406. s += '0';
    407. }
    408. return s;
    409. },
    410. },
    411. // 准备待返回的配置项,把准备好的 legendData、series 传入。
    412. }
    413. </script>
    414. <style lang="scss" scoped>
    415. //饼图(外面的容器)
    416. .container {
    417. width: 90%;
    418. height: 100%;
    419. padding-top: 15px;
    420. }
    421. //饼图的大小
    422. .chartsGl {
    423. height: 200px;
    424. width: 380px;
    425. }
    426. //饼图底座(我也想给你们底座图片 可是我不知道咋给)
    427. .buttomCharts {
    428. background: center top url("../imgs/u111.png") no-repeat;
    429. background-size: 100% 100%;
    430. height: 95px;
    431. width: 204px;
    432. margin-top: -141px;
    433. margin-left: 21%;
    434. }
    435. .ybjgtzz {
    436. overflow-y: auto;
    437. padding: 10px;
    438. height: 250px;
    439. box-sizing: border-box;
    440. }
    441. </style>

    四、常修改的参数

    1、修改3d饼图大小,在大概244行的位置,grid3D的对象里面,修改distance属性,即可调整

    值越小,图越大 

     

    2、修改3d饼图视角高度,在大概161行的位置,修改函数的第二个参数

     

    3、修改3d饼图颜色,直接在data中的optionData里面修改就行了
     4、修改饼图位置,这个常用,也是在grid3D这个属性里面设置,在大概240行的位置

    在3d饼图中设置下面这两属性是没用的,所以这里请注意一下,记得去grid3D里面修改他的位置

     

     最后乘上官方文档例子:echarts图表集

  • 相关阅读:
    frp 反向隧道代理(内网穿透)之协议 “websocket”
    电脑重装系统后Win11用户名怎么更改
    【C++】STL入门—— 一张图带你了解常用的string类函数
    用帝国主义竞争算法(ICA)求解旅行商问题(TSP)(Matlab代码实现)
    Qt QtWidgets相关问题汇总
    浅谈分布式任务调度系统Celery的设计与实现
    构造函数原型prototype
    【Jmeter】二次开发
    core sound driver详解
    澳大利亚博士后招聘|国立大学—太阳能电池方向
  • 原文地址:https://blog.csdn.net/qq_41579104/article/details/133949902