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>
更多推荐


所有评论(0)