From 228c5f5e39c75eece115ebdad919a15383e6aa7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Mon, 5 Dec 2022 11:48:13 +0100 Subject: [PATCH] projection.domain accepts an iterable closes #1148 --- README.md | 2 +- src/projection.js | 13 ++++++++++++- test/plots/projection-fit-antarctica.js | 6 +++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 72af6a9d3e..0623e35455 100644 --- a/README.md +++ b/README.md @@ -341,7 +341,7 @@ If the **projection** option is specified as an object, the following additional * projection.**parallels** - the [standard parallels](https://github.com/d3/d3-geo/blob/main/README.md#conic_parallels) (for conic projections only) * projection.**precision** - the [sampling threshold](https://github.com/d3/d3-geo/blob/main/README.md#projection_precision) * projection.**rotate** - a two- or three- element array of Euler angles to rotate the sphere -* projection.**domain** - a GeoJSON object to fit in the center of the frame +* projection.**domain** - a GeoJSON object (or an iterable of GeoJSON objects) to fit in the center of the frame * projection.**inset** - inset by the given amount in pixels when fitting to the frame (default zero) * projection.**insetLeft** - inset from the left edge of the frame (defaults to inset) * projection.**insetRight** - inset from the right edge of the frame (defaults to inset) diff --git a/src/projection.js b/src/projection.js index 07ab9a70f6..11061eefa1 100644 --- a/src/projection.js +++ b/src/projection.js @@ -74,7 +74,18 @@ export function Projection( // Otherwise wrap the projection stream with a suitable transform. If a domain // is specified, fit the projection to the frame. Otherwise, translate. if (domain) { - const [[x0, y0], [x1, y1]] = geoPath(projection).bounds(domain); + const fitDomain = domain.type ? [domain] : domain; + let x0 = Infinity, + y0 = x0, + x1 = -x0, + y1 = x1; + for (const domain of fitDomain) { + const [[xl, yl], [xh, yh]] = geoPath(projection).bounds(domain); + if (xl < x0) x0 = xl; + if (xh > x1) x1 = xh; + if (yl < y0) y0 = yl; + if (yh > y1) y1 = yh; + } const k = Math.min(dx / (x1 - x0), dy / (y1 - y0)); if (k > 0) { tx -= (k * (x0 + x1) - dx) / 2; diff --git a/test/plots/projection-fit-antarctica.js b/test/plots/projection-fit-antarctica.js index 430c7e1ba8..9c5ff1ed7a 100644 --- a/test/plots/projection-fit-antarctica.js +++ b/test/plots/projection-fit-antarctica.js @@ -4,7 +4,7 @@ import {feature} from "topojson-client"; export default async function () { const world = await d3.json("data/countries-50m.json"); - const domain = feature( + const ata = feature( world, world.objects.countries.geometries.find((d) => d.properties.name === "Antarctica") ); @@ -12,7 +12,7 @@ export default async function () { width: 600, height: 600, inset: 30, - projection: {type: "azimuthal-equidistant", rotate: [0, 90], domain}, - marks: [Plot.graticule({clip: "frame"}), Plot.geo(domain, {clip: "frame", fill: "currentColor"}), Plot.frame({})] + projection: {type: "azimuthal-equidistant", rotate: [0, 90], domain: [ata]}, + marks: [Plot.graticule({clip: "frame"}), Plot.geo(ata, {clip: "frame", fill: "currentColor"}), Plot.frame({})] }); }