JavaScript Hierarchy Chart

JavaScript Hierarchy Chart
Project: Organization Chart POC
Author: Jane Harrison
Edit Online: View on CodePen
License: MIT

This code snippet helps you to create a hierarchy chart. It provides a code defining the plot options for a Highcharts chart. Specifically, it is defining the behavior of the series in the chart. The code is setting an event listener for the afterAnimate event on each series. When this event is triggered, the function provided will execute. Within this function, it first gets all of the data label elements for the current series and converts them to an array. It then iterates over the array of data labels to determine the maximum x position of the nodes in the series. It does this by filtering the SVG elements for all <rect> elements, which it assumes are the nodes, and then getting the bounding box of each <rect> element.

Finally, the function then positions a label indicating the hierarchy level of the nodes to the right of the nodes, and adds it to the chart using the Highcharts renderer.

How to Create JavaScript Hierarchy Chart

Create the HTML structure for the hierarchy chart as follows:

<script src="https://code.highcharts.com/stock/highstock.js"></script>
<script src="https://code.highcharts.com/modules/sankey.js"></script>
<script src="https://code.highcharts.com/modules/organization.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>

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

Now, style the hierarchy chart using the following CSS styles:

.item{
width: 100%;
height: 100%;
}
#container {
  min-width: 1500px;
  border: 1px solid silver;
  overflow: scroll !important;
  float: left;
  width: 800px;
  height: 500px;
}

.labels {
  float: left;
  width: 600px;
  font-size: 14px;
  position: relative;
  height: 600px;
}
.labels .label {
  position: absolute;
}

#container h4 {
  text-transform: none;
  font-size: 14px;
  font-weight: normal;
}

#container p {
  font-size: 13px;
  line-height: 16px;
}

Finally, add the following JavaScript function:

// (function(H) {
//   H.wrap(H.Series.prototype, 'drawDataLabels', function(p) {
//     // fire default drawDataLabels()
//     p.apply(this, arguments);
//     // fire custom code right after drawDataLabels() (instead of firing an event)
//     console.log(this);
//     this.points.forEach(function(point) {
//       var test = point;
//     });
//   });
// })(Highcharts);

Highcharts.chart('container', {

  chart: {
    height: 600,
    width: 800,
    inverted: true
  },

  title: {
    text: 'Highcharts Org Chart'
  },

  series: [{
    type: 'organization',
    name: 'Highsoft',
    keys: ['from', 'to'],
    data: [
      ['Shareholders', 'Board'],
      ['Board', 'CEO'],
      ['CEO', 'CTO'],
      ['CEO', 'CPO'],
      ['CEO', 'CSO'],
      ['CEO', 'CMO'],
      ['CEO', 'HR'],
      ['CTO', 'Product'],
      ['CTO', 'Web'],
      ['CSO', 'Sales'],
      ['CMO', 'Market']
    ],
    levels: [{
      level: 0,
      color: 'silver',
      dataLabels: {
        color: 'black'
      },
      height: 25
    }, {
      level: 1,
      color: 'silver',
      dataLabels: {
        color: 'black'
      },
      height: 25
    }, {
      level: 2,
      color: '#980104'
    }, {
      level: 4,
      color: '#359154'
    }],
    nodes: [{
      id: 'Shareholders'
    }, {
      id: 'Board'
    }, {
      id: 'CEO',
      title: 'CEO',
      name: 'Grethe Hjetland',
      image: 'https://wp-assets.highcharts.com/www-highcharts-com/blog/wp-content/uploads/2018/11/12132317/Grethe.jpg'
    }, {
      id: 'HR',
      title: 'HR/CFO',
      name: 'Anne Jorunn Fjærestad',
      color: '#007ad0',
      image: 'https://wp-assets.highcharts.com/www-highcharts-com/blog/wp-content/uploads/2018/11/12132314/AnneJorunn.jpg',
      column: 3,
      offset: '75%'
    }, {
      id: 'CTO',
      title: 'CTO',
      name: 'Christer Vasseng',
      column: 4,
      image: 'https://wp-assets.highcharts.com/www-highcharts-com/blog/wp-content/uploads/2018/11/12140620/Christer.jpg',
      layout: 'hanging'
    }, {
      id: 'CPO',
      title: 'CPO',
      name: 'Torstein Hønsi',
      column: 4,
      image: 'https://wp-assets.highcharts.com/www-highcharts-com/blog/wp-content/uploads/2018/11/12131849/Torstein1.jpg'
    }, {
      id: 'CSO',
      title: 'CSO',
      name: 'Anita Nesse',
      column: 4,
      image: 'https://wp-assets.highcharts.com/www-highcharts-com/blog/wp-content/uploads/2018/11/12132313/Anita.jpg',
      layout: 'hanging'
    }, {
      id: 'CMO',
      title: 'CMO',
      name: 'Vidar Brekke',
      column: 4,
      image: 'https://wp-assets.highcharts.com/www-highcharts-com/blog/wp-content/uploads/2018/11/13105551/Vidar.jpg',
      layout: 'hanging'
    }, {
      id: 'Product',
      name: 'Product developers'
    }, {
      id: 'Web',
      name: 'General tech',
      description: 'Web developers, sys admin'
    }, {
      id: 'Sales',
      name: 'Sales team'
    }, {
      id: 'Market',
      name: 'Marketing team'
    }],
    colorByPoint: false,
    color: '#007ad0',
    dataLabels: {
      color: 'white'
    },
    borderColor: 'white',
    nodeWidth: 65
  }],
  tooltip: {
    outside: true
  },
  exporting: {
    allowHTML: true,
    sourceWidth: 800,
    sourceHeight: 600
  },
  
    plotOptions: {
        series: {
            events: {
                afterAnimate: function () {
                  const labelsCollection = this.dataLabelsGroup.div.children;
                  const labelsArray = [...labelsCollection];
                  let maxX = 0;
                  let widthAtMaxX = 0;
                  
                  if (labelsArray){
                    let i = 0;
                    const self = this;
                    
                    // Get max x position of node
                    const svgGroupCollection = this.group.element.children;
                    const svgGroupArray = [...svgGroupCollection]
                    
                    const rectArray = svgGroupArray.filter(function(svgItem) {
	return svgItem.nodeName == 'rect';
});
                    
                    rectArray.forEach(function(rect) {
                      
                      const boundingBox = rect.getBoundingClientRect();
                      
                      if (maxX < boundingBox.x){
                        maxX = boundingBox.x;
                        widthAtMaxX = boundingBox.width;
                      }
                    });
                    
                    const xPosOfLevelLabel = maxX + widthAtMaxX + 50; // 50 = space between end of last label and lierarchy level label
                    let previousY = 0;
                    
                    labelsArray.forEach(function(label) {
                      let h4Label = label.querySelector('h4');
                      //if (i === 0){
                        const boundingBox = h4Label.getBoundingClientRect();
                      
                      if (previousY < boundingBox.y){
                        self.chart.renderer.label('Level Description', 700, boundingBox.top-15) // would need to calc y pos properly
                        .attr({
                            padding: 10,
                            fill: Highcharts.getOptions().colors[3]
                        })
                        .css({
                            color: 'white'
                        })
                        .add();
                        
                        previousY = boundingBox.y;
                      }
                                               
                        
                        
//                       }else if (i === 1){
                        
//                       }
//                       i++;
                    });
                  }
                }
            }
        }
    },

});

That’s all! hopefully, you have successfully created the JavaScript hierarchy chart. If you have any questions or suggestions, feel free to comment below.

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *