当前位置:   article > 正文

echarts环形3D立体图_echarts 立体环形图

echarts 立体环形图

 "echarts": "^5.2.0",    "echarts-gl": "^2.0.8",vue2.6

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

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号