Skip to content

Commit 2f7a2c7

Browse files
authored
Determine the default height when the projection domain is set (#2102)
* Determine the default height when the projection domain is set closes #2063 * Only scale if passed a width (height being always passed with width, there's no need to check both) the case where width and height are undefined is when we are testing the projection's aspect ratio with a given domain Note that the path in the SVG is broken (full of NaN) when projection.scale() === 0. This seems to be a secondary issue. * adding the case where the projection is given by a {type: function, domain}
1 parent 53d757e commit 2f7a2c7

16 files changed

+705
-511
lines changed

src/dimensions.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ function autoHeight(
9494
) {
9595
const nfy = fy ? fy.scale.domain().length : 1;
9696

97-
// If a projection is specified, use its natural aspect ratio (if known).
97+
// If a projection is specified, compute an aspect ratio based on the domain,
98+
// defaulting to the projection’s natural aspect ratio (if known).
9899
const ar = projectionAspectRatio(projection);
99100
if (ar) {
100101
const nfx = fx ? fx.scale.domain().length : 1;

src/projection.js

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,10 @@ function scaleProjection(createProjection, kx, ky) {
167167
if (precision != null) projection.precision?.(precision);
168168
if (rotate != null) projection.rotate?.(rotate);
169169
if (typeof clip === "number") projection.clipAngle?.(clip);
170-
projection.scale(Math.min(width / kx, height / ky));
171-
projection.translate([width / 2, height / 2]);
170+
if (width != null) {
171+
projection.scale(Math.min(width / kx, height / ky));
172+
projection.translate([width / 2, height / 2]);
173+
}
172174
return projection;
173175
},
174176
aspectRatio: ky / kx
@@ -183,7 +185,7 @@ function conicProjection(createProjection, kx, ky) {
183185
const projection = type(options);
184186
if (parallels != null) {
185187
projection.parallels(parallels);
186-
if (domain === undefined) {
188+
if (domain === undefined && width != null) {
187189
projection.fitSize([width, height], {type: "Sphere"});
188190
}
189191
}
@@ -234,16 +236,25 @@ export function hasProjection({projection} = {}) {
234236
return projection != null;
235237
}
236238

237-
// When a named projection is specified, we can use its natural aspect ratio to
238-
// determine a good value for the projection’s height based on the desired
239-
// width. When we don’t have a way to know, the golden ratio is our best guess.
240-
// Due to a circular dependency (we need to know the height before we can
241-
// construct the projection), we have to test the raw projection option rather
242-
// than the materialized projection; therefore we must be extremely careful that
243-
// the logic of this function exactly matches createProjection above!
239+
// When a projection is specified, we can use its aspect ratio to determine a
240+
// good value for the projection’s height based on the desired width. When we
241+
// don’t have a way to know, the golden ratio is our best guess. Due to a
242+
// circular dependency (we need to know the height before we can construct the
243+
// projection), we have to test the raw projection option rather than the
244+
// materialized projection; therefore we must be extremely careful that the
245+
// logic of this function exactly matches createProjection above!
244246
export function projectionAspectRatio(projection) {
245247
if (typeof projection?.stream === "function") return defaultAspectRatio;
246-
if (isObject(projection)) projection = projection.type;
248+
if (isObject(projection)) {
249+
let domain, options;
250+
({domain, type: projection, ...options} = projection);
251+
if (domain != null && projection != null) {
252+
const type = typeof projection === "string" ? namedProjection(projection).type : projection;
253+
const [[x0, y0], [x1, y1]] = geoPath(type({...options, width: 100, height: 100})).bounds(domain);
254+
const r = (y1 - y0) / (x1 - x0);
255+
return r && isFinite(r) ? (r < 0.2 ? 0.2 : r > 5 ? 5 : r) : defaultAspectRatio;
256+
}
257+
}
247258
if (projection == null) return;
248259
if (typeof projection !== "function") {
249260
const {aspectRatio} = namedProjection(projection);

test/output/geoText.svg

Lines changed: 67 additions & 67 deletions
Loading

test/output/geoTip.svg

Lines changed: 104 additions & 104 deletions
Loading

test/output/geoTipCentroid.svg

Lines changed: 104 additions & 104 deletions
Loading

test/output/geoTipGeoCentroid.svg

Lines changed: 104 additions & 104 deletions
Loading

test/output/geoTipXY.svg

Lines changed: 104 additions & 104 deletions
Loading
Lines changed: 22 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)