Skip to content

Instantly share code, notes, and snippets.

@Fil
Forked from veltman/draw.js
Last active June 13, 2019 21:20
D3 frames to video

This amazing script by Noah Veltman allows to create videos from d3.

install

npm install canvas topojson d3 rw

run

node draw.js | ffmpeg -y -c:v png -f image2pipe -r 20 -i - -an -c:v libx264 -pix_fmt yuv420p -movflags +faststart myvideo.mp4

enjoy

// Pipe to ffmpeg with something like:
// node draw.js | ffmpeg -y -c:v png -f image2pipe -r 20 -i - -an -c:v libx264 -pix_fmt yuv420p -movflags +faststart myvideo.mp4
var Canvas = require("canvas"),
d3 = require("d3"),
topojson = require("topojson"),
rw = require("rw"),
world = require("./world-110m.json");
var width = 960,
height = 540;
var canvas = new Canvas(width, height),
context = canvas.getContext("2d");
var countries = topojson.feature(world, world.objects.countries),
mesh = topojson.mesh(world, world.objects.countries);
var projection = d3.geoOrthographic()
.scale(240)
.translate([width / 2, height / 2])
.clipAngle(90)
.precision(.1);
var path = d3.geoPath()
.projection(projection)
.context(context);
// Draw 60 frames
d3.range(600).forEach(function(frame){
// Spin the globe a bit more each time
projection.rotate([frame * 0.6]);
context.clearRect(width, height);
// Water
context.fillStyle = "#23b4d8";
context.beginPath();
path({type: "Sphere"});
context.fill();
// Countries
countries.features.forEach(function(country, i){
context.fillStyle = d3.interpolateRainbow(Math.sin(i + frame/10));
context.beginPath();
path(country);
context.fill();
});
// Borders
context.beginPath();
path(mesh);
context.stroke();
// Pipe to stdout but squash EPIPE
rw.writeFileSync("/dev/stdout", canvas.toBuffer());
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment