首页 > 其他分享 >echarts两饼图连接映射

echarts两饼图连接映射

时间:2024-09-24 10:49:02浏览次数:13  
标签:const 映射 两饼 pieCenters props false type echarts left

最近开发中,突然来了一个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

相关文章

  • XML映射器-动态sql
    01-动态sql1.实现动态条件SQL第一种方法在sql语句中加入where1=1其他条件都加and就行,这样就可以根据if条件来判断要传递的参数可以有几个第二种方法用where标签给if语句包起来where标签的作用如下图第三种方法用trim标签解释如下图用choose也可以实现条件查询......
  • 利用 JavaScript 的集合和映射实现高效的内容管理系统
    javascript提供了几种强大的数据结构来处理数据集合。其中,map和set对于某些类型的任务特别有用。在本博客中,我们将探讨使用map和set解决常见编程问题的现实示例。理解地图和集合在深入示例之前,让我们快速回顾一下javascript中的map和set是什么。地图map是键值对......
  • 第二百四十一节 JPA教程 - JPA一对一主键连接列示例、JPA一对一映射级联示例
    JPA教程-JPA一对一主键连接列示例例子下面的代码来自Person.java。packagecn.w3cschool.common;importjavax.persistence.Entity;importjavax.persistence.GeneratedValue;importjavax.persistence.GenerationType;importjavax.persistence.Id;importjavax.pe......
  • Recharts:终极 React 图表库
    在当今数据驱动的世界中,有效可视化数据的能力比以往任何时候都更加重要。无论您是数据科学家、开发人员还是业务分析师,创建富有洞察力的交互式图表都可以帮助您清晰地传达复杂的信息。用于此目的的最佳工具之一是recharts——一个完全基于react组件构建的可组合图表库。在这篇......
  • 二,MyBatis -Plus 关于映射 Java Bean 对象的注意事项和细节(详细说明)
    二,MyBatis-Plus关于映射JavaBean对象的注意事项和细节(详细说明)文章目录二,MyBatis-Plus关于映射JavaBean对象的注意事项和细节(详细说明)1.映射2.表的映射3.字段映射4.字段失效5.视图属性6.总结:7.最后:1.映射这里的映射:是指将从数据库查询到的信......
  • 用户态内存映射
    内存映射不仅仅是物理内存和虚拟内存之间的映射,还包括将文件中的内容映射到虚拟内存空间。这个时候,访问内存空间就能够访问到文件里面的数据。而仅有物理内存和虚拟内存的映射,是一种特殊情况。对于堆的申请来讲,mmap是映射内存空间到物理内存。如果一个进程想映射一个文件到自己的......
  • 【数据类型】映射map
    小明正在备考英语四级考试,但他的词典太厚了,他记不住哪个单词在哪里。于是他准备开发一个可以直接找某单词在某页的应用。但是,他不会做,整天十分烦恼。好啦,进入正题,大家好,我是@学霸小羊,今天来讲讲map——映射map翻译为映射,是STL中的常用容器。其实,数组就是一种映射,比如:int......
  • 使用swig映射c++function
    swig可以自动生成从c++到其他语言如Java、Python等转换的中间语言,目前swig已经支持很多c++11的特性了,但是这次项目中发现function特性还没有支持,只能自己生成。从网上找了一份Java的java-HowtouseSWIGtowrapstd::functionobjects?-StackOverflow,我需要的c#的,故需要稍......
  • 请考虑使用 app.config 将程序集“XXXX”从版本“x.y.z.0”[]重新映射到版本“x.y.z.1
    VisualStudio编译过程中,发现以下警告:请考虑使用app.config将程序集“Newtonsoft.Json,Culture=neutral,PublicKeyToken=30ad4fe6b2a6aeed”从版本“10.0.0.0”[]重新映射到版本“13.0.0.0”[D:\WorkSpace..................\Debug\Newtonsoft.Json.dll],以解决冲突并消除警告......
  • 0708,文件流,目录流,MMAP内存映射
    目录目录相关操作目录流及相关操作文件描述符和相关操作fopen()和open()的关系内存映射mmapmmap相关函数01_chdir.c02_mkdir.c03_rewinddir.c04_ftruncate.c05_mmap.c目录相关操作#include<unistd.h>#include<sys/stat.h>#include<sys/types.h>char*getcw......