基于echarts桑基图改造的数据流向

最近出了个需求,要求做一个数据流向的图表。

根据数据结构特点:数据可以通过多个节点开始流入,最终可以流向多个节点。根据这个特点,满足要求的有两个:一个是关系图,另一个是桑基图。再根据各节点的排列位置来看,桑基图是最接近的了

但是设计师觉得桑基图的样式不好看,所以要基于桑基图来调整。

一般的桑基图是这样的

在阅读echarts的桑基图的文档之后,节点的高度是自动的,宽度可以设置,但是只能统一设置,不能对节点单独设置。这样的比较麻烦了,不太好自定义了。

但是,echarts还有个label属性,我们可以通过echarts的label的富文本属性来自定义节点的样式【太妙了】 

下面直接上代码:

(这里的代码的主要终点就是对node的label的设置,已经link的lineStyle的设置,其他的根绝自己的需求调整即可)

使用的技术栈:vue3.0 + ts

function handleInitEchart(data: any[], links: any[]) {
      const nodesMap: any = {}, linksCountMap: any = {};
      const colors: any = [
        "#1C4BA0",
        "#F99F46",
        "#F4654E",
        "#5A2EF7",
        "#0086FF",
        "#FF6600",
        "#FF6666",
      ];
      const bigColor: any = [
        "#336699",
        "#FF6600",
        "#990033",
        "#FF6666",
        "#009966",
        "#CC6600",
        "#003366",
        "#CC3333",
        "#006699",
        "#FFCCCC",
      ];
      for (let i = 0; i < links.length; i++) {
        let item = links[i];
        if (!linksCountMap[item.target]) {
          linksCountMap[item.target] = [item.source];
        } else {
          linksCountMap[item.target].push(item.source);
        }
      }
      links.forEach((item: any) => {
        if (linksCountMap[item.target].includes(item.source)) {
          item.value = parseInt(
            (60 / linksCountMap[item.target].length) as any
          );
        } else {
          item.value = 10;
        }
        if (item.value > 10) {
          item.value = 10;
        }
        Object.assign(item, {
          lineStyle: {
            color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
              {
                offset: 0,
                color: colors[item.level - 1],
              },
              {
                offset: 1,
                color: colors[item.level],
              },
            ]),
          },
        });
      });
      for (let i = 0; i < data.length; i++) {
        data[i].count = data[i].value;
      }

      data.forEach((item: any, idx: number) => {
        if (!nodesMap[item.level]) {
          nodesMap[item.level] = [item];
        } else {
          nodesMap[item.level].push(item);
        }

        item.value = 30;
        item.name = "节点名称" + idx;
        let offsetY = 8;
        let padding = [4, 10],
          color = colors[item.level - 1];
        if (item.level == "1") {
          if (item.count > 5000000) {
            item.value = 28;
            padding = [10, 10];
            offsetY = 8;

            let colori = parseInt((Math.random() * 7) as any);
            color = bigColor[colori];
          } else {
            item.value = 16;
            padding = [4, 10];
            offsetY = 4;
          }
        } else {
          item.value = 60;
          padding = [17, 10];
          offsetY = 20;
          if (linksCountMap[item.id].length > 3) {
            offsetY = 0;
          }
        }

        Object.assign(item, {
          level: item.level,
          nodeWidth: 270,
          label: {
            offset: [0, -offsetY],
            width: 247,
            show: true,
            position: "inside",
            padding: padding,
            borderColor: color,
            borderWidth: 1,
            borderRadius: 4,
            borderType: "solid",
            backgroundColor: color,
            fontSize: item.level == "1" ? 12 : 20,
            formatter(e: any) {
              if (item.level == "1") {
                return `{a|${e.data.name}}{b|${e.data.count}}`;
              } else {
                return `{c|${e.data.name}}\n{d|${e.data.count}}`;
              }
            },
          },
        });
      });
      const option = {
        series: [
          {
            type: "sankey",
            left: 20,
            top: 20,
            right: 20,
            bottom: 20,
            data: data,
            links: links,
            nodeWidth: 270,
            draggable: false,
            focusNodeAdjacency: "allEdges",
            lineStyle: {
              color: "source",
              curveness: 0.5,
            },
            itemStyle: {
              color: "transparent",
              borderColor: "transparent",
            },
            label1: {
              position: "inside",
              fontSize: 12,
              color: "#666",
              formatter: function (params: any) {
                let { data } = params;
                return data.name;
              },
            },
            label: {
              position: "inside",
              show: true,
              color: "#fff",
              fontSize: 12,
              rich: {
                a: {
                  width: 200,
                  align: "left",
                  color: "#fff",
                },
                b: {
                  color: "#fff",
                  align: "right",
                },
                c: {
                  width: 200,
                  fontSize: 24,
                  align: "center",
                },
                d: {
                  fontSize: 24,
                  align: "center",
                },
              },
            },
          },
        ],
        tooltip: {
          trigger: "item",
        },
      };

      echartsOptions.value = option;
    }

 最终的效果图:

 

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在echarts桑基图中使用动态数据,你可以按照以下步骤进行操作: 1. 首先,引入echarts库和桑基图组件。你可以使用如下代码在组件中引入: ```javascript const echarts = require('echarts5/lib/echarts'); require('echarts/lib/chart/sankey'); ``` 2. 在main.js文件中注册echarts。你可以使用如下代码进行注册: ```javascript import * as echarts5 from 'echarts5'; Vue.use(echarts5); ``` 3. 在组件的mounted生命周期钩子函数中,定义option对象,并配置图表的参数。你可以使用如下代码进行配置: ```javascript onMounted(() => { const myChart = echarts.init(chart.value); const option = { title: { text: '人口迁移桑基图', left: 'center', textStyle: { color: '#333', fontSize: 20, fontWeight: 'bold', }, }, tooltip: { trigger: 'item', triggerOn: 'mousemove', }, series: [ { type: 'sankey', data: nodes.map(n => ({ name: n })), links: data.map(d => ({ source: d.source, target: d.target, value: d.value })), lineStyle: { opacity: 0.5, curveness: 0.3, }, label: { position: 'right', color: '#000', }, emphasis: { focus: 'adjacency', itemStyle: { borderWidth: 2, borderColor: '#333', }, }, }, ], }; myChart.setOption(option); }); ``` 这样,你就可以在echarts桑基图中使用动态数据。只需将数据传递给`nodes`和`data`变量即可。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [echarts 桑基图](https://blog.csdn.net/lance_heart/article/details/126195333)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [极致呈现系列之:Echarts桑基图的流动旋律](https://blog.csdn.net/w137160164/article/details/131341100)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值