vue3+echarts实现渐变电池环形图+自定义图例(仅适用于背景不透明的情况)

实现的效果如下:

这个图表就是在渐变环形图的基础上进行构造的,同样的我的data的结构同渐变圆环图的一样

由于ui图的设计中的图例在基本的结构中没有,在echarts中定义了一些图例的形状

icon:

circle, rect, roundRect, triangle, diamond, pin, arrow, none

或者使用图片链接 image://或者base64图片(可在网上在线转成base64类型)

我这里是使用的阿里巴巴矢量图库iconfont的图标,选择自己需要的图标加入购物车然后添加到项目中,到这个页面中,点击到symbol点击生成代码,下边会出现一个js文件的链接

在这个文件中我们只需要path d =“”里的内容放在echarts中legend中的icon中icon: 'path://',中即可自定义legend的图标。

具体的代码如下

<div class="chart" ref="chartRef" style="width: 400px; height: 230px;"></div>
<script setup>
import * as echarts from 'echarts';
import { ref, onMounted, nextTick } from 'vue';
const chartRef = ref(null)
import up from '../../assets/images/cockpit/right/icon-arrow-up.png'
import down from '../../assets/images/cockpit/right/icon-arrow-down.png'

const obj= {}//同渐变圆环图的结构,就不展示了
const totalValue = ref(obj.equmentStatusEchart.reduce((total, value) => total + value.value, 0));
const rangArr = ref([]);
let cacheNum = 0;
for (let i = 0; i < obj.equmentStatusEchart.length; i++) {
  const endNum = cacheNum + obj.equmentStatusEchart[i].value;
  rangArr.value.push([cacheNum, endNum]);
  cacheNum = endNum;
}
const angleArr = ref(rangArr.value.map(arr => arr.map(num => (num / totalValue.value) * Math.PI * 2)));
function getCoordinates(startArc, endArc) {
  const posi = [
    Math.sin(startArc),
    -Math.cos(startArc),
    Math.sin(endArc),
    -Math.cos(endArc)
  ];
  const dx = posi[2] - posi[0];
  const dy = posi[3] - posi[1];

  return getLocation(dx, dy);
}

function getLocation(dx, dy) {
  const tanV = dx / dy;
  const directSign = Math.abs(tanV) < 1;
  const t = directSign ? tanV : 1 / tanV;

  const sign1 = t > 0 ? 1 : -1;
  const sign2 = dx > 0 ? 1 : -1;
  const sign = directSign ? sign1 * sign2 : sign2;

  const group1 = [0.5 - sign * t / 2, 0.5 + sign * t / 2];
  const group2 = sign > 0 ? [0, 1] : [1, 0];
  const group = [...group1, ...group2];
  const keys = directSign ? ['x', 'x2', 'y', 'y2'] : ['y', 'y2', 'x', 'x2'];

  let res = {};
  keys.forEach((k, idx) => {
    res[k] = group[idx];
  });
  return res;
}

onMounted(() => {
  const chartDom = chartRef.value;
  const myChart = echarts.init(chartDom);
  myChart.setOption({
    tooltip: {
      trigger: 'item',
      backgroundColor: 'rgba(0, 0 , 0, .6)',
      borderColor: "rgba(147, 235, 248, .8)",
      textStyle: {
        color: "#fff"
      },
    },
    graphic: [
      {
        type: 'text',
        left: '18%',
        top: '30%',
        style: {
          text: totalValue.value,
          fill: '#fff',
          fontSize: 36,
          fontWeight: 600,
          fontFamily:  'ShuHeiTi'
        }
      },
      {
        type: 'text',
        left: '36%',
        top: '38%',
        style: {
          text: '人',
          fill: '#fff',
          fontSize: 14,
          fontWeight: 400,
        }
      },
      {
        type: 'text',
        left: '18%',
        top: '50%',
        style: {
          text: '租房总人数',
          fill: '#fff',
          fontSize: 16,
          fontWeight: 400,
          fontFamily:  'ShuHeiTi'
        }
      },
      {
        type: 'text',
        left: '20%',
        top: '65%',
        style: {
          text: '同比',
          fill: '#fff',
          fontSize: 14,
          fontWeight: 400,
        }
      },
      {
        type: 'image',
        left: '30%',
        top: '63%',
        style: {
          image: '/src/assets/images/cockpit/right/icon-arrow-up.png',
          width:10,
          height:16,
        }
      },
      {
        type: 'text',
        left: '34%',
        top: '65%',
        style: {
          text: '0',
          fill: '#00FFB1',
          fontSize: 14,
          fontWeight: 400,
        }
      },
    ],
    legend: {
      // data: obj.equmentStatusEchart,
        orient: 'vertical',
        right: 10,
        top: 0,
        icon: 'path://M 1021.72 1021.72 l 0 -1019.45 c -270.222 0 -529.749 107.52 -720.896 298.553 S 2.27556 751.502 2.27556 1021.72 L 1021.72 1021.72 Z',
        formatter: function(name) {
          const item = obj.equmentStatusEchart.find(item => item.name === name);
          let text = '{a|' + item.name + '}' + ' {b|' + item.value + '}' + ' {c|' + '人' + '} \n';
          if(item.up) {
            text += '{d|' + '同比' + '}' + '{e|}' + '{f|' + item.up + '}';
          } else if(item.down) {
            text += '{d|' + '同比' + '}' + '{h|}' + '{g|' + item.down + '}';
          }
          return text
        },
        textStyle: {
          rich: {
          a: {
            color: '#fff',
            fontSize: 14,
            fontWeight: 400,
            padding: [15, 0, 0, 0]
          },
          b: {
            color: '#fff',
            fontSize: 20,
            fontWeight: 600,
            fontFamily: 'ShuHeiTi',
            padding: [15, 0, 0, 10]
          },
          c: {
            color: '#fff',
            fontSize: 10,
            fontWeight: 400,
            lineHeight: 30,
            padding: [14, 0, 0, 0]
          },
          d: {
            color: '#fff',
            fontSize: 12,
            fontWeight: 400,
            padding: [0, 10, 0, 60]
          },
          e: {
            width:10,
            height: 16,
            backgroundColor: {image: up}
          },
          h: {
            width:10,
            height: 16,
            backgroundColor: {image: down}
          },
          f: {
            color: '#00FFB1',
            fontSize: 14,
            fontWeight: 400,
            lineHeight: 20,
            padding: [0, 0, 0, 5]
          },
          g: {
            color: '#F00000',
            fontSize: 14,
            fontWeight: 400,
            lineHeight: 20,
            padding: [0, 0, 0, 5]
          }
        }
        },


      },
    
    series: [
      {//最外部细虚线
        type: 'gauge',
          startAngle: 0,
          endAngle: 360,
          radius: '110%',
          center: ['28%', '52%'],
          axisTick: {
              show: false
          },
          axisLabel: {
              show: false
          },
          splitNumber: 30,
          axisLine: {
              show: false,

          },
          splitLine: {
              length: 25,
              lineStyle: {
                  width: 5,
                  color: 'rgba(8, 21, 53, 1)',
                  distance: 10,
              } //刻度节点线
          },
          detail: {
              show: false
          },
          z:10
      },
    {
        type: 'pie',
        radius: ['75%', '89%'],
        center: ['28%', '52%'],
        avoidLabelOverlap: false,
        itemStyle: {
        },
        label: {
          show: false,
          position: 'outer',
          align: 'left',
          height: 50,
          lineHeight: 10,
          formatter: function(params) {
          return (
            '{a|' + params.data.name + '}\n' +
            '{b|' + params.data.value  + ' } ' +
            '{value| 人}'
          );
          },
          borderWidth: 10,
          padding: [0, -60],
          rich: {
          a: {
            fontSize: 14,
            color: '#fff',
            fontWeight: 400,
            lineHeight: 35
          },
          b: {
            color: '#fff', 
            fontSize: 18,
            fontWeight: 600,
            lineHeight: 10
          },
          value: {
            color: '#fff',
            fontSize: 14,
            fontWeight: 400,
          }
        }
        },
      labelLine: {
        show: false
      },
        emphasis: {
          itemStyle:{
            shadowBlur: 10,
            shadowOffsetX: 0,
            shadowColor: 'rgba(0, 0, 0, 0.2)'
          }
        },
        z: 1,
        itemStyle: {

        },
        data: obj.equmentStatusEchart.map((item, index) => {
        const range = getCoordinates(angleArr.value[index][0], angleArr.value[index][1]);
        const startColor = `rgb(${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)}, ${Math.floor(Math.random() * 256)})`;
        const color = {
          type: 'linear',
          x: range.x,
          x2: range.x2,
          y: range.y,
          y2: range.y2,
          colorStops: [{
              offset: 0, color: item.start // 指定起始颜色
          }, {
              offset: 1, color: item.end // 指定终点颜色
          }],
          global: false
        };

        return {
          name: item.name,
          value: item.value,
          itemStyle: {
            color: color
        }
        };
      })
      }
      
    ],
  });
})
</script>

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue3是一种流行的JavaScript框架,而Echarts5是一种强大的数据可视化库。结合Vue3和Echarts5,可以很容易地实现世界地的可视化效果。 首先,你需要在Vue项目中安装Echarts5。可以通过npm或yarn来安装echarts: ``` npm install echarts ``` 或者 ``` yarn add echarts ``` 安装完成后,你可以在Vue组件中引入Echarts,并使用它来绘制世界地。 在Vue组件中,你可以使用`<template>`标签来定义HTML模板,使用`<script>`标签来编写JavaScript代码,使用`<style>`标签来定义CSS样式。 下面是一个简单的示例代码,展示了如何在Vue3中使用Echarts5绘制世界地: ```vue <template> <div id="world-map" style="width: 100%; height: 400px;"></div> </template> <script> import * as echarts from 'echarts'; export default { mounted() { this.drawWorldMap(); }, methods: { drawWorldMap() { const chartDom = document.getElementById('world-map'); const myChart = echarts.init(chartDom); // 定义地数据 const mapData = [ { name: 'China', value: 100 }, { name: 'United States', value: 50 }, // 其他国家... ]; // 配置地选项 const option = { tooltip: { trigger: 'item', formatter: '{b}: {c}', }, visualMap: { min: 0, max: 100, left: 'left', top: 'bottom', text: ['High', 'Low'], seriesIndex: [1], inRange: { color: ['#e0ffff', '#006edd'], }, }, series: [ { type: 'map', mapType: 'world', roam: true, label: { show: true, }, data: mapData, }, ], }; // 使用配置项绘制地 myChart.setOption(option); }, }, }; </script> <style> #world-map { width: 100%; height: 400px; } </style> ``` 在上面的代码中,我们首先引入了Echarts库,然后在`mounted`生命周期钩子函数中调用`drawWorldMap`方法来绘制地。`drawWorldMap`方法中,我们使用`echarts.init`方法初始化一个Echarts实例,并通过配置项`option`来定义地的样式和数据。最后,使用`myChart.setOption(option)`方法将配置项应用到地上。 这样,你就可以在Vue项目中使用Vue3和Echarts5来实现世界地的可视化效果了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值