vue3之echarts3D环柱饼图

news2024/9/23 11:18:47
vue3之echarts3D环柱饼图

效果:
在这里插入图片描述

版本
"echarts": "^5.4.1", "echarts-gl": "^2.0.9"

核心代码:

<template>
    <div class="content">
        <div ref="eCharts" class="chart"></div>
    </div>
</template>

<script setup>
import { onMounted, ref } from "vue";
import * as echarts from "echarts";
import "echarts-gl";

const eCharts = ref(null);
let myChart = null;

let boxHeight;
let optionData = ref([
  {
    name: "林地",
    value: 5,
    itemStyle: {
      color: "#22c4ff",
    },
  },
  {
    name: "草地",
    value: 13,
    itemStyle: {
      color: "#aaff00",
    },
  },
  {
    name: "耕地",
    value: 38,
    itemStyle: {
      color: "#bbaaf1",
    },
  },
]);

const 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 * 0.1;
      }
      return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;
    },
  };
};

const getPie3D = (pieData, internalDiameterRatio) => {
  // internalDiameterRatio:透明的空心占比
  let series = [];
  let sumValue = 0;
  let startValue = 0;
  let endValue = 0;

  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,也就是实现每一个扇形。
  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 = getParametricEquation(
      series[i].pieData.startRatio,
      series[i].pieData.endRatio,
      false,
      false,
      k,
      series[i].pieData.value // 控制各模块高度一致100   控制各模块高度根据value改变
    );
    startValue = endValue;
  }
  boxHeight = getHeight3D(series, 26); //通过传参设定3d饼/环的高度,26代表26PX
  return series;
};

const getHeight3D = (series, height) => {
  series.sort((a, b) => {
    return b.pieData.value - a.pieData.value;
  });
  return (height * 25) / series[0].pieData.value;
};

const initCharts = () => {
  myChart = echarts.init(eCharts.value);
  const series = getPie3D(optionData.value, 0);
  series.push({
    name: "pie2d",
    type: "pie",
    label: {
      opacity: 1,
      fontSize: 28,
      lineHeight: 20,
    },
    labelLine: {
      length: 20,
      length2: 50,
    },
    startAngle: -40, //起始角度,支持范围[0, 360]。
    clockwise: false, //饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式
    radius: ["50%", "32%"],
    center: ["50%", "50%"],
    data: optionData.value,
    itemStyle: {
      opacity: 0,
    },
  });
  optionData.value.forEach((item) => {
    item.label = {
      color: item.itemStyle.color,
      show: true,
      formatter: (item) => {
        return `{b|${item.name} \n}`;
      },
      rich: {
        b: {
          fontSize: 16,
          lineHeight: 20,
        },
      },
    };
  });
  let option = {
    xAxis3D: {
      min: -1,
      max: 1,
    },
    yAxis3D: {
      min: -1,
      max: 1,
    },
    zAxis3D: {
      min: -1,
      max: 1,
    },
    grid3D: {
      show: false,
      top: 0, // 距离上边的间距
      boxHeight, // 圆环的高度
      viewControl: {
        // 3d效果可以放大、旋转等,请自己去查看官方配置
        alpha: 22, // 角度
        distance: 400, // 调整视角到主体的距离,类似调整zoom
        rotateSensitivity: 0, // 设置为0无法旋转
        zoomSensitivity: 0, // 设置为0无法缩放
        panSensitivity: 0, // 设置为0无法平移
        autoRotate: false, // 自动旋转
      },
    },
    series,
  };
  myChart?.setOption(option);
};

onMounted(() => {
  initCharts();
});
</script>

<style lang="scss" scoped>
.content {
    position: relative;

    .chart {
      position: absolute;
      top: -20px;
      left: -20px;
      width: 500px;
      height: 300px;
    }
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1421156.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Docker】linux、nginx、容器镜像三者基本概念

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是《Docker容器》序列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对…

【数据结构 04】单链表

一、链表简介 链表是一种物理存储结构上非连续的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 链表在结构上的分类&#xff1a; 1. 带头结点或无头结点 2. 单向或双向 3. 循环或非循环 虽然链表有多种结构类型&#xff0c;但是我么在实际开发中…

算法设计与分析实验:并查集与生成树

目录 一、情侣牵手 1.1 采用并查集的思想 1.2 采用动态规划的思想 二、账户合并 2.1 具体思路 2.2 思路呈现 2.3 代码实现 2.4 复杂度分析 三、连接所有点的最小费用 3.1 思路一&#xff1a;最小生成树 3.2 思路二&#xff1a;并查集 鸡汤 一、情侣牵手 力扣第765…

Django模型(五)

一、数据的条件查询 参考文档:QuerySet API 参考 | Django 文档 | Django 1.1、常用检索字段 字段检索,是在字段名后加 __ 双下划线,再加关键字,类似 SQL 语句中的 where 后面的部分, 如: 字段名__关键字 exact :判断是否等于value,一般不使用,而直接使用 =contai…

数据与资源可视化——长安链运维监控实践

前言 “链上的交易总量是多少”&#xff0c;“我的链上现在有多少区块了”&#xff0c;“节点是否存活无法第一时间感知到”&#xff0c;除sdk查询链上的相关信息外&#xff0c;今天我们介绍一种新的方式实现链上数据与相关资源的可视化的监控。 简介 监控链上数据以及链上节…

日志资源成本减少 35%:新东方可观测体系改造如何降本增效?

一分钟精华速览 在双减政策影响下&#xff0c;新东方面临业务缩减和资源紧张的局面&#xff0c;迫切需要技术调整和优化以应对成本压力并提高效率。面对人手减少、技术标准化不足和技术栈复杂等挑战&#xff0c;公司制定了通过建立标准化的可观测性体系来提升运维和研发效率的…

初始化爱情的构造之旅

初始化爱情的构造之旅 The Constructive Journey of Initializing Love 在一个名为“编程之城”的奇幻世界里&#xff0c;住着两位年轻的程序员——林浩然和杨凌芸。林浩然是Java王国中的首席对象设计师&#xff0c;擅长用代码构建复杂而精巧的对象&#xff1b;而杨凌芸则是数据…

专业138总分420+中国科学技术大学843信号与系统考研经验中科大电子信息通信

**今年中科大专业课843信号与系统138分&#xff0c;总分420顺利上岸&#xff0c;梦圆中科大&#xff0c;也是报了高考失利的遗憾&#xff0c;总结一下自己的复习经历&#xff0c;希望可以给大家提供参考。**首先&#xff0c;中科大843包括信号与系统&#xff0c;和数字信号处理…

Cache Lab:Part B- 32 ×32【分块算法】

任务描述 在B部分中&#xff0c;您将在trans.c中编写一个转置函数&#xff0c;从而导致尽可能少的miss。缓存的参数位 (s 5, E 1, b 5)。三种测试用例的矩阵大小分别为&#xff1a; • 32 32 (M 32, N 32) • 64 64 (M 64, N 64) • 61 67 (…

继电器模块详解

继电器&#xff0c;一种常见的电控制装置&#xff0c;其应用几乎无处不在。在家庭生活&#xff0c;继电器被广泛应用于照明系统、电视机、空调等电器设备的控制&#xff1b;在工业领域&#xff0c;它们用于控制电机、泵站、生产线等高功率设备的运行&#xff1b;继电器还在通信…

mini-spring|设计与实现资源加载器并从Spring.xml解析和注册Bean对象

**需求&#xff1a;**我们需要自动为bean加载资源&#xff0c;代替注册、注入属性、注入bean等功能 1.资源加载器属于相对独立的部分&#xff0c;它位于 Spring 框架核心包下的IO实现内容&#xff0c;主要用于处理Class、本地和云环境中的文件信息。 2.当资源可以加载后&#…

假期刷题打卡--Day18

1、MT1168阶乘数 输入正整数N&#xff0c;找出它是否是一个等于其他数的阶乘值的数&#xff0c;输出YES或者NO。 格式 输入格式&#xff1a; 输入正整数N 输出格式&#xff1a; 输出YES或者NO 样例 1 输入&#xff1a; 5输出&#xff1a; NO 相关知识点 阶乘 可以理…

研发人员如何做好日常工作的稳定性保障

一、前言 二、稳定性介绍 三、实际操作流程 1、需求分析阶段 2、设计阶段 2、1备选架构 2、2方案设计 2、3 架构设计 2、4设计的checklist 2、5的checklist 3、开发联调 4、自测环节 5、上线前环节 6、上线后的验收和复盘 四、稳定性、效率、成本之间的考量 五、…

12306 真的很拉跨吗?春运是对它最大的误解!

春节降至&#xff0c;大家都抢到火车票了吗&#xff1f;马上就要迎来春节&#xff0c;是不是都在吐槽 12306 的种种不好&#xff0c;它真的有这么拉跨吗&#xff1f; 其实不然&#xff0c;每到各种节假日&#xff0c;都是对 12306 最大的误解&#xff01; 特别是春运&#xf…

Vite+Vue3使用Vue-i18n笔记

一、下载依赖 vue-i18n yarn add vue-i18n创建存放语言文件的目录 以及配置文件的配置 我是在src/lang 新建index.ts、cn.ts、en.ts以及test文件夹其中再分别新建cn.ts以及en.ts /lang/index.ts 用于导出vue-i18n需要的配置对象 import en from "./en.ts"; import…

PYTHON蓝桥杯——每日一练(简单题)

题目 利用字母可以组成一些美丽的图形&#xff0c;下面给出了一个例子&#xff1a; ABCDEFG BABCDEF CBABCDE DCBABCD EDCBABC 这是一个5行7列的图形&#xff0c;请找出这个图形的规律&#xff0c;并输出一个n行m列的图形。 输入格式 输入一行&#xff0c;包含两个整数…

[ESXi 8]安装centos7

文章目录 创建虚拟机创建虚拟机选择centos7选择存储选择镜像文件上传ios镜像文件 安装即将完成 启动虚拟机自动获取ip设置root密码安装成功 创建虚拟机 创建虚拟机 选择centos7 选择存储 选择镜像文件 上传ios镜像文件 如图显示上传进度&#xff0c;上传完毕之后&#xff0c;将…

【讲座分享】| 复旦大学张奇教授——《自然语言发表论文如何打怪升级?NLP顶会论文发表》

文章目录 1 基础关1.1 基础书籍1.2 提高书籍1.3 课程链接1.4 编程实战 2 阅读关2.1 分层过滤2.2 集团作战&#xff0c;信息获取2.3 论文如何泛读 3 动机 方向关3.1 快速发论文3.2 好的研究 4 写作关4.1 论文写作流程4.2 从读者角度出发4.3 每一部分怎么写4.3.1 Abstract摘要4.3…

一体化设计:兼容多种OS系统Linux网关楼宇DDC

在工业物联网&#xff08;IIoT&#xff09;和智能建筑领域&#xff0c;钡铼网关具备高度灵活性与强大计算能力的边缘网关产品正逐渐成为推动行业智能化转型的关键要素。本文将详细介绍的基于Linux系统的4G工业智能网关&#xff0c;不仅拥有NXP i.MX8M Mini四核64位处理器的强大…

直播观看人次破30W | 极新「2024未来直播电商科技峰会」圆满落幕

“共话直播电商&#xff06;消费科技行业破局之道” 文&#xff5c;德江&凯丰 编辑 | 云舒 出品&#xff5c;极新 1月27日&#xff0c;由极新携手北京电子商务协会联合举办的「2024未来直播电商科技峰会」圆满落幕&#xff01;在峰会上&#xff0c;共进行了10 场演讲 &a…