Public
Edited
Apr 11, 2023
1 fork
Insert cell
Insert cell
Insert cell
Insert cell
worldMapImage
Insert cell
pdxEquatorPixel = 2100
Insert cell
pdxEquatorPct = pdxEquatorPixel / worldMapImage.height;
Insert cell
miller.translate()
Insert cell
miller.invert([8192, 2100, 5])
Insert cell
miller = getMiller(worldMapImage.width, worldMapImage.height)
Insert cell
function getMiller(pxWidth, pxHeight) {
const pdxEquatorPct = pdxEquatorPixel / worldMapImage.height;
const miller = d3.geoMiller().fitWidth(pxWidth, ({type: "Sphere"}));
const pdxTranslate = [miller.translate()[0], pdxEquatorPct * pxHeight];
miller.translate(pdxTranslate); //.reflectY(true);
return miller;
}
Insert cell
Insert cell
Insert cell
Insert cell
gm2 = d3.geoMiller().fitWidth(window.innerWidth, ({type: "Sphere"}));
Insert cell
gm2.clipExtent()
Insert cell
globe = {
let showGraticule = true;
//let width = d3.select("#map").node().getBoundingClientRect().width
let height = 600
const sensitivity = 75

let yValues = geoTopology.arcs.flat().map(c => c[1]);
let minY = _.min(yValues);
let maxY = _.max(yValues);
let projection = d3.geoMiller().fitWidth(window.innerWidth, ({type: "Sphere"}));
/*
.scale(250)
.center([0, 0])
.rotate([0,-30])
.translate([width / 2, height / 2])
*/

const initialScale = projection.scale()
let path = d3.geoPath().projection(projection)
const svg = d3.select(DOM.svg(width, height))

let globe = svg.append("circle")
.attr("fill", colors.water)
.attr("stroke", "#none")
.attr("stroke-width", "0")
.attr("cx", width/2)
.attr("cy", height/2)
.attr("r", initialScale)
// create one path per TopoJSON feature
let countries = topojson.feature(geoTopology, geoTopology.objects.land).features
let borders = topojson.mesh(geoTopology, geoTopology.objects.regions, (a, b) => a !== b);
let graticule = d3.geoGraticule()
if (showGraticule) {
svg.append("path")
.datum(graticule())
.attr("class", "graticule")
.attr("d", path)
.attr('fill', 'none')
.attr('stroke', colors.graticules)
.attr('stroke-width', '0.5px');
}
let country = svg.selectAll("country")
.data(countries)
.enter().append("path")
.attr("class", "country")
.attr("d", path)
.style("fill", colors.land);
svg.append("path")
.datum(borders)
.attr("d", path)
.attr("class", "borders")
.style("fill", "none")
.style("stroke", colors.borders)
.style("stroke-width", "0.3px")

svg.call(d3.drag().on('drag', (event) => {
const rotate = projection.rotate()
const k = sensitivity / projection.scale()
projection.rotate([
rotate[0] + event.dx * k,
rotate[1]
])
path = d3.geoPath().projection(projection)
svg.selectAll("path").attr("d", path)
}))
.call(d3.zoom().on('zoom', (event) => {
if(event.transform.k > 0.3) {
projection.scale(initialScale * event.transform.k)
path = d3.geoPath().projection(projection)
svg.selectAll("path").attr("d", path)
globe.attr("r", projection.scale())
}
else {
event.transform.k = 0.3
}
}))

// let map = svg.append("g")
return svg.node()

}

Insert cell

viewof colors = inputsGroup(
[
[
color({
value: "#bfd7e4",
title: "Water",
}),
color({
value: "#eaeaea",
title: "Land",
}),
color({
value: "#aaaaaa",
title: "Borders",
}),
color({
value: "#ffffff",
title: "Graticules",
})
]
],
[
['water','land','borders','graticules']
]
)
Insert cell
function inputsGroup(views,names){
const form = html`<div class="inputs-group">${
views.map(row => html`<div class="inputs-group-row">${
row.map(input => html`<div class="inputs-group-cell" style="display:inline-block; margin-right: 25px;">${input}</div>`)
}</div>`)
}</div>`;
form.oninput = () => {
form.value = views.map(row => row.map(input => input.value))
if(names){
names.forEach((row,i)=>row.forEach((c,j)=> form.value[i][j]!=null && (form.value[c]=form.value[i][j])))
}
};
form.oninput();
return form;
}
Insert cell
import {color} from "@jashkenas/inputs"
Insert cell
geoJson = {
topojson.feature(geoTopology
const cancellationToken = getCancellationToken();
const downscaleFactor = 4;
const topology = await buildTopology(worldMapImage, colorTable, downscaleFactor, cancellationToken);
return getGeoTopology(topology, downscaleFactor);
}
Insert cell
geoTopology = {
const cancellationToken = getCancellationToken();
const downscaleFactor = 4;
const topology = await buildTopology(worldMapImage, colorTable, downscaleFactor, cancellationToken);
return getGeoTopology(topology, downscaleFactor);
}
Insert cell
function getGeoTopology(topology, downscaleFactor) {
const allCoords = topology.arcs.flat()
const width = worldMapImage.width / downscaleFactor;
const height = worldMapImage.height / downscaleFactor;
const miller = getMiller(width, height);

function pxToMiller(coord) {
const geoCoord = miller.invert(coord);
coord[0] = geoCoord[0];
coord[1] = geoCoord[1];
return coord;
}
topology.arcs = topology.arcs.map(a => a.map(pxToMiller));
return topology;
}
Insert cell
Insert cell
Insert cell
cm.canvas
Insert cell
cm.transformManager.cursorPixel
Insert cell
cm.transformManager.hoverRect
Insert cell
hoverObjects = cm.hoverObjects
Insert cell
cm = new CanvasMap(worldMapImage)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function getChildrenFromMultiGeoJson(geoMulti) {
const geometry = geoMulti.geometry;
const type = geometry.type.replace("Multi", "");
return geometry.coordinates.map(c => ({
type: geoMulti.type,
properties: Object.assign({}, geoMulti.properties),
geometry: {
type,
coordinates: c
}
}));
}
Insert cell
Insert cell
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