三种效果图:

图一:

<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>

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐