Tuesday, February 4, 2014

Running D3 in Node.js on Windows without Python

If you do a quick search on running D3 in Node.js, several great examples show up. Once such example is http://mango-is.com/blog/engineering/pre-render-d3-js-charts-at-server-side.html. Unfortunately, the D3 NPM package has a dependency on the jsdom NPM package, which has a dependency on Contextify, which has a dependency on Python and C++. While this isn't that big of a deal, it does add some complexity to getting setup in a Windows environment. Luckily, there is an NPM package named jsdom-nogyp that removes the dependency on Contextify.

Here are the steps to get that previously mentioned example up and running with jsdom-nogyp:

1. Create a directory for your app and add the D3.min.js file to it.

2. Install the jsdom-nogyp NPM package with the command "npm install jsdom-nogyp".

3. Create a new file named test.js and add the following code within it. This code is basically a merge of the original example and the index.js file from the D3 code-base.

var fs = require('fs')
, jsdom = require('jsdom-nogyp')
, htmlStub = '<html><head></head><body><div id="dataviz-container"></div><script src="./d3.min.js"></script></body></html>'
, document = jsdom.jsdom(htmlStub)
, window = document.createWindow()
, globals = {};
jsdom.env({ features : { QuerySelector : true }, html : htmlStub, done : function(errors, win) {
// stash globals
if ('window' in global) globals.window = global.window;
global.window = window;
if ('document' in global) globals.document = global.document;
global.document = document;
// https://github.com/chad3814/CSSStyleDeclaration/issues/3
var CSSStyleDeclaration_prototype = window.CSSStyleDeclaration.prototype,
CSSStyleDeclaration_setProperty = CSSStyleDeclaration_prototype.setProperty;
CSSStyleDeclaration_prototype.setProperty = function(name, value, priority) {
return CSSStyleDeclaration_setProperty.call(this, name + "", value == null ? null : value + "", priority == null ? null : priority + "");
};
var d3 = require('./d3.min.js');
var el = window.document.querySelector('#dataviz-container')
, body = window.document.querySelector('body')
, circleId = 'a2324';
d3.select(el)
.append('svg:svg')
.attr('width', 600)
.attr('height', 300)
.append('circle')
.attr('cx', 300)
.attr('cy', 150)
.attr('r', 30)
.attr('fill', '#26963c')
.attr('id', circleId);
var clientScript = "d3.select('#" + circleId + "').transition().delay(1000).attr('fill', '#f9af26')";
d3.select(body)
.append('script')
.html(clientScript);
var svgsrc = window.document.innerHTML
fs.writeFile('index.html', svgsrc, function(err) {
if(err) {
console.log('error saving document', err)
} else {
console.log('The file was saved!')
}
});
// restore globals
if ('window' in globals) global.window = globals.window;
else delete global.window;
if ('document' in globals) global.document = globals.document;
else delete global.document;
}
});
4. You can now run the test with the command "node test.js".


2 comments:

  1. This example works for me. But if I try to pull in data from a CSV file with d3.csv, I get this kind of error:

    C:\wamp\www\vital\d3.v3.js:1863
    oresend", "progress", "load", "error"), headers = {}, request = new XMLHttpReq
    ^
    ReferenceError: XMLHttpRequest is not defined
    at d3_xhr (C:\wamp\www\vital\d3.v3.js:1863:114)

    I've tried to load some kind of XMLHttpRequest facility into my script, but nothing has worked so far. Do you have any ideas about how to deal with this?

    ReplyDelete
  2. I get this error when I try this.

    https://github.com/a85/Newman/issues/146

    ReplyDelete