Highcharts Symbols Inverted Axis

As I sit here and write this article to help others, I wonder if my efforts were based on my inability to let things go or an uncontrollable urge to get this right? I think a little of both would suffice the question just asked.

I will admit that this answer starts with this link and eventually leads to me discovering how to set attributes based on other attributes being set. How I arrived at the solution was more of me adapting to what was not working. For most of the time I was just trying to get the icons to render, then getting the icons to render vertically and eventually trying to figure out how to get the icons to show properly once the chart redrew itself. I Googled quite hard in seeing what other people were doing as well as stumbling along other links which explained my issue.

So lets get down to the business of properly displaying a font awesome icon inside of a Highchart element.

First we must extend the SVGRenderer symbol method


/*
This experiment explores how to use FontAwesome iconic fonts as markers in Highcharts. Three steps are required:

1. Supply the plugin code below to handle text symbols.
2. In each series' marker.symbol setting, add the font icon as Unicode string on the format 
   "text:\uf182". The Unicode corresponding to icons can be found at 
   https://github.com/FortAwesome/Font-Awesome/blob/master/less/variables.less

Compatibility notes:
- IE6, 7, and 8 don't support rgba colors (fall back to solid rgb)
*/

/* Highcharts plugin to handle text symbols */
(function (H) {
    function symbolWrap(proceed, symbol, x, y, w, h, options) {
        if (symbol.indexOf('text:') === 0) {
            var text = symbol.split(':')[1],
                svgElem = this.text(text, x, y)
            .attr({
            	translateY: h,
                translateX: -1
            })
                .css({
                    fontFamily: 'FontAwesome',
                    fontSize: h * 2
                });
            
            if (svgElem.renderer.isVML) {
                svgElem.fillSetter = function (value, key, element) {
                    element.style.color = H.Color(value).get('rgb');
                };
            }
            return svgElem;
        }
        return proceed.apply(this, [].slice.call(arguments, 1));
    }
    H.wrap(H.SVGRenderer.prototype, 'symbol', symbolWrap);
    if (H.VMLRenderer) {
        H.wrap(H.VMLRenderer.prototype, 'symbol', symbolWrap);
    }
    
    // Load the font for SVG files also
    H.wrap(H.Chart.prototype, 'getSVG', function (proceed) {
        var svg = proceed.call(this);
        svg = '' + 
            svg;
        return svg;
    });
}(Highcharts));

Next we need to add proper translation and rotation whenever this chart resizes. This is important as once the chart redraws itself the icons will be moved to it’s new location based on the final size of the chart. We used the little know class of MutationObserver to take care of placing the icon appropriately.


var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;

var height = (h/2) + y;
var width = (w/2) + x;
var transformParams = “translate(-1, ” + h + “) rotate(90 ” + width + ” ” + height + “)”;

svgElem.element.setAttribute(“transform”, transformParams);

var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
        if(mutation.target.style.fontFamily === ‘FontTW’) {
            var element = mutation.target;
            var x = parseInt(element.attributes[‘x’].value);
            var y = parseInt(element.attributes[‘y’].value);
            var params = “translate(-1, ” + parseInt(element.attributes[‘height’].value) + “) rotate(90 ” + x + ” ” + y + “)”;
            
            mutation.target.setAttribute(“transform”, params);
        }
    });
});

observer.observe(svgElem.element, {
    attributeFilter: [‘x’, ‘y’] //configure it to listen to attribute changes
});

When we put everything together we end up with this script


/*
This experiment explores how to use FontAwesome iconic fonts as markers in Highcharts. Three steps are required:

1. Supply the plugin code below to handle text symbols.
2. In each series’ marker.symbol setting, add the font icon as Unicode string on the format
  “text:\uf182”. The Unicode corresponding to icons can be found at
  https://github.com/FortAwesome/Font-Awesome/blob/master/less/variables.less

Compatibility notes:
- IE6, 7, and 8 don’t support rgba colors (fall back to solid rgb)
*/

/* Highcharts plugin to handle text symbols */
(function (H) {
   function symbolWrap(proceed, symbol, x, y, w, h, options) {
       var test = proceed.apply(this, [].slice.call(arguments, 1));
       var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;

       if (symbol.indexOf(‘text:‘) === 0) {
           var text = symbol.split(‘:’)[1],
               svgElem = this.text(text, x, y + h)
               .attr({
                   translateY: h,
                   translateX: -1
               })
               .css({
                   fontFamily: ‘FontTW’,
                   fontSize: h * 2 + “px”
               });

           var height = (h/2) + y;
           var width = (w/2) + x;
           var transformParams = “translate(-1, ” + h + “) rotate(90 ” + width + ” ” + height + “)”;

           svgElem.element.setAttribute(“transform”, transformParams);

           var observer = new MutationObserver(function(mutations) {
             mutations.forEach(function(mutation) {
               if(mutation.target.style.fontFamily === ‘FontTW’) {
                   var element = mutation.target;
                   var x = parseInt(element.attributes[‘x’].value);
                   var y = parseInt(element.attributes[‘y’].value);
                   var params = “translate(-1, ” + parseInt(element.attributes[‘height’].value) + “) rotate(90 ” + x + ” ” + y + “)”;

                   mutation.target.setAttribute(“transform”, params);
               }
             });
           });

           observer.observe(svgElem.element, {
             attributeFilter: [‘x’, ‘y’] //configure it to listen to attribute changes
           });

           if (svgElem.renderer.isVML) {
               svgElem.fillSetter = function (value, key, element) {
                   element.style.color = H.Color(value).get(‘rgb’);
               };
           }
           return svgElem;
       }


       return test;
   }
   H.wrap(H.SVGRenderer.prototype, ‘symbol’, symbolWrap);
   if (H.VMLRenderer) {
       H.wrap(H.VMLRenderer.prototype, ‘symbol’, symbolWrap);
   }

   // Load the font for SVG files also
   H.wrap(H.Chart.prototype, ‘getSVG’, function (proceed) {
       var svg = proceed.call(this);
       svg = ‘’ +
           svg;
       return svg;
   });
}(Highcharts));

How long did this take approximately 20 hours of researching, testing and correcting all the intricate details. I hope you can take these code snippets and copy and paste the final result. Although this took me forever and made me question my own abilities as a developer I’m glad that I’m able to share this with the rest of the world until they fix this lowly ranked issue in Highcharts.