Public
Edited
Dec 20, 2022
5 forks
15 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function Chart(coordinates, {
width = 640,
height = width / 2,
inset = 0,
precision = 0.2,
graticule = d3.geoGraticule10(),
projection = d3.geoEquirectangular().fitExtent([[inset, inset], [width - inset, height - inset]], {type: "Sphere"})
} = {}) {
const path = d3.geoPath(projection);
const line = {type: "LineString", coordinates};

const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.style("overflow", "visible");
const g = svg.append("g")
.attr("fill", "none")
.attr("stroke", "#f00")
.attr("stroke-width", 1.5);

const pathGraticule = g.append("path")
.attr("stroke", "#999")
.attr("stroke-width", 0.5);
const pathLine = g.append("path");

let point = g.append("g")
.selectAll("circle");

return Object.assign(svg.node(), {
rotate(rotate) {
projection.rotate(rotate);

// Render the line with the specified precision.
projection.precision(precision);
pathLine.attr("d", path(line));

// Override the path context to extract the coordinates.
const context = new BufferContext();
path.context(context)(line);
path.context(null);
point = point
.data(context.buffer())
.join("circle")
.attr("r", 4.5)
.attr("transform", (d) => `translate(${d})`);

// Render the graticule with the default precision.
projection.precision(0.2);
pathGraticule.attr("d", path(graticule));

return svg.node();
}
});
}
Insert cell
class BufferContext {
constructor() { this._ = []; }
moveTo(x, y) { this._.push([x, y]); }
lineTo(x, y) { this._.push([x, y]); }
closePath() {}
buffer() {const _ = this._; this._ = []; return _;}
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more