github.com/wI2L/jettison@v0.7.5-0.20230106001914-c70014c6417a/tools/charts/index.js (about) 1 #!/usr/bin/env node 2 3 const fs = require('fs') 4 const jd = require('jsdom') 5 const { 6 JSDOM 7 } = jd 8 const path = require('path') 9 const prog = require('commander') 10 const util = require('util') 11 const deca = require('decamelize') 12 const { optimize } = require('svgo'); 13 14 prog 15 .option('-f, --input <file>', 'json-formatted benchmark data file') 16 .option('-d, --directory <dir>', 'output directory of charts') 17 .option('-n, --names <list>', 'comma-separated list of benchmark names', (value) => { 18 return value.split(',') 19 }) 20 21 prog.version('0.2.0') 22 prog.parse(process.argv) 23 24 // createChart creates and exports a Google Bar Chart 25 // as a PNG image, using the decamelized form of name 26 // with '-' as separator. The parameter data must be a 27 // two-dimensional array where each row represents a 28 // bar in the chart. 29 function createBarChart (dom, name, data, opts) { 30 var head = dom.window.document.getElementsByTagName('head')[0] 31 var func = head.insertBefore 32 33 // Prevent call to Google Font API. 34 head.insertBefore = function (el, ref) { 35 if (el.href && el.href.indexOf('//fonts.googleapis.com/css?family=Input') > -1) { 36 return 37 } 38 func.call(head, el, ref) 39 } 40 // Add an event listener to draw the chart once 41 // the DOM is fully loaded. 42 dom.window.addEventListener('DOMContentLoaded', function () { 43 const g = dom.window.google 44 45 // Load the Google Visualization 46 // API and the corechart package. 47 g.charts.load('45.2', { 48 packages: ['corechart', 'bar'] 49 }) 50 g.charts.setOnLoadCallback(function () { 51 drawBarChart(dom, name, data, opts) 52 }) 53 }) 54 } 55 56 // exportChartAsSVG exports the SVG of the chart to 57 // the current working directory. The file name is a 58 // decamelized version of name using the hyphen char 59 // as separator, in lowercase. 60 function exportChartAsSVG (e, name) { 61 var filename = util.format('%s.svg', 62 path.join(prog.directory, deca(name, '-')) 63 ) 64 var svgEl = e.getElementsByTagName('svg')[0] 65 var svg = htmlToElement(svgEl.outerHTML) 66 67 svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg') 68 svg.setAttribute('version', '1.1') 69 70 const result = optimize(svg.outerHTML, { 71 plugins: [{ 72 name: "sortAttrs" 73 }, { 74 name: "removeAttrs", 75 params: { 76 attrs: "(clip-path|aria-label|overflow)" 77 } 78 }], 79 multipass: true 80 }) 81 try { 82 return fs.writeFileSync(filename, result.data) 83 } catch (err) { 84 console.error('cannot write svg chart %s: %s', filename, err) 85 } 86 } 87 88 function htmlToElement (html) { 89 const d = (new JSDOM('...')).window.document 90 var t = d.createElement('template') 91 t.innerHTML = html.trim() 92 return t.content.firstChild 93 } 94 95 function drawBarChart (dom, name, data, opts) { 96 const g = dom.window.google 97 const d = dom.window.document 98 99 // Convert the data 2D-array to a DataTable, 100 // and sort it in alphabetical order using 101 // the content of the first column which 102 // contains the names of the benchmark runs. 103 var dt = new g.visualization.arrayToDataTable(data) 104 dt.sort([{ 105 column: 0 106 }]) 107 var e = d.getElementById('chart') 108 var c = new g.visualization.ColumnChart(e) 109 110 // Setup a callback that exports the chart as 111 // a PNG image when it has finished drawing. 112 g.visualization.events.addListener(c, 'ready', function () { 113 exportChartAsSVG(e, name) 114 }) 115 c.draw(dt, opts) 116 } 117 118 // Load and parse the JSON-formatted benchmark 119 // statistics from the input file. 120 var file = fs.readFileSync(prog.input) 121 var data = JSON.parse(file) 122 123 // Iterate over all benchmarks and create the 124 // chart only if it was requested through the 125 // command-line parameters. 126 Object.keys(data).forEach(function (key) { 127 if (!prog.names.includes(key)) { 128 return 129 } 130 const pageFile = path.join(__dirname, 'jsdom.html') 131 132 JSDOM.fromFile(pageFile, { 133 resources: 'usable', 134 runScripts: 'dangerously', 135 pretendToBeVisual: true 136 }).then(dom => { 137 createBarChart(dom, key, data[key], { 138 width: 700, 139 height: 400, 140 chartArea: { 141 left: 100, 142 top: 50, 143 width: '70%', 144 height: '75%' 145 }, 146 vAxis: { 147 format: '', 148 gridlines: { 149 count: 5 150 }, 151 minorGridlines: { 152 count: 2 153 } 154 }, 155 hAxis: { 156 textStyle: { 157 bold: true, 158 fontName: 'Input' 159 } 160 } 161 }) 162 }) 163 })