news 2026/4/15 4:53:50

Vue3 漏斗图

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue3 漏斗图

三种效果图:

图一:

<template> <v-chart ref="vChartRef" :option="option"></v-chart> </template> <script setup lang="ts"> import { ref, computed, PropType, nextTick } from "vue"; import VChart from "vue-echarts"; import { use } from "echarts/core"; import { CanvasRenderer } from "echarts/renderers"; import { FunnelChart } from "echarts/charts"; import cloneDeep from "lodash/cloneDeep"; import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent, } from "echarts/components"; use([ DatasetComponent, CanvasRenderer, FunnelChart, GridComponent, TooltipComponent, LegendComponent, ]); // 获取图表实例 const vChartRef = ref(); const chartData = ref<any>([ { name: "data1", value: 20, }, { name: "data2", value: 40, }, { name: "data3", value: 60, }, { name: "data4", value: 80, }, { name: "data5", value: 100, }, ]); const seriesItem = ref<any>({ type: "funnel", top: 70, left: "10%", width: "80%", min: 0, minSize: "0%", maxSize: "100%", sort: "descending", // descending | ascending gap: 5, label: { show: true, position: "inside", fontSize: 12, }, itemStyle: { borderColor: "#fff", borderWidth: 0, }, emphasis: { label: { fontSize: 20, }, }, data: <any>[], }); const getSeries = () => { let series: any = []; const values = chartData.value; //系列模板 let item = cloneDeep(seriesItem.value); item.data = values; series.push(item); return series; }; const option = ref<any>({ tooltip: {}, legend: {}, series: getSeries(), }); </script>

图二:

<template> <v-chart ref="vChartRef" :option="option"></v-chart> </template> <script setup lang="ts"> import { ref, computed, PropType, nextTick } from "vue"; import VChart from "vue-echarts"; import { use } from "echarts/core"; import { CanvasRenderer } from "echarts/renderers"; import { FunnelChart } from "echarts/charts"; import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent, } from "echarts/components"; use([ DatasetComponent, CanvasRenderer, FunnelChart, GridComponent, TooltipComponent, LegendComponent, ]); // 获取图表实例 const vChartRef = ref(); const chartData = ref<any>({ dimensions: ["categoryName", "categoryNum"], source: [ { categoryName: "施工管理", categoryNum: 20 }, { categoryName: "物管纠纷", categoryNum: 40 }, { categoryName: "房屋交易监管", categoryNum: 60 }, { categoryName: "街面秩序", categoryNum: 80 }, { categoryName: "拖欠克扣工资", categoryNum: 100 }, { categoryName: "产品质量问题", categoryNum: 88 }, { categoryName: "失业待遇", categoryNum: 64 }, ], }); // 排序函数 const sortBy = (property: string) => { return function (value1: any, value2: any) { let a = value1[property]; let b = value2[property]; if (a < b) { return 1; } if (a > b) { return -1; } return 0; }; }; // 数据处理 const source = [...chartData.value.source].sort(sortBy("categoryNum")); const total = source.reduce((prev: any, cur: any) => prev + cur.categoryNum, 0); const legendData = source.map((i: any) => { // 计算占比 const zb = (i.categoryNum / total) * 100; let percent = 0; if (zb - Math.floor(zb) > 0) { percent = Number(zb.toFixed(2)); } else { percent = zb; } // 文本换行 let text = i.categoryName; let length = text.length; let maxLineLength = 6; let lineCount = Math.ceil(length / maxLineLength); let lines = []; for (let j = 0; j < lineCount; j++) { let line = text.substr(j * maxLineLength, maxLineLength); lines.push(line); } const str = lines.join("\n"); return `${str}\n${i.categoryNum}次 | ${percent}%`; }); // 重新组装数据 const dataMap = { dimensions: chartData.value.dimensions, source: legendData.map((label: any, index: number) => ({ categoryName: label, categoryNum: source[index].categoryNum, title: source[index].categoryName, })), }; const option = ref<any>({ color: [ "#0674F1", "#029CD4", "#2BA471", "#F5BA18", "#E37318", "#D54941", "#E851B3", "#8E56DD", ], dataset: { ...dataMap }, legend: { type: "scroll", orient: "vertical", left: "65%", width: 90, height: "100%", itemGap: 8, data: legendData, }, series: [ { name: "Funnel", type: "funnel", top: "3%", left: "0%", width: "60%", height: "100%", min: 0, minSize: "0%", maxSize: "100%", sort: 'ascending', // descending | ascending gap: 2, colorBy: "data", label: { show: true, position: "inside", fontSize: 12, fontWeight: "bold", fontFamily: "Arial-BoldMT", color: "#fff", formatter: `{d}%`, }, itemStyle: { borderColor: "#fff", borderWidth: 0, shadowBlur: 0, }, emphasis: { label: { fontSize: 20, }, }, }, ], }); </script>

图三:

<template> <v-chart ref="vChartRef" :option="option"></v-chart> </template> <script setup lang="ts"> import { ref, computed, PropType, nextTick } from "vue"; import VChart from "vue-echarts"; import { use } from "echarts/core"; import { CanvasRenderer } from "echarts/renderers"; import { FunnelChart } from "echarts/charts"; import cloneDeep from 'lodash/cloneDeep' import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent, } from "echarts/components"; use([ DatasetComponent, CanvasRenderer, FunnelChart, GridComponent, TooltipComponent, LegendComponent, ]); // 获取图表实例 const vChartRef = ref(); const chartData = ref<any>({ dimensions: ["categoryName", "categoryNum"], source: [ { categoryNum: 10678, categoryName: "高中及以上学历", }, { categoryNum: 9678, categoryName: "专科及以上学历", }, { categoryNum: 6678, categoryName: "本科及以上学历", }, { categoryNum: 1678, categoryName: "硕士及以上学历", }, { categoryNum: 178, categoryName: "博士及以上学历", }, ], }); // 排序函数 const sortBy = (property: string) => { return function (value1: any, value2: any) { let a = value1[property]; let b = value2[property]; if (a < b) { return 1; } if (a > b) { return -1; } return 0; }; }; // 数据处理 const source = [...chartData.value.source].sort(sortBy("categoryNum")); const total = source.reduce((prev: any, cur: any) => prev + cur.categoryNum, 0); const legendData = cloneDeep(source).map(i => { // 计算占比 const zb = (i.categoryNum / total) * 100 let percent = 0 if(zb - Number(zb) > 0){ percent = Number(zb.toFixed(2)) }else{ percent = zb } // 文本换行 let text = i.categoryName; let length = text.length; let maxLineLength = 6; // 每行最多显示的字符数 let lineCount = Math.ceil(length / maxLineLength); // 计算需要几行 let lines = []; for (let i = 0; i < lineCount; i++) { let line = text.substr(i * maxLineLength, maxLineLength); lines.push(line); } const str = lines.join('\n'); return `${str}\n${i.categoryNum}次 | ${percent}%` }) // 重新组装数据 const dataMap = { dimensions: chartData.value.dimensions, source: legendData.map((label: any, index: number) => ({ categoryName: label, categoryNum: source[index].categoryNum, title: source[index].categoryName, })), }; const option = ref<any>({ color: [ "#0674F1", "#029CD4", "#2BA471", "#F5BA18", "#E37318", "#D54941", "#E851B3", "#8E56DD", ], dataset: { ...dataMap }, legend: { type: "scroll", orient: "vertical", left: "65%", width: 90, height: "100%", itemGap: 16, data: legendData, }, series: [ { name: "Funnel", type: "funnel", top: "3%", left: "0%", width: "60%", height: "100%", min: 0, minSize: "0%", maxSize: "100%", sort: "descending", // descending | ascending gap: 2, colorBy: "data", label: { show: true, position: "inside", fontSize: 12, fontWeight: "bold", fontFamily: "Arial-BoldMT", color: "#fff", // formatter: '{c}', formatter: (params: any) => { return params.value.categoryNum; }, }, itemStyle: { borderColor: "#fff", borderWidth: 0, shadowBlur: 0, }, emphasis: { label: { fontSize: 20, }, }, }, ], }); </script>
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/14 18:37:52

从“证书获取“到“能力建设“:六西格玛培训的价值实现路径

在制造业质量管理的实践中&#xff0c;一个有趣的现象值得深思&#xff1a;两家同行业的包装企业同时派员工参加六西格玛绿带培训&#xff0c;三个月后&#xff0c;A公司的学员成功主导了产线损耗率降低42%的改进项目&#xff0c;而B公司的学员却连基础数据收集工作都未能完成。…

作者头像 李华
网站建设 2026/4/10 19:42:32

基于阶梯式碳机制与电制氢的综合能源系统优化调度:热电联产与氢能效益研究

MATLAB 代码:考虑阶梯式碳机制与电制氢的综合能源系统热电优化 关键词:碳 电制氢 阶梯式碳 综合能源系统 热电优化 参考文档:《考虑阶梯式碳机制与电制氢的综合能源系统热电优化》基本复现 仿真平台:MATLABCPLEX 主要内容:代码主要做的是一个考虑阶梯式碳机制的电热综合能源…

作者头像 李华
网站建设 2026/4/10 9:43:27

可持续测试实践探索

可持续测试的时代背景与意义 在数字化浪潮席卷全球的今天&#xff0c;软件已成为社会运转的核心驱动力&#xff0c;但随之而来的能源消耗、电子废弃物和低效流程也对环境与社会构成了挑战。根据行业数据&#xff0c;全球IT部门的碳排放占总量约2-4%&#xff0c;而低质量软件导…

作者头像 李华
网站建设 2026/4/3 18:16:39

「安卓开发辅助工具按键精灵」xml全分辨率插件jsd插件脚本教程

在处理界面上文字提取的问题&#xff0c;我通常会选择使用jsd插件&#xff0c;感觉用起来挺方便&#xff0c;以往在使用jsd插件的时候就是按照命令提供例子的方法直接使用&#xff0c;这次想自己分析一下每个命令。 jsd插件主要是对节点的处理&#xff0c;我也只分析和节点相关…

作者头像 李华
网站建设 2026/4/15 0:53:15

代码复现:LEARNING FAST AND SLOW FORONLINE TIME SERIES FORECASTING

基于上一篇文章文献阅读&#xff1a;LEARNING FAST AND SLOW FORONLINE TIME SERIES FORECASTING-CSDN博客过后&#xff0c;这里去根据论文中的代码仓库进行了一个实验。尊重原创代码&#xff1a;GitHub - DMIRLAB-Group/LSTD 问题 这里发现给的配置文件不是很全面&#xff0c…

作者头像 李华
网站建设 2026/4/12 12:47:54

密码管理器:单主密码管所有,是便捷福音还是风险陷阱?

在数字时代&#xff0c;每个人的生活都被密密麻麻的账号密码包裹&#xff1a;社交软件、购物平台、办公系统、金融账户……为了安全&#xff0c;我们被反复提醒“不要重复使用密码”“密码需包含大小写字母、数字和特殊符号”&#xff1b;可为了记忆&#xff0c;不少人又不得不…

作者头像 李华