/** * 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)