Network / Force Directed Graph - Highcharts

author(s): Paweł Fus

by jeffersonswartz

HTML

<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/networkgraph.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

<div id="container"></div>

CSS

#container {
  min-width: 320px;
  max-width: 800px;
  margin: 0 auto;
}

JavaScript

// Add the nodes option through an event call. We want to start with the parent
// item and apply separate colors to each child element, then the same color to
// grandchildren.
Highcharts.addEvent(
    Highcharts.seriesTypes.networkgraph,
    'afterSetOptions',
    function (e) {
        var colors = Highcharts.getOptions().colors,
            i = 0,
            nodes = {};
        e.options.data.forEach(function (link) {

            if (link[0] === 'Proto Indo-European') {
                nodes['Proto Indo-European'] = {
                    id: 'Proto Indo-European',
                    marker: {
                        radius: 20
                    }
                };
                nodes[link[1]] = {
                    id: link[1],
                    marker: {
                        radius: 10
                    },
                    color: colors[i++]
                };
            } else if (nodes[link[0]] && nodes[link[0]].color) {
                nodes[link[1]] = {
                    id: link[1],
                    color: nodes[link[0]].color
                };
            }
        });

        e.options.nodes = Object.keys(nodes).map(function (id) {
            return nodes[id];
        });
    }
);

Highcharts.seriesTypes.networkgraph.prototype.pointClass.prototype.remove = function(redraw, animation) {
    var point = this,
      series = point.series,
      dataOptions = series.options.data,
      nodesOptions = series.options.nodes || [],
      links = series.points,
      index,
      i = nodesOptions.length;
  
    // For nodes, remove all connected links:
    if (point.isNode) {
      // Temporrary disable series.points array, beacuse
      // Series.removePoint() modifies it
      series.points = [];
  
      // Remove link from all nodes collections:
      [].concat(point.linksFrom)
        .concat(point.linksTo)
        .forEach(
          function(linkFromTo) {
            // Incoming links
            index =...