Skip to content

Instantly share code, notes, and snippets.

@alexp1917
Last active August 2, 2021 00:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexp1917/48b47109a4d854e5e3f559df5d9a31ae to your computer and use it in GitHub Desktop.
Save alexp1917/48b47109a4d854e5e3f559df5d9a31ae to your computer and use it in GitHub Desktop.
d3 on Node.js example
node_modules/
// the alternative is to downgrade to a very old version
// then understanding the code below is not necessary
// but this works so lets use it for now
module.exports = new Promise(async resolve => {
var d3 = await import('d3');
var d3Scale = await import('d3-scale');
// for (var e of Object.keys(d3Scale)) {
var d3ScaleObj = { scale: {}, };
for (var e in (d3Scale)) {
if (e.startsWith('scale')) {
var letter = e.substring('scale'.length, 'scale'.length + 1).toLowerCase()
var rest = e.substring('scale'.length + 1);
d3ScaleObj.scale[letter + rest] = d3Scale[e];
}
}
resolve({
...d3ScaleObj,
...d3,
})
})
// testing
// module.exports.then(d3 => console.log('scale', d3.scale))
// setTimeout(function() {}, 10000);
// https://gist.github.com/kunnix/148eadcfde3e978a1ad1d3ec9e2a7265
// Instructions:
// npm install --save d3 jsdom
const fs = require('fs');
const d3 = import('d3');
const jsdom = require('jsdom');
const { JSDOM } = jsdom;
async function main() {
const fakeDom = new JSDOM('<!DOCTYPE html><html><body></body></html>');
const outputLocation = './output.svg';
let body = (await d3).select(fakeDom.window.document).select('body');
// Make an SVG Container
let svgContainer = body.append('div').attr('class', 'container')
.append("svg")
.attr("width", 1280)
.attr("height", 1024);
// Draw a line
let circle = svgContainer.append("line")
.attr("x1", 5)
.attr("y1", 5)
.attr("x2", 500)
.attr("y2", 500)
.attr("stroke-width", 2)
.attr("stroke", "black");
// Output the result to console
console.log(body.select('.container').html());
// Output the result to file
// fs.writeFileSync(outputLocation, body.select('.container').html());
}
main();
var jsdom = require('jsdom');
var fs = require('fs');
var getD3 = require('./d3-shim');
async function doTheThing(d3) {
var fakeDom = new jsdom.JSDOM(`
<!DOCTYPE html>
<html>
<body>
<!-- to illustrate/for visual debugging purposes -->
<div class="container" style="background-color:lightblue;">
</div>
</body>
</html>
`
// simply replace all the extra whitespace
// so it doesnt print at the end
//
// \s means whitespace ('WS') (spaces, enter, tabs...)
// the regex means find any 2 or more WS, replace with ''
//
// the /g means do it for all of them, not just the 1st one
//
.replace(/\s\s+/g, ''));
// simulating browser, like "window" variable in browsers
var { window } = fakeDom;
// this is not the same as jQuery $('.container') or
// document.querySelector('.container').
//
// im not sure why, but i tried to use standard DOM api's and it broke
//
var container = d3.select(window.document).select('.container');
// Make the SVG itself
var svg = container
.append('svg')
.attr('width', 300)
.attr('height', 40);
var possibleStates = ['started', 'inProgress', 'completed'];
var possibleColors = ['yellow', 'orange', 'green' ];
var segmentWidth = 100;
var currentState = possibleStates[1]; // 'inProgress'
var colorScale = d3.scale.ordinal()
.domain(possibleStates)
.range(possibleColors);
// draw a rectangle and forget about it
svg.append('rect')
.attr('class', 'bg-rect')
.attr('rx', 10)
.attr('ry', 10)
.attr('fill', 'gray')
.attr('height', 15)
// this could just as well have been a constant
// but d3 supports functions because its about dynamic data
.attr('width', () => segmentWidth * possibleStates.length)
.attr('x', 0);
// this time make a rectangle and dont forget about it
var progress = svg.append('rect')
.attr('class', 'progress-rect')
.attr('fill', () => colorScale(currentState))
.attr('height', 15)
.attr('width', 0)
// "radius" (i think) -- this is what makes the corners rounded
.attr('rx', 10)
.attr('ry', 10)
.attr('x', 0);
// how to make it move slowly, animated
progress
.transition()
.duration(1000)
.attr('width', function(){
var index = possibleStates.indexOf(currentState);
return (index + 1) * segmentWidth;
});
// this overrides the previous action
progress.attr('width', 250);
/**
* requires waiting
**/
function moveProgressBar(state = 'inProgress') {
progress.transition()
.duration(0)
.attr('fill', function(){
return colorScale(state);
})
.attr('width', function(){
var index = possibleStates.indexOf(state);
return (index + 1) * segmentWidth;
});
}
return {
fakeDom,
container,
svg,
moveProgressBar,
};
}
async function progressBar() {
var d3 = await getD3;
var output = await doTheThing(d3);
var html = output.fakeDom.serialize();
var svg = output.svg.node().outerHTML;
console.log('html');
console.log(html);
// <!DOCTYPE html><html><head></head><body><div class="container" style="background-color:lightblue;"><div class="container"><svg width="300" height="40"><rect class="bg-rect" rx="10" ry="10" fill="gray" height="15" width="300" x="0"></rect><rect class="progress-rect" fill="orange" height="15" width="250" rx="10" ry="10" x="0"></rect></svg></div></div></body></html>
console.log('svg');
console.log(svg);
// <svg width="300" height="40">
// <rect class="bg-rect" rx="10" ry="10" fill="gray" height="15" width="300" x="0"></rect>
// <rect class="progress-rect" fill="orange" height="15" width="250" rx="10" ry="10" x="0"></rect>
// </svg>
// await fs.promises.writeFile('progress-bar.html', html, 'utf8');
return output;
}
if (require.main === module)
progressBar();
module.exports = { progressBar };
import * as d3 from 'd3';
console.log(d3)
{
"name": "blah",
"version": "0.0.1",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "Alexander Pavlovich <alexpimt1917@gmail.com>",
"license": "GPL-3.0-or-later",
"dependencies": {
"d3": "^7.0.0",
"d3-scale": "^4.0.0",
"jsdom": "^16.7.0",
"pdfmake": "^0.2.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment