Published
Edited
Mar 10, 2021
17 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function show(projections, polygons) {
const w = width / polygons.length,
h = w,
height = w * projections.length,
context = DOM.context2d(width, height),
path = d3.geoPath().context(context);

function draw(rotate) {
context.clearRect(0, 0, width, height);
projections.forEach((projection, l) => {
path.projection(projection);

projection
.rotate(rotate)
.fitSize([w * 0.9, h], { type: "Sphere" })
.precision(0.1);

polygons.forEach((p, i) => {
projection.translate([w * i + w / 2, h / 2 + l * h]);

context.beginPath();
path({ type: "Sphere" });
context.lineWidth = 1.5;
context.stroke();

context.beginPath();
path(p);
context.fillStyle = green;
context.fill();
context.lineWidth = .5;
context.stroke();
});

// reset for drag
projection.translate([w / 2, h / 2]);
});
}

draw([0, 0]);

return d3
.select(context.canvas)
.call(drag(projections, draw, w, h))
.style("cursor", "grab")
.node();
}
Insert cell
viewof green = html`<input type=color value="${d3.color("lime").hex()}">`
Insert cell
polygons = [land, pole, bowl, stripes, spiral]
Insert cell
land = {
const topo = await d3.json(
"https://unpkg.com/visionscarto-world-atlas@0.0.6/world/110m.json"
),
simpler = topojson.simplify(topojson.presimplify(topo), 1);
return topojson.feature(simpler, simpler.objects.land);
}
Insert cell
stripes = {
const c = d3.geoCircle().radius(100);
return {
type: "Polygon",
coordinates: [90, -90].map(pole => c.center([0, pole])().coordinates[0])
};
}
Insert cell
pole = ({
type: "Polygon",
coordinates: d3
.geoCircle()
.center([0, 90])
.radius(20)().coordinates
})
Insert cell
bowl = ({
type: "Polygon",
coordinates: d3
.geoCircle()
.center([0, 90])
.radius(130)().coordinates
})
Insert cell
spiral = {
const n = 1e3,
dy = 5,
spiral = d3
.range(0, 1 + 1 / n, 1 / n)
.map(t => [((360 * 10 * t) % 360) - 180, -90 + dy + (90 - dy) * 2 * t])
.concat(
d3
.range(1, 0, -1 / n)
.map(t => [((360 * 10 * t) % 360) - 180, -90 + (90 - dy) * 2 * t])
);

return {
type: "Polygon",
coordinates: [[...spiral, spiral[0]]]
};
}
Insert cell
// versor dragging?
drag = {
let v0, q0, r0, projection;

return (projections, draw, w, h) =>
d3
.drag()
.on("start", function() {
d3.select(this).style("cursor", "grabbing");
const { x, y } = d3.event;
projection = projections[(y / h) | 0];
v0 = versor.cartesian(projection.invert([x % w, y % h]));
q0 = versor((r0 = projection.rotate()));
})
.on("drag", function() {
const { x, y } = d3.event;
const v1 = versor.cartesian(
projection.rotate(r0).invert([x % w, y % h])
);
const q1 = versor.multiply(q0, versor.delta(v0, v1));
draw(versor.rotation(q1));
})
.on("end", function() {
d3.select(this).style("cursor", "grab");
});
}
Insert cell
d3 = require("d3@5", "d3-geo-projection", "d3-geo-polygon@1.12.0")
Insert cell
topojson = require("topojson@3")
Insert cell
versor = require("versor@0")
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