phantom-exporter.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /**
  2. * PNG\JPEG exporter for C3.js, version 0.2
  3. * (c) 2014 Yuval Bar-On
  4. *
  5. * usage: path/to/phantomjs output options [WxH]
  6. *
  7. */
  8. // useful python-styled string formatting, "hello {0}! Javascript is {1}".format("world", "awesome");
  9. if (!String.prototype.format) {
  10. String.prototype.format = function() {
  11. var args = arguments
  12. return this.replace(/{(\d+)}/g, function(match, number) {
  13. return typeof args[number] != 'undefined' ? args[number] : match
  14. })
  15. }
  16. }
  17. // defaults
  18. var page = require('webpage').create(),
  19. fs = require('fs'),
  20. system = require('system'),
  21. config = JSON.parse(fs.read('config.json')),
  22. output,
  23. size
  24. if (system.args.length < 3) {
  25. console.log('Usage: phantasm.js filename html [WxH]')
  26. phantom.exit(1)
  27. } else {
  28. out = system.args[1]
  29. opts = JSON.parse(system.args[2])
  30. if (system.args[3]) {
  31. var dimensions = system.args[3].split('x'),
  32. width = dimensions[0],
  33. height = dimensions[1]
  34. function checkNum(check) {
  35. check = parseInt(check)
  36. if (!isNaN(check)) return check
  37. return false
  38. }
  39. width = checkNum(width)
  40. height = checkNum(height)
  41. if (width && height) {
  42. page.viewportSize = {
  43. height: height,
  44. width: width
  45. }
  46. }
  47. // fit chart size to img size, if undefined
  48. if (!opts.size) {
  49. opts.size = {
  50. height: height,
  51. width: width
  52. }
  53. }
  54. } else {
  55. // check if size is defined in chart,
  56. // else apply defaults
  57. page.viewportSize = {
  58. height: opts.size && opts.size.height ? opts.size.height : 320,
  59. width: opts.size && opts.size.width ? opts.size.width : 710
  60. }
  61. }
  62. }
  63. page.onResourceRequested = function(requestData, request) {
  64. console.log('::loading resource ', requestData['url'])
  65. }
  66. // helpful debug functions
  67. page.onConsoleMessage = function(msg) {
  68. console.log(msg)
  69. }
  70. page.onError = function(msg, trace) {
  71. var msgStack = ['ERROR: ' + msg]
  72. if (trace && trace.length) {
  73. msgStack.push('TRACE:')
  74. trace.forEach(function(t) {
  75. msgStack.push(
  76. ' -> ' +
  77. t.file +
  78. ': ' +
  79. t.line +
  80. (t.function ? ' (in function "' + t.function + '")' : '')
  81. )
  82. })
  83. }
  84. console.error(msgStack.join('\n'))
  85. }
  86. // render page
  87. function injectVerify(script) {
  88. var req = page.injectJs(script)
  89. if (!req) {
  90. console.log('\nError!\n' + script + ' not found!\n')
  91. phantom.exit(1)
  92. }
  93. }
  94. page.onLoadFinished = function() {
  95. console.log('::rendering')
  96. for (var j in config.js) {
  97. injectVerify(config.js[j])
  98. }
  99. page.evaluate(function(chartoptions) {
  100. // phantomjs doesn't know how to handle .bind, so we override
  101. Function.prototype.bind =
  102. Function.prototype.bind ||
  103. function(thisp) {
  104. var fn = this
  105. return function() {
  106. return fn.apply(thisp, arguments)
  107. }
  108. }
  109. // generate chart
  110. c3.generate(chartoptions)
  111. }, opts)
  112. // setting transition to 0 has proven not to work thus far, but 300ms isn't much
  113. // so this is acceptable for now
  114. setTimeout(function() {
  115. page.render(out)
  116. phantom.exit()
  117. }, 300)
  118. }
  119. // apply css inline because that usually renders better
  120. var css = ''
  121. for (var i in config.css) {
  122. css += fs.read(config.css[i])
  123. }
  124. page.content = config.template.format(css)