Published
Edited
Aug 4, 2020
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function getCenter(method) {
if (!chosen[0]) return null;

const select = filter ? biggest : aggregate;

if (method === "d3.geoCentroid") {
return d3.geoCentroid(select);
}

if (method === "turf.centroid") {
return turf.centroid(select).geometry.coordinates;
}

if (method === "turf.centerOfMass") {
return turf.centerOfMass(select).geometry.coordinates;
}

if (filter || aggregate.type === "Polygon")
return polylabel(select.coordinates, 1.0);
return null;
}
Insert cell
function format([x, y]) {
const dir = [["N", "S"], ["E", "W"]];
return [y, x].map((d, i) => {
const suffix = d >= 0 ? dir[i][0] : dir[i][1];
const rawDeg = Math.abs(d);
const deg = Math.floor(rawDeg);
const rawMin = (rawDeg - Math.floor(deg)) * 60;
const min = Math.floor(rawMin);
const rawSec = (rawMin - min) * 60;
const sec = Math.floor(rawSec);

return `${deg}°${d3.format("02")(min)}'${d3.format("02")(sec)}''${suffix}`;
});
}
Insert cell
centers = new Map(methods.map(d => [d, getCenter(d)]))
Insert cell
methods = [
"d3.geoCentroid",
"turf.centroid",
"turf.centerOfMass",
"mapbox.polylabel"
]
Insert cell
color = d3.scaleOrdinal(methods.map(d => d.name), d3.schemeCategory10)
Insert cell
biggest = {
if (!chosen[0]) return null;

if (aggregate.type === "Polygon") return aggregate;

return aggregate.coordinates
.map(d => ({ type: "Polygon", coordinates: d }))
.sort((a, b) => d3.descending(d3.geoArea(a), d3.geoArea(b)))[0];
}
Insert cell
aggregate = {
if (!chosen[0]) return null;

const aggregate = topojson.merge(
world,
world.objects.countries.geometries.filter(d =>
chosen.includes(d.properties.name)
)
);

// If the selected countries form a polygon
if (aggregate.coordinates.length === 1)
return {
type: "Polygon",
coordinates: aggregate.coordinates[0]
};

return aggregate;
}
Insert cell
mutable chosen = []
Insert cell
mutable hovered = "Select a country"
Insert cell
chosenToString = chosen
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))
.join(" - ")
Insert cell
{
map.update(centers);
}
Insert cell
{
clear;
mutable chosen = [];
map.clear();
}
Insert cell
function handleMouseMove(d) {
if (d3.select(this).attr("class") === "unclicked") {
d3.select(this).attr("fill", "#ccc");
}
mutable hovered = d.properties.name;
}
Insert cell
function handleMouseLeave() {
if (d3.select(this).attr("class") === "unclicked") {
d3.select(this).attr("fill", "#f4f4f4");
}
mutable hovered = "Select a country";
}
Insert cell
function handleClick(d) {
if (d3.select(this).attr("class") === "unclicked") {
d3.select(this)
.attr("class", "clicked")
.attr("fill", "#999");
} else {
d3.select(this)
.attr("class", "unclicked")
.attr("fill", "#f4f4f4");
}
mutable chosen = d3
.select(this.parentNode)
.selectAll(".clicked")
.data()
.map(d => d.properties.name);
}
Insert cell
height = 510
Insert cell
path = d3.geoPath(projection)
Insert cell
projection = d3.geoNaturalEarth1().fitSize([width, height], countries)
Insert cell
countries = topojson.feature(world, world.objects.countries)
Insert cell
world = FileAttachment("countries-50m.json").json()
Insert cell
topojson = require("topojson-client@3")
Insert cell
turf = require("@turf/turf@5")
Insert cell
polylabel = require("https://bundle.run/@mapbox/polylabel@1.0.2")
Insert cell
d3 = require("d3@5")
Insert cell
import { button, checkbox } from "@jashkenas/inputs"
Insert cell
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