如何与JavaScript切换HighCharts Sankey链接

发布于 2025-02-05 14:09:28 字数 3811 浏览 4 评论 0原文

如何切换可见的Sankey链接(以及节点和标签)? 我希望用户通过单击节点来逐步扩展节点。完全扩展时,该图将具有Ca 5级别和CA 10列。第一个负载上的默认视图显示约6列和4个级别。

  1. 我可以操纵数据并将重量设置为0,以隐藏所有3个(节点,链接,标签)。
  2. 3个工作?
  3. 我可以在节点上添加一个className并使用“显示:无”(对所有 -Chart-toggle-visibily of节点“>有关组织图表的问题。我可以适应Sankey的解决方案吗?

我尝试了第一个选项。它运行良好 - 隐藏所有3个(节点,链接,标签)。但是,为了使其正常工作,我需要每次查询数据库,然后重新绘制(重新加载)图表。我正在做API电话并操纵JSON。不是太多的API呼叫还是有更好的方法可以这样做?

与第三次相比,第二个选项看起来更清楚,因为我比HighCharts.js了解更多的CSS。 (尽管我倾向于避免级联样式:)

第三选项似乎很乏味,因为我需要找出这些库的工作方式。但是也许这是一个很好的解决方案,那么我对投资时间毫无疑问。不过,给定的例子不是很好。

避免开发和自定义,功能,导出。,响应式设计等问题的最佳解决方案是什么?

这是所需视图的小提琴: link

var nodes = [{
    id: 'Col_1-Row_1',
    column: 1
  }, ],
  data0 = [
    // default - data is set to 0 - link is hidden
    ['Col_0-Row_0', 'Col_1-Row_0', 0],
    ['Col_0-Row_1', 'Col_1-Row_0', 0],
    // data to display
    ['Col_1-Row_0', 'Col_2-Row_0', 153],
    ['Col_1-Row_1', 'Col_2-Row_0', 91],
    ['Col_1-Row_1', 'Col_2-Row_0', 221],
    ['Col_1-Row_1', 'Col_2-Row_0', 200],
    //  circulra link
    ['Col_2-Row_0', 'Col_1-Row_1', 10],
  ],
  data1 = [
    ['Col_0-Row_0', 'Col_1-Row_0', 0.1],
    ['Col_0-Row_1', 'Col_1-Row_0', 152.9],
    ['Col_1-Row_0', 'Col_2-Row_0', 153],
    ['Col_1-Row_1', 'Col_2-Row_0', 91],
    ['Col_1-Row_1', 'Col_2-Row_0', 221],
    ['Col_1-Row_1', 'Col_2-Row_0', 200],
    ['Col_2-Row_0', 'Col_1-Row_1', 10],
  ]

const chart = Highcharts.chart('container', {
  chart: {

    height: (9 / 16 * 80) + "%",
    marginBottom: 60, // display circulra link
    marginRight: 60 // display circulra link
  },
  title: {
    text: 'Sankey toggle link visibilty'
  },
  plotOptions: {
    series: {
      animation: false,
      minLinkWidth: 1,
      nodePadding: 50,
      colors: ['#0dcaf0'],
      clip: false, // display circulra link
      dataLabels: {
        enabled: true,

        // set data label position
        align: "left",
        verticalAlign: "top",
        y: -20,
        x: -5,

        // show data labels taht overlap
        allowOverlap: true,
        padding: 0,

        // handle data labels that flow outside the plot area
        overflow: "allow",
        crop: false,

        style: {
          fontSize: "12px",
          fontFamily: "Arial, sans-serif",
          color: "black",
        },
      },
    },
  },
  series: [{
    data: data0,
    nodes: nodes,
    type: 'sankey',
  }, {
    data: data1,
    nodes: nodes,
    visible: false,
    type: 'sankey',
  }]
});
#container {
  height: 90hw;
  margin: 1em auto;
}
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/sankey.src.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://code.highcharts.com/modules/accessibility.js"></script>

<button id="btn_show" class="autocompare">expand</button>
<button id="btn_hide" class="autocompare">hide</button>
<div id="container"></div>


<script>
  document.getElementById('btn_show').addEventListener('click', e => {
    seriesHide();
    seriesShow(1);
  });
  document.getElementById('btn_hide').addEventListener('click', e => {
    seriesHide();
    seriesShow(0);
  });

  function seriesHide() {
    chart.series.forEach(ser => ser.hide())
  }

  function seriesShow(i) {
    var series = chart.series[i];
    series.show();
  }
</script>

How can I toggle visible the Sankey link (together with the node and label)?
I want users to expand nodes step by step by clicking on the node. The diagram would have ca 5 levels and ca 10 columns when fully expanded. Default view on the first load is showing about 6 columns and 4 levels.

  1. I could manipulate the data and set the weight to 0 to hide all 3 of them (node,link,label).
  2. I could add a className to the node and use 'display:none' (Would it work for all 3 of them?)
  3. Here is a similar question about organization chart. Can I adapt the solution to Sankey?

I've tried out the 1st option. It works well - hiding all 3 of them(node,link,label). Though, to make it to work, I need to query the database every time and redraw (reload) the chart. I'm doing API call and manipulating the json. Isn't it too many API calls or there is a better way to do it?

The 2nd option looks more clear compared to the 3rd, because I know more CSS than highcharts.js. (Though I tend to avoid the cascading styles:)

The 3rd option seems tedious, because I need to find out how these libraries are working. But maybe it's a good solution, then I have no doubts about investing time. Though, the given example was not very well working.

What would be the best solution to avoid problems with dev and customisation, functionalities, export.js, responsive design, etc?

Here is the fiddle of the desired view : link

var nodes = [{
    id: 'Col_1-Row_1',
    column: 1
  }, ],
  data0 = [
    // default - data is set to 0 - link is hidden
    ['Col_0-Row_0', 'Col_1-Row_0', 0],
    ['Col_0-Row_1', 'Col_1-Row_0', 0],
    // data to display
    ['Col_1-Row_0', 'Col_2-Row_0', 153],
    ['Col_1-Row_1', 'Col_2-Row_0', 91],
    ['Col_1-Row_1', 'Col_2-Row_0', 221],
    ['Col_1-Row_1', 'Col_2-Row_0', 200],
    //  circulra link
    ['Col_2-Row_0', 'Col_1-Row_1', 10],
  ],
  data1 = [
    ['Col_0-Row_0', 'Col_1-Row_0', 0.1],
    ['Col_0-Row_1', 'Col_1-Row_0', 152.9],
    ['Col_1-Row_0', 'Col_2-Row_0', 153],
    ['Col_1-Row_1', 'Col_2-Row_0', 91],
    ['Col_1-Row_1', 'Col_2-Row_0', 221],
    ['Col_1-Row_1', 'Col_2-Row_0', 200],
    ['Col_2-Row_0', 'Col_1-Row_1', 10],
  ]

const chart = Highcharts.chart('container', {
  chart: {

    height: (9 / 16 * 80) + "%",
    marginBottom: 60, // display circulra link
    marginRight: 60 // display circulra link
  },
  title: {
    text: 'Sankey toggle link visibilty'
  },
  plotOptions: {
    series: {
      animation: false,
      minLinkWidth: 1,
      nodePadding: 50,
      colors: ['#0dcaf0'],
      clip: false, // display circulra link
      dataLabels: {
        enabled: true,

        // set data label position
        align: "left",
        verticalAlign: "top",
        y: -20,
        x: -5,

        // show data labels taht overlap
        allowOverlap: true,
        padding: 0,

        // handle data labels that flow outside the plot area
        overflow: "allow",
        crop: false,

        style: {
          fontSize: "12px",
          fontFamily: "Arial, sans-serif",
          color: "black",
        },
      },
    },
  },
  series: [{
    data: data0,
    nodes: nodes,
    type: 'sankey',
  }, {
    data: data1,
    nodes: nodes,
    visible: false,
    type: 'sankey',
  }]
});
#container {
  height: 90hw;
  margin: 1em auto;
}
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/sankey.src.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://code.highcharts.com/modules/accessibility.js"></script>

<button id="btn_show" class="autocompare">expand</button>
<button id="btn_hide" class="autocompare">hide</button>
<div id="container"></div>


<script>
  document.getElementById('btn_show').addEventListener('click', e => {
    seriesHide();
    seriesShow(1);
  });
  document.getElementById('btn_hide').addEventListener('click', e => {
    seriesHide();
    seriesShow(0);
  });

  function seriesHide() {
    chart.series.forEach(ser => ser.hide())
  }

  function seriesShow(i) {
    var series = chart.series[i];
    series.show();
  }
</script>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

如果没结果 2025-02-12 14:09:28

我根据So的帖子准备了一个演示,隐藏的分支似乎是一个很好的方法。

Highcharts.chart('container', {
  chart: {
    events: {
      load() {
        //hide nodes after initial load
        let chart = this,
          nodes = chart.series[0].nodeLookup;

        for (let i in nodes) {
          if (nodes[i].column > 1) {
            nodes[i].graphic.hide();
            nodes[i].dataLabel.hide();
            nodes[i].linksTo[0].graphic.hide();
            nodes[i].visible = false;
          }
        }
      }
    }
  },
  title: {
    text: 'Highcharts Sankey Diagram'
  },
  accessibility: {
    point: {
      valueDescriptionFormat: '{index}. {point.from} to {point.to}, {point.weight}.'
    }
  },
  series: [{
    keys: ['from', 'to', 'weight'],
    data: [
      ['Brazil', 'Portugal', 5],
      ['Brazil', 'France', 1],
      ['Brazil', 'Spain', 1],
      ['Brazil', 'England', 1],
      ['Canada', 'Portugal', 1],
      ['Canada', 'France', 5],
      ['Canada', 'England', 1],
      ['Mexico', 'Portugal', 1],
      ['Mexico', 'France', 1],
      ['Mexico', 'Spain', 5],
      ['Mexico', 'England', 1],
      ['USA', 'Portugal', 1],
      ['USA', 'France', 1],
      ['USA', 'Spain', 1],
      ['USA', 'England', 5],
      ['Portugal', 'Angola', 2],
      ['Portugal', 'Senegal', 1],
      ['Portugal', 'Morocco', 1],
      ['Portugal', 'South Africa', 3],
    ],
    type: 'sankey',
    name: 'Sankey demo series',
    nodes: [{
      id: 'Brazil',
    }, {
      id: 'Portugal',
      events: {
        click() {
          //show nodes
          let series = this.series,
            nodes = series.nodeLookup;

          for (let i in nodes) {
            if (nodes[i].id === "Portugal") {
              if (nodes[i].visible) {
                nodes[i].graphic.hide()
                nodes[i].dataLabel.hide();
                nodes[i].visible = false;
              } else {
                nodes[i].graphic.show()
                nodes[i].dataLabel.show();
                nodes[i].visible = true;
              }

            }
          }
          this.linksFrom.forEach(link => {
            if (link.graphic.visibility == "visible") {
              link.graphic.hide()

            } else {
              link.graphic.show()
            }
          })
        }
      }
    }, {
      id: 'Mexico',
    }, {
      id: 'France',
    }],
  }]

});
#csv {
    display: none;
}

.highcharts-figure,
.highcharts-data-table table {
    min-width: 310px;
    max-width: 800px;
    margin: 1em auto;
}

.highcharts-data-table table {
    font-family: Verdana, sans-serif;
    border-collapse: collapse;
    border: 1px solid #ebebeb;
    margin: 10px auto;
    text-align: center;
    width: 100%;
    max-width: 500px;
}

.highcharts-data-table caption {
    padding: 1em 0;
    font-size: 1.2em;
    color: #555;
}

.highcharts-data-table th {
    font-weight: 600;
    padding: 0.5em;
}

.highcharts-data-table td,
.highcharts-data-table th,
.highcharts-data-table caption {
    padding: 0.5em;
}

.highcharts-data-table thead tr,
.highcharts-data-table tr:nth-child(even) {
    background: #f8f8f8;
}

.highcharts-data-table tr:hover {
    background: #f1f7ff;
}
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/sankey.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://code.highcharts.com/modules/export-data.js"></script>
<script src="https://code.highcharts.com/modules/accessibility.js"></script>

<figure class="highcharts-figure">
    <div id="container"></div>
    <p class="highcharts-description">
        Sankey charts are used to visualize data flow and volume
        between nodes. The wider lines indicate larger volumes.
    </p>
</figure>

httpps://jsfiddle.net.net/blacklabel/blacklabel/blacklabel/blacklabel/sm01jtof/1/

演示

使用 update 方法。

演示:

I prepared a demo based on a post from SO, hiding branches seems to be a good approach.

Highcharts.chart('container', {
  chart: {
    events: {
      load() {
        //hide nodes after initial load
        let chart = this,
          nodes = chart.series[0].nodeLookup;

        for (let i in nodes) {
          if (nodes[i].column > 1) {
            nodes[i].graphic.hide();
            nodes[i].dataLabel.hide();
            nodes[i].linksTo[0].graphic.hide();
            nodes[i].visible = false;
          }
        }
      }
    }
  },
  title: {
    text: 'Highcharts Sankey Diagram'
  },
  accessibility: {
    point: {
      valueDescriptionFormat: '{index}. {point.from} to {point.to}, {point.weight}.'
    }
  },
  series: [{
    keys: ['from', 'to', 'weight'],
    data: [
      ['Brazil', 'Portugal', 5],
      ['Brazil', 'France', 1],
      ['Brazil', 'Spain', 1],
      ['Brazil', 'England', 1],
      ['Canada', 'Portugal', 1],
      ['Canada', 'France', 5],
      ['Canada', 'England', 1],
      ['Mexico', 'Portugal', 1],
      ['Mexico', 'France', 1],
      ['Mexico', 'Spain', 5],
      ['Mexico', 'England', 1],
      ['USA', 'Portugal', 1],
      ['USA', 'France', 1],
      ['USA', 'Spain', 1],
      ['USA', 'England', 5],
      ['Portugal', 'Angola', 2],
      ['Portugal', 'Senegal', 1],
      ['Portugal', 'Morocco', 1],
      ['Portugal', 'South Africa', 3],
    ],
    type: 'sankey',
    name: 'Sankey demo series',
    nodes: [{
      id: 'Brazil',
    }, {
      id: 'Portugal',
      events: {
        click() {
          //show nodes
          let series = this.series,
            nodes = series.nodeLookup;

          for (let i in nodes) {
            if (nodes[i].id === "Portugal") {
              if (nodes[i].visible) {
                nodes[i].graphic.hide()
                nodes[i].dataLabel.hide();
                nodes[i].visible = false;
              } else {
                nodes[i].graphic.show()
                nodes[i].dataLabel.show();
                nodes[i].visible = true;
              }

            }
          }
          this.linksFrom.forEach(link => {
            if (link.graphic.visibility == "visible") {
              link.graphic.hide()

            } else {
              link.graphic.show()
            }
          })
        }
      }
    }, {
      id: 'Mexico',
    }, {
      id: 'France',
    }],
  }]

});
#csv {
    display: none;
}

.highcharts-figure,
.highcharts-data-table table {
    min-width: 310px;
    max-width: 800px;
    margin: 1em auto;
}

.highcharts-data-table table {
    font-family: Verdana, sans-serif;
    border-collapse: collapse;
    border: 1px solid #ebebeb;
    margin: 10px auto;
    text-align: center;
    width: 100%;
    max-width: 500px;
}

.highcharts-data-table caption {
    padding: 1em 0;
    font-size: 1.2em;
    color: #555;
}

.highcharts-data-table th {
    font-weight: 600;
    padding: 0.5em;
}

.highcharts-data-table td,
.highcharts-data-table th,
.highcharts-data-table caption {
    padding: 0.5em;
}

.highcharts-data-table thead tr,
.highcharts-data-table tr:nth-child(even) {
    background: #f8f8f8;
}

.highcharts-data-table tr:hover {
    background: #f1f7ff;
}
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/sankey.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script src="https://code.highcharts.com/modules/export-data.js"></script>
<script src="https://code.highcharts.com/modules/accessibility.js"></script>

<figure class="highcharts-figure">
    <div id="container"></div>
    <p class="highcharts-description">
        Sankey charts are used to visualize data flow and volume
        between nodes. The wider lines indicate larger volumes.
    </p>
</figure>

Demo: https://jsfiddle.net/BlackLabel/sm01jtof/1/

EDIT

Updated demo to show/hide nodes in sankey graph using update method.

Demo: https://jsfiddle.net/BlackLabel/80ruyxdq/4/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文