Published
Edited
May 8, 2021
3 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
austria = topojson.feature(topology, topology.objects.boundaries)
Insert cell
topojson = require("topojson-client@3")
Insert cell
// manually composed, see: https://observablehq.com/@nikita-sharov/metropolitan-france-map#data
topology = FileAttachment("boundaries.json").json()
Insert cell
Insert cell
Insert cell
chart = () => {
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);
const container = svg.append("g")
.attr("id", "boundaries");
for (const scale of scales) {
const feature = austria.features.find(d => d.properties.scale === scale);
addBoundary(container, feature, scale);
}
const zoomed = (event) => {
const {transform} = event;
container.attr("transform", transform);
};
const zoom = d3.zoom()
.scaleExtent([1, 8])
.translateExtent([[0, 0], [width, height]])
.on("zoom", zoomed);
zoom(svg);
return svg.node()
}
Insert cell
d3 = require("d3-geo@2", "d3-selection@2", "d3-zoom@2")
Insert cell
height = {
const [[x0, y0], [x1, y1]] = path.bounds(austria);
return Math.ceil(y1 - y0);
}
Insert cell
addBoundary = (parent, feature, scale) =>
parent.append("path")
.attr("id", `${scale}-scale`)
.attr("d", path(feature))
Insert cell
path = d3.geoPath(projection)
Insert cell
projection = d3.geoTransverseMercator()
.rotate([-13.33, 0]) // rounded, see: https://epsg.io/31255
.fitWidth(width, austria)
Insert cell
html`<style>
#boundaries {
fill: none;
stroke: black;
stroke-linejoin: bevel; /* 'miter' (default) appears partially disrupted at a high zoom */
}

#small-scale {
stroke-opacity: .3;
}

#medium-scale {
stroke-opacity: .6;
}

#large-scale {
stroke-opacity: .9;
}
</style>`
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