Public
Edited
Feb 15, 2023
6 stars
Also listed in…
Geo
Insert cell
Insert cell
{
const context = DOM.context2d(
width,
height,
8 /* extra high resolution for download */
),
path = d3.geoPath(projection, context);

context.fillStyle = "#fff";
context.fillRect(0, 0, width, height);
context.fillStyle = "#eee";
context.beginPath();
path({ type: "Sphere" });
context.fill();

for (const f of countries.features) {
const { id } = f;

// cache the polygons
const polygons = f.closest || (f.closest = closest(f));

context.save();
context.lineWidth = 0.5;
context.strokeStyle = context.fillStyle = color(id);
context.beginPath();
path(f);
context.fill(), context.stroke();
context.clip();

context.globalAlpha = 0.3;
for (const p of polygons) {
context.fillStyle = color(p.properties.site.id);
context.beginPath();
path(p);
context.fill();

context.lineWidth = 0.25;
context.strokeStyle = "white";
context.stroke();
}

context.restore();

yield context.canvas;
}

context.strokeStyle = "white";
context.beginPath();
context.lineWidth = 0.75;
path(borders);
context.stroke();

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

yield context.canvas;
}
Insert cell
color = d3.scaleOrdinal([].concat(d3.schemeTableau10).concat(d3.schemePastel1))
Insert cell
Insert cell
function closest(f) {
// todo intersect, or at least eliminate useless polygons
const e = d3.geoBounds(f);
return d3
.geoVoronoi(points.filter(d => d.id !== f.id))
.polygons()
.features.filter(f => {
const t = d3.geoBounds(f);
if (
// we can't optimize longitudes (Russia)
//e[0][0] > t[1][0] ||
//t[0][0] > e[1][0] ||
e[0][1] > t[1][1] ||
t[0][1] > e[1][1]
)
return false;
return true;
});
}
Insert cell
points = countries.features.flatMap(c => {
const v = geoVertices(c);
return v.map(d => {
d.id = c.id;
return d;
});
})
Insert cell
d3 = require("d3@5", "d3-geo-projection@2", "d3-geo-voronoi@1.6", "d3-geo-polygon@1.9")
Insert cell
borders = topojson.mesh(world, world.objects.countries, (a, b) => a != b)
Insert cell
countries = {
const countries = topojson.feature(world, world.objects.countries);
//countries.features.sort((a, b) => d3.geoArea(b) - d3.geoArea(a));
return countries;
}
Insert cell
vertices = geoVertices(borders)
Insert cell
world = d3.json(
"https://unpkg.com/visionscarto-world-atlas@0.1.0/world/110m.json"
)
Insert cell
topojson = require("topojson")
Insert cell
geoVertices = function(feature) {
const vertices = [];
const stream = {
point: function(lambda, phi) {
vertices.push([lambda, phi]);
},
lineStart: function() {},
lineEnd: function() {},
polygonStart: function() {},
polygonEnd: function() {}
};
d3.geoStream(feature, stream);
return vertices;
}
Insert cell
height = 600
Insert cell
projection = d3
//.geoOrthographic()
.geoBertin1953()
//.geoAirocean().angle(30)
.fitExtent([[2, 2], [width - 2, height - 2]], { type: "Sphere" })
//.rotate([0, 90])
Insert cell
codes = d3.tsv(
"https://unpkg.com/visionscarto-world-atlas@0.0.6/world/110m.tsv"
)
Insert cell
import { select } from "@jashkenas/inputs"
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