title: Create Treemap server-side with jsdom, highcharts
body: <p>I am trying to extract the svg-code from a treemap (type of chart) which is to be generated server-side with nodejs and jsdom.</p>
  
  <p>I have found following code which exports a "line chart" successfully when I run it on my server: <a href="https://gist.github.com/TorsteinHonsi/e8a1e6971608523eb8dd" rel="nofollow">https://gist.github.com/TorsteinHonsi/e8a1e6971608523eb8dd</a></p>
  
  <p>When I change the chart to treemap I get the errors below!</p>
  
  <p>I simply change the code from the line chart to treemap, i.e. i change this</p>
  
  <pre><code>Highcharts.chart('container', {
      chart: {
          forExport: true,
          width: 600,
          height: 400
      },
      xAxis: {
        categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 
          'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
      },
      series: [{
        data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]
      }]
  });
  </code></pre>
  
  <p>to this (found from official treemap example by highcharts: <a href="http://jsfiddle.net/gh/get/jquery/1.9.1/highslide-software/highcharts.com/tree/master/samples/highcharts/demo/treemap-coloraxis/" rel="nofollow">http://jsfiddle.net/gh/get/jquery/1.9.1/highslide-software/highcharts.com/tree/master/samples/highcharts/demo/treemap-coloraxis/</a>)</p>
  
  <pre><code>Highcharts.chart('container', {
       chart: {
          forExport: true,
          width: 600,
          height: 400
      },
      series: [{
          type: 'treemap',
          layoutAlgorithm: 'squarified',
          data: [{
              name: 'A',
              value: 6,
              colorValue: 1
          }, {
              name: 'B',
              value: 6,
              colorValue: 2
          }, {
              name: 'C',
              value: 4,
              colorValue: 3
          }, {
              name: 'D',
              value: 3,
              colorValue: 4
          }, {
              name: 'E',
              value: 2,
              colorValue: 5
          }, {
              name: 'F',
              value: 2,
              colorValue: 6
          }, {
              name: 'G',
              value: 1,
              colorValue: 7
          }]
      }]
  });
  </code></pre>
  
  <p>When I run it with "node myscript.js" I get following errors:</p>
  
  <pre><code>/opt/dlins/node-v6.3.0-linux-x64/bin/node_modules/highcharts/highcharts.js:8
  (function(D,aa){typeof module==="object"&amp;&amp;module.exports?module.exports=D.document?aa(D):aa:D.Highcharts=aa(D)})(typeof window!=="undefined"?window:this,function(D){function aa(a,b){var c="Highcharts error #"+a+": www.highcharts.com/errors/"+a;if(b)throw Error(c);D.console&amp;&amp;console.log(c)}function pb(a,b,c){this.options=b;this.elem=a;this.prop=c}function E(){var a,b=arguments,c,d={},e=function(a,b){var c,d;typeof a!=="object"&amp;&amp;(a={});for(d in b)b.hasOwnProperty(d)&amp;&amp;(c=b[d],a[d]=c&amp;&amp;typeof c==="object"&amp;&amp;
                                                                                                                                                                                                                                                           ^
  
  Error: Highcharts error #17: www.highcharts.com/errors/17
      at Error (native)
      at aa (/opt/dlins/node-v6.3.0-linux-x64/bin/node_modules/highcharts/highcharts.js:8:256)
      at Object.gb.initSeries (/opt/dlins/node-v6.3.0-linux-x64/bin/node_modules/highcharts/highcharts.js:214:242)
      at /opt/dlins/node-v6.3.0-linux-x64/bin/node_modules/highcharts/highcharts.js:236:107
      at Array.forEach (native)
      at p (/opt/dlins/node-v6.3.0-linux-x64/bin/node_modules/highcharts/highcharts.js:25:392)
      at Object.gb.firstRender (/opt/dlins/node-v6.3.0-linux-x64/bin/node_modules/highcharts/highcharts.js:236:78)
      at Object.gb.init (/opt/dlins/node-v6.3.0-linux-x64/bin/node_modules/highcharts/highcharts.js:214:135)
      at Object.gb.getArgs (/opt/dlins/node-v6.3.0-linux-x64/bin/node_modules/highcharts/highcharts.js:213:57)
      at Object.x.Chart (/opt/dlins/node-v6.3.0-linux-x64/bin/node_modules/highcharts/highcharts.js:212:378)
  </code></pre>
  
  <p>My complete script which produces errors is this:</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>/**
   * Sample of serverside generation of Highcharts using an extension to jsdom in node.js.
   *
   * Usage: 
   * npm install jsdom
   * npm install highcharts
   * node highcharts-jsdom
   */
  
  /* eslint-env node */
  /* eslint no-console: 0 */
  var jsdom = require('jsdom'),
      fs = require('fs');
  
  // Get the document and window
  var doc = jsdom.jsdom('&lt;!doctype html&gt;&lt;html&gt;&lt;body&gt;&lt;div id="container"&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;'),
      win = doc.defaultView;
  
  // Do some modifications to the jsdom document in order to get the SVG bounding
  // boxes right.
  doc.createElementNS = function (ns, tagName) {
      var elem = doc.createElement(tagName);
  
      // Set private namespace to satisfy jsdom's getter
      elem._namespaceURI = ns; // eslint-disable-line no-underscore-dangle
      /**
       * Pass Highcharts' test for SVG capabilities
       * @returns {undefined}
       */
      elem.createSVGRect = function () {};
      /**
       * jsdom doesn't compute layout (see https://github.com/tmpvar/jsdom/issues/135).
       * This getBBox implementation provides just enough information to get Highcharts
       * to render text boxes correctly, and is not intended to work like a general
       * getBBox implementation. The height of the boxes are computed from the sum of
       * tspans and their font sizes. The width is based on an average width for each glyph.
       * It could easily be improved to take font-weight into account.
       * For a more exact result we could to create a map over glyph widths for several
       * fonts and sizes, but it may not be necessary for the purpose.
       * @returns {Object} The bounding box
       */
      elem.getBBox = function () {
          var lineWidth = 0,
              width = 0,
              height = 0;
  
          [].forEach.call(elem.children.length ? elem.children : [elem], function (child) {
              var fontSize = child.style.fontSize || elem.style.fontSize,
                  lineHeight,
                  textLength;
  
              // The font size and lineHeight is based on empirical values, copied from
              // the SVGRenderer.fontMetrics function in Highcharts.
              if (/px/.test(fontSize)) {
                  fontSize = parseInt(fontSize, 10);
              } else {
                  fontSize = /em/.test(fontSize) ? parseFloat(fontSize) * 12 : 12;
              }
              lineHeight = fontSize &lt; 24 ? fontSize + 3 : Math.round(fontSize * 1.2);
              textLength = child.textContent.length * fontSize * 0.55;
  
              // Tspans on the same line
              if (child.getAttribute('dx') !== '0') {
                  height += lineHeight;
              }
  
              // New line
              if (child.getAttribute('dy') !== null) {
                  lineWidth = 0;
              }
  
              lineWidth += textLength;
              width = Math.max(width, lineWidth);
  
          });
  
          return {
              x: 0,
              y: 0,
              width: width,
              height: height
          };
      };
      return elem;
  };
  
  // Require Highcharts with the window shim
  var Highcharts = require('highcharts')(win);
  
  // Disable all animation
  Highcharts.setOptions({
      plotOptions: {
          series: {
              animation: false,
              dataLabels: {
                  defer: false
              }
          }
      }
  });
  
  // Generate the chart into the container
  /*
  // Working simple line chart
  Highcharts.chart('container', {
      chart: {
    forExport: true,
    width: 600,
    height: 400
   },
   xAxis: {
     categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 
    'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
   },
   series: [{
     data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]
   }]
  });
  */
  
  //not working treemap
  // http://jsfiddle.net/gh/get/jquery/1.9.1/highslide-software/highcharts.com/tree/master/samples/highcharts/demo/treemap-coloraxis/
  Highcharts.chart('container', {
    chart: {
    forExport: true,
    width: 600,
    height: 400
   },
   series: [{
    type: 'treemap',
    layoutAlgorithm: 'squarified',
    data: [{
     name: 'A',
     value: 6,
     colorValue: 1
    }, {
     name: 'B',
     value: 6,
     colorValue: 2
    }, {
     name: 'C',
     value: 4,
     colorValue: 3
    }, {
     name: 'D',
     value: 3,
     colorValue: 4
    }, {
     name: 'E',
     value: 2,
     colorValue: 5
    }, {
     name: 'F',
     value: 2,
     colorValue: 6
    }, {
     name: 'G',
     value: 1,
     colorValue: 7
    }]
   }]
  });
  
  var svg = win.document.getElementById('container').innerHTML;
  fs.writeFile('chart.svg', svg, function () {
      console.log('Wrote ' + svg.length + ' bytes to ' + __dirname + '/chart.svg.'); // eslint-disable-line no-path-concat
  });</code></pre>
  </div>
  </div>
  </p>