/** * PNG\JPEG exporter for C3.js, version 0.2 * (c) 2014 Yuval Bar-On * * usage: path/to/phantomjs output options [WxH] * */ // useful python-styled string formatting, "hello {0}! Javascript is {1}".format("world", "awesome"); if (!String.prototype.format) { String.prototype.format = function() { var args = arguments; return this.replace(/{(\d+)}/g, function(match, number) { return typeof args[number] != 'undefined' ? args[number] : match ; }); }; } // defaults var page = require('webpage').create(), fs = require('fs'), system = require('system'), config = JSON.parse( fs.read('config.json') ), output, size; if (system.args.length < 3 ) { console.log('Usage: phantasm.js filename html [WxH]'); phantom.exit(1); } else { out = system.args[1]; opts = JSON.parse( system.args[2] ); if (system.args[3]) { var dimensions = system.args[3].split('x'), width = dimensions[0], height = dimensions[1]; function checkNum(check) { check = parseInt(check); if (!isNaN(check)) return check; return false; } width = checkNum(width); height = checkNum(height); if (width && height) { page.viewportSize = { height: height, width: width } } // fit chart size to img size, if undefined if (!opts.size) { opts.size = { "height": height, "width": width }; } } else { // check if size is defined in chart, // else apply defaults page.viewportSize = { height: (opts.size && opts.size.height) ? opts.size.height : 320, width: (opts.size && opts.size.width ) ? opts.size.width : 710, } } } page.onResourceRequested = function(requestData, request) { console.log('::loading resource ', requestData['url']); }; // helpful debug functions page.onConsoleMessage = function(msg){ console.log(msg); }; page.onError = function(msg, trace) { var msgStack = ['ERROR: ' + msg]; if (trace && trace.length) { msgStack.push('TRACE:'); trace.forEach(function(t) { msgStack.push(' -> ' + t.file + ': ' + t.line + (t.function ? ' (in function "' + t.function +'")' : '')); }); } console.error(msgStack.join('\n')); }; // render page function injectVerify(script) { var req = page.injectJs(script); if (!req) { console.log( '\nError!\n' + script + ' not found!\n' ); phantom.exit(1); } } page.onLoadFinished = function() { console.log('::rendering'); for (var j in config.js) { injectVerify(config.js[j]); } page.evaluate(function(chartoptions) { // phantomjs doesn't know how to handle .bind, so we override Function.prototype.bind = Function.prototype.bind || function (thisp) { var fn = this; return function () { return fn.apply(thisp, arguments); }; }; // generate chart c3.generate(chartoptions); }, opts); // setting transition to 0 has proven not to work thus far, but 300ms isn't much // so this is acceptable for now setTimeout(function() { page.render(out); phantom.exit(); }, 300); } // apply css inline because that usually renders better var css = ''; for (var i in config.css) { css += fs.read(config.css[i]); } page.content = config.template.format(css);