Published unlisted
Edited
Oct 11, 2022
1 fork
Importers
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
map = {
const height = 600;
const projection = d3.geoMercator().fitExtent(
[
[1, 10],
[width - 50, height - 10]
],
// japan
selectedGeo,
// countyShapes // so just doing appears to draw the state but not the counties
);

const path = d3.geoPath(projection);
// const [[, top], [, bottom]] = path.bounds(japan);
const [[, top], [, bottom]] = path.bounds(selectedGeo);

// f translates fill() to the mapped x-y relationship drawn in line plot below (I think?)
const f = (d) => bottom + (top - bottom) * J(d);

// draws viewport (base svg)
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width);

// rectangular background, clipped by path to create fill
const bg = svg
.append("rect")
.attr("clip-path", "url(#clip)")
.attr("width", width)
.attr("height", height)
.attr("stroke", "none")
.attr("fill", "#BC002D");

// clips rectangular bg fill to Japan path
const clip = svg
.append("clipPath")
.attr("id", "clip")
.append("path")
// .attr("d", path(japan));
.attr("d", path(selectedGeo));

// draws y axis gridlines
svg
.append("g")
.selectAll()
.data(d3.ticks(0, 1, 50))
.join("line")
.attr("x2", width - 50)
.attr("stroke", "black")
.attr("stroke-width", (d) => ((d * 10) % 1 ? 0.25 : 1))
.attr("transform", (d) => `translate(0,${f(d)})`);

// labels y axis ticks
svg
.append("g")
.selectAll()
.data(d3.ticks(0, 1, 10))
.join("text")
.attr("font-family", "sans-serif")
.attr("font-size", "12")
.attr("transform", (d) => `translate(${width - 2},${f(d)})`)
.attr("y", "0.38em")
.attr("text-anchor", "end")
.text((d) => `${(100 * d) | 0}%`);

//draws static fill
svg
.append("path")
.attr("stroke", "none")
.attr("fill", "beige")
.attr("fill-opacity", 0.85)
.attr("d", path(selectedGeo));

// draws outline of Japan boundaries
svg
.append("path")
.attr("stroke", "black")
.attr("fill", "none")
.attr("d", path(selectedGeo));

// updates raw percentage selected on slider to area-aware y fill value to be drawn
function update(percentage) {
const r = f(percentage);
bg.attr("y", r);
return r;

// ADD modifications to this block BELOW
if (showGraticule) {
const graticule = d3
.geoGraticule(selectProjection[0])
.step([showGraticule, showGraticule]);
}

// option to show gridlines
if (showGridlines) {
const gridlines = d3.svg
.append("g")
.selectAll()
.data(d3.ticks(0, 1, 50))
.join("line")
.attr("x2", width - 50)
.attr("stroke", "black")
.attr("stroke-width", (d) => ((d * 10) % 1 ? 0.25 : 1))
.attr("transform", (d) => `translate(0,${f(d)})`); //;
}
// from https://observablehq.com/@observablehq/us-geographic-data
svg.append("path")
.attr("d", path(countyShapes))
.attr("fill", "none")
.attr("stroke", "#fff")
.attr("stroke-width", 0.35)
// return svg.node()
}
return Object.assign(svg.node(), { update });
}
Insert cell
map.update(percentage / 100)
Insert cell
fill = (shape) => {
const w = 1000; // precision
const context = DOM.context2d(w, w, 1);
// TODO: prefer an area-preserving projection such as geoAzimuthalEqualArea
const projection = d3.geoMercator().fitSize([w, w], shape);
context.beginPath();
const path = d3.geoPath(projection, context);
path(shape);
context.fill();
const [[, top], [, bottom]] = path.bounds(selectedGeo);
const d = context.getImageData(
0,
Math.floor(top),
w,
Math.ceil(bottom - top)
).data;
const l = d.length >> 2;
// TODO: we could be more precise by scanning lines instead of pixels
const c = d3.cumsum({ length: l }, (_, i) => d[(i << 2) + 3]);
const H = c[c.length - 1];
return (p) => 1 - d3.bisect(c, (1 - p) * H) / l;
}
Insert cell
J = fill(selectedGeo)
Insert cell
Plot.lineY(d3.ticks(0, 1, 500), { x: (d) => d, y: J }).plot({
nice: true,
x: { label: "percentage" },
y: { label: "height" }
})
Insert cell
// japan = FileAttachment("japan.json").json()
// japan = selectedGeo
Insert cell
Insert cell
// import {viewof selectProjection, selectedGeo} from "@njcode/liquid-geoplanes"
import {
selectedGeo,
viewof selectProjection,
viewof selectResolution,
viewof showScaleBar, // addtl code required. might be more fitting to show full w/h or other dimension here
viewof showGraticule // addtl code required. should probably either alternate with gridlines (or shape the gridlines later)
} from "@washpostgraphics/state-plane-selector"
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