D3.js
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 stylescontext.strokeStyle
andcontext.strokeText
: for the stroke of the textcontext.fillStyle
andcontext.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