logo

D3.js

Last Updated: 2022-03-26

SVG vs Canvas

Common

const width = 1080,
  height = 600;

const scale = height / 4;

const projection = d3.geoMercator()
  .translate([width / 2, height / 2])
  .scale(scale);

const data = ...; // geojson or topojson

SVG

const path = d3.geoPath().projection(projection);

const map = d3
  .select('#map')
  .append('svg')
  .attr('width', width)
  .attr('height', height);

map.append('path').datum(data).attr('class', 'land').attr('d', path);

Canvas

const path = d3.geoPath().projection(projection).context(context);

const canvas = d3
  .select('#map')
  .append('canvas')
  .attr('width', width)
  .attr('height', height);

const context = canvas.node().getContext('2d');

context.beginPath();
path(data);
context.fillStyle = '#DDD';
context.fill();
context.closePath();

D3 Scales

D3 scales can be use not only for data viz

  • Domain: input
  • Range: output

Scale map from input(domain) to output(range)

  • Time: d3.time.scale()
  • Linear: d3.scale.linear()
  • Log: d3.scale.log()

E.g.

var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);

x.domain(
  d3.extent(data, function (d) {
    return d.date;
  })
);
y.domain([
  0,
  d3.max(data, function (d) {
    return d.close;
  }),
]);

Update Axis

svg.selectAll('g .y.axis').call(yAxis);

Remove

d3.select('svg').remove();

Date Format

To Create formats:

var rawFormat = d3.time.format('%Y%m%d%H%M');
var newFormat = d3.time.format('%Y-%m-%d  %H:%M');

To parse the data:

// timestamp is a string like "201809010805", this returns a Date object
var date = rawFormat.parse(timestamp);

To convert a Date object to string

// return a string like "2018-09-01  08:05"
var str = newFormat(date);

https://github.com/d3/d3/blob/master/API.md#time-formats-d3-time-format

Add Grid Lines

// function to generate axis(the axis is essentially a function)
function getYAxis() {
  return d3.svg.axis().scale(y).orient('left');
}

// Add initial Y Axis with ticks
svg.append('g').attr('class', 'y axis').call(getYAxis());

// Add initial grid line(dummy Y Axis)
svg.append('g').attr('class', 'grid-line').call(
  getYAxis()
    .tickFormat('') // Hide tick text
    .tickSize(-width, 0, 0) // Set tick width so it expands all the way to the right
);

function updateChart(data) {
  svg.selectAll('g .y.axis').call(getYAxis());

  svg
    .selectAll('g .grid-line')
    .call(getYAxis().tickFormat('').tickSize(-width, 0, 0));
}

Geo

const line = {
  type: 'Feature',
  geometry: {
    type: 'LineString',
    coordinates: [
      [-122.375, 37.618889],
      [-74.168611, 40.6925],
    ],
  },
  properties: {
    airports: ['SFO', 'EWR'],
  },
};

To draw the cirle:

const circle = d3.geoCircle().center(line.geometry.coordinates[0]).radius(1.5);
context.beginPath();
geoGenerator(circle());
context.fillStyle = 'red';
context.fill();

To add labels, use the following to style the text:

  • context.font: for font styles
  • context.strokeStyle and context.strokeText: for the stroke of the text
  • context.fillStyle and context.fillText: for the fill of the text
context.font = 'bolder 12px monospace';
context.strokeStyle = 'white';
context.strokeText('SFO', ...projection(line.geometry.coordinates[0]));
context.fillStyle = 'black';
context.fillText('SFO', ...projection(line.geometry.coordinates[0]));

Note: use projection to calculate the right position from coordinates