Public
Edited
May 22, 2023
1 star
Insert cell
Insert cell
Insert cell
{
const svg = d3.select(DOM.svg(size + margin * 2, size + margin * 2));
const g = svg.append("g")
.attr("transform", `translate(${margin}, ${margin})`);
const projection = d3.geoOrthographic()
.fitSize([size, size], {type: "Sphere"});
const path = d3.geoPath()
.projection(projection);
const circle = d3.geoCircle()
.center(d => d)
.radius(1);
const graticule = g.append("path")
.datum(d3.geoGraticule()())
.attr("class", "graticule");
const sphere = g.append("path")
.datum({type: "Sphere"})
.attr("class", "sphere");
const points = g.selectAll(".point")
.data([a, b])
.enter().append("path")
.attr("class", "point");
const line = g.append("path")
.datum(geoLine(a, b))
.attr("class", "line");
const swoop = g.append("path")
.datum(geoSwoop(a, b, offset))
.attr("class", "swoop");
function update(){
graticule.attr("d", path);
sphere.attr("d", path);
line.attr("d", path);
swoop.attr("d", path);
points.attr("d", d => path(circle(d)));
}
update();
d3.geoInertiaDrag(svg, update, projection);
return svg.node();
}
Insert cell
Insert cell
html`<style>
.sphere {
fill: none;
stroke: black;
stroke-width: 2px;
}
.graticule {
fill: none;
stroke: #ccc;
}
.point {
fill: none;
stroke: black;
}
.line {
fill: none;
stroke: black;
}
.swoop {
fill: none;
stroke: tomato;
}
</style>`
Insert cell
a = [0, 20];
Insert cell
b = [35, 0];
Insert cell
function geoLine(a, b){
return {
type: "Feature",
geometry: {
type: "LineString",
coordinates: geoResample([a, b])
}
}
}
Insert cell
geoSwoop = (a, b, t) => {
return {
type: "Feature",
geometry: {
type: "LineString",
coordinates: swoopy.arc(a, b, t)
}
};
}
Insert cell
// by Mike Bostock -- https://github.com/d3/d3-geo-projection/issues/75
// Takes a sparse line string that assumes Cartesian interpolation in spherical
// coordinates and inserts interstitial points for greater accuracy when
// rendering with D3, which assumes spherical interpolation.
function geoResample(coordinates) {
var i = 0,
j = -1,
n = coordinates.length,
source = coordinates.slice(),
p0, x0, y0,
p1 = coordinates[0], x1 = p1[0], y1 = p1[1],
dx, dy, d2,
m2 = 10; // squared minimum angular distance
while (++i < n) {
p0 = p1, x0 = x1, y0 = y1;
p1 = source[i], x1 = p1[0], y1 = p1[1];
dx = x1 - x0, dy = y1 - y0, d2 = dx * dx + dy * dy;
coordinates[++j] = p0;
if (d2 > m2) for (var k = 1, m = Math.ceil(Math.sqrt(d2 / m2)); k < m; ++k) {
coordinates[++j] = [x0 + dx * k / m, y0 + dy * k / m];
}
}
coordinates[++j] = p1;
coordinates.length = j + 1;
return coordinates;
}
Insert cell
Insert cell
Insert cell
d3 = require("d3-geo@1", "d3-inertia@0", "d3-selection@1", "d3-shape@1");
Insert cell
swoopy = require("swoopy@0.0.12")
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