news 2026/10/13 4:48:58

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/10/13 3:21:08

15、系统管理脚本实用指南

系统管理脚本实用指南 在Unix或Linux系统管理中,shell脚本是非常实用的工具。下面将详细介绍几个实用的系统管理脚本。 1. 环境验证脚本(validator) 环境验证脚本用于检查用户环境变量的有效性。以下是脚本代码: if [ ! -d ${HOME:?"You need to have your HOME…

作者头像 李华
网站建设 2026/10/12 19:15:10

怎么选一款适合大面积清洁的多功能全自动洗地机呢?

理解多功能全自动洗地机的优势在如今快节奏的生活里&#xff0c;我们越来越需要高效的清洁工具。多功能全自动洗地机就像是清洁工作的小帮手&#xff0c;不仅能快速完成常规的清理&#xff0c;还能提供多种功能&#xff0c;让打扫变得更加简单。例如&#xff0c;MN-V86驾驶式洗…

作者头像 李华
网站建设 2026/10/12 2:57:55

教培行业新媒体运营困境凸显!这款软件或成转型制胜法宝?

随着数字化时代的来临&#xff0c;教培行业的竞争格局发生了巨大变化。新媒体运营成为了教培机构提升品牌知名度、获取客户的重要手段。然而&#xff0c;许多教培机构在新媒体运营过程中却遭遇了重重困境&#xff0c;如何突破这些困境&#xff0c;实现数字化转型&#xff0c;成…

作者头像 李华