echarts画桑基图,并根据选择的分析因子画图

发布时间 2023-12-20 11:25:31作者: carol2014

最近要在系统中增加一个桑基图,要求桑基图可以根据选择的分析因子重新绘图。

仔细看了下echarts的示例,桑基图本身很简单,困难的是如何根据数据资料整理成桑基图的数据格式,并且实现选择分析因子重新绘图。

研究了几天的数据资料,特将方法写个demo记录下。

<script src="./plugins/echarts.min.js"></script>
<div>
  <label><input type="checkbox" name="factor" value="city" />city</label>
  <label><input type="checkbox" name="factor" value="degree" />degree</label>
  <label><input type="checkbox" name="factor" value="type" />type</label>
  <button onclick="handleSankeyChart()">确定</button>
</div>
<div id="main3" style="height: 400px"></div>
<script>
  const data_orig = [
    { city: "北京", degree: "本科", value: 300, type: "减少" },
    { city: "广州", degree: "硕士", value: 400, type: "增加" },
    { city: "深圳", degree: "硕士", value: 360, type: "增加" },
    { city: "北京", degree: "硕士", value: 250, type: "减少" },
    { city: "上海", degree: "本科", value: 350, type: "减少" },
    { city: "重庆", degree: "本科", value: 300, type: "增加" },
    { city: "深圳", degree: "本科", value: 230, type: "增加" },
  ];

  //统计数据
  const data = {};
  for (let i in data_orig) {
    const key_arr = [];
    for (let key in data_orig[i]) {
      if (key != "value") {
        key_arr.push(data_orig[i][key]);
      }
    }
    const key_str = key_arr.join("|");
    if (!(key_str in data)) data[key_str] = 0;
    data[key_str] += data_orig[i]["value"];
  }
  //数据key中分析因子的顺序,后面可根据此顺序获取对应的值
  const key_order = ["city", "degree", "type"];

  function handleSankeyChart() {
    const params = [];
    document.querySelectorAll("input[name=factor]").forEach((e, i) => {
      if (e.checked) params.push(e.value);
    });

    const data_links_all = [];
    for (let key in data) {
      const key_arr = key.split("|");

      for (let i = 1; i < params.length; i++) {
        const order_index = key_order.indexOf(params[i]);
        const target = key_arr[order_index];
        const source = key_arr[key_order.indexOf(params[i - 1])];

        data_links_all.push({
          source: source,
          target: target,
          value: data[key],
        });
      }
    }

    //links 去掉source=target的项(会报错),合并source和target分别相同的项
    const data_links = [];
    const pairs = [];
    for (let i in data_links_all) {
      const key = data_links_all[i]["source"] + "|" + data_links_all[i]["target"];
      const index = pairs.indexOf(key);
      if (index == -1 && data_links_all[i]["source"] != data_links_all[i]["target"]) {
        pairs.push(key);
        data_links.push(data_links_all[i]);
      } else if (data_links_all[i]["source"] != data_links_all[i]["target"]) {
        data_links[index]["value"] += data_links_all[i]["value"];
      }
    }

    //根据links,组装节点数据
    const data_nodes = [];
    const items = [];
    if (data_links.length > 0) {
      for (let i in data_links) {
        if (items.indexOf(data_links[i]["source"]) === -1) {
          data_nodes.push({
            name: data_links[i]["source"],
          });
          items.push(data_links[i]["source"]);
        }

        if (items.indexOf(data_links[i]["target"]) === -1) {
          data_nodes.push({
            name: data_links[i]["target"],
          });
          items.push(data_links[i]["target"]);
        }
      }
    }

    drawSankeyChart(data_nodes, data_links);
  }

  function drawSankeyChart(data_nodes, data_links) {
    var chartDom = document.getElementById("main3");
    var myChart = echarts.init(chartDom);
    var option;

    option = {
      tooltip: {
        trigger: "item",
        triggerOn: "mousemove",
      },
      series: [
        {
          type: "sankey",
          //严格按照数据节点的顺序显示
          layoutIterations: 0,
          emphasis: {
            focus: "series",
          },
          //定义文本宽度及超出后的换行
          label: {
            width: 100,
            overflow: "break",
          },
          data: data_nodes,
          links: data_links,
        },
      ],
    };
    option && myChart.setOption(option);
  }
</script>

 

实现了如下的效果:

 当桑基图中 layoutIterations 配置项取默认的值32时,echarts会优化图形的显示,减少连线交叉