Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
35e356e
Linting/formatting
camdecoster Jul 9, 2026
2d1a490
Switch default fitbounds to 'locations' for geo traces
camdecoster Jul 9, 2026
03c1e43
Save fitbounds computed values to layout
camdecoster Jul 9, 2026
a8742c8
Persist view attributes during manual zoom operations
camdecoster Jul 9, 2026
9894fdb
Update tests per new default, view attrs saved to layout
camdecoster Jul 9, 2026
82acb12
Add user view attribute gate for fitbounds
camdecoster Jul 9, 2026
0f9af80
Save center lat/lon for clipped projections
camdecoster Jul 9, 2026
02b0c92
Update tests per gate addition
camdecoster Jul 9, 2026
fe45f65
Add draftlog
camdecoster Jul 9, 2026
4f6f122
Replace undefined with null for fitbounds computed values
camdecoster Jul 10, 2026
c2b23ea
Use local variables for calculating zoom button actions
camdecoster Jul 10, 2026
93055f0
Update tests
camdecoster Jul 10, 2026
5aa17cf
Update draftlog
camdecoster Jul 10, 2026
195345c
Add test image generation timeout
camdecoster Jul 10, 2026
f04bc14
Add special handling for Albers USA
camdecoster Jul 10, 2026
e470048
Add check for projections that don't play well with fitbounds
camdecoster Jul 15, 2026
5feb26a
Simplify fitbounds default-setting logic
camdecoster Jul 16, 2026
16254c7
Update baseline images
camdecoster Jul 16, 2026
122cdd4
Skip fitbounds if axis range has been set
camdecoster Jul 16, 2026
7dd5c74
Disable fitbounds for a number of mocks
camdecoster Jul 17, 2026
087b342
Update mocks affected by axis range fix
camdecoster Jul 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions draftlogs/7895_change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- **Breaking:** Change `layout.geo.fitbounds` default from `false` to `'locations'` [[#7895](https://github.com/plotly/plotly.js/pull/7895)]
- `geo` subplots will now auto-fit the initial view to the trace data
- Set `fitbounds: false` explicitly to opt out
27 changes: 23 additions & 4 deletions src/components/modebar/buttons.js
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,8 @@ modeBarButtons.hoverClosestGeo = {
click: toggleHover
};

const ZOOM_STEP_GEO = 2;

function handleGeo(gd, ev) {
const button = ev.currentTarget;
const attr = button.getAttribute('data-attr');
Expand All @@ -603,21 +605,38 @@ function handleGeo(gd, ev) {

for (const id of geoIds) {
const geoLayout = fullLayout[id];
const geoSubplot = geoLayout._subplot;

if (attr === 'zoom') {
const { minscale, scale } = geoLayout.projection;
// Under fitbounds, geoLayout.projection.scale is undefined; read the
// effective view from the D3 projection state instead
const projection = geoSubplot.projection;
const effectiveScale = projection.scale() / geoSubplot.fitScale; // Convert to schema format (multiples of original scale)
const [rotationLon, rotationLat] = projection.rotate().map((d) => -d); // Flip sign because D3 rotation is opposite of ours
const [centerLon, centerLat] = projection.invert(geoSubplot.midPt);

const { minscale } = geoLayout.projection;
const maxscale = geoLayout.projection.maxscale ?? Infinity;
// swap if user supplied min > max so clamping is well-defined
const min = Math.min(minscale, maxscale);
const max = Math.max(minscale, maxscale);
let newScale = val === 'in' ? 2 * scale : 0.5 * scale;
let newScale = val === 'in' ? ZOOM_STEP_GEO * effectiveScale : (1 / ZOOM_STEP_GEO) * effectiveScale;

// clamp to [min, max]
if (newScale > max) newScale = max;
else if (newScale < min) newScale = min;

if (newScale !== scale) {
Registry.call('_guiRelayout', gd, id + '.projection.scale', newScale);
if (newScale !== effectiveScale) {
// Persist the currently-effective view attrs with the new scale; turn
// off fitbounds so auto-fit doesn't overwrite them on the ensuing replot
Registry.call('_guiRelayout', gd, {
[id + '.projection.scale']: newScale,
[id + '.projection.rotation.lon']: rotationLon,
[id + '.projection.rotation.lat']: rotationLat,
[id + '.center.lon']: centerLon,
[id + '.center.lat']: centerLat,
[id + '.fitbounds']: false
});
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/plots/geo/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ exports.lataxisSpan = {
'*': 180
};

// Projections whose math doesn't play well with fitbounds
exports.fitboundsIncompatible = new Set(['albers usa', 'craig', 'satellite']);

// defaults for each scope
exports.scopeDefaults = {
world: {
Expand Down
13 changes: 9 additions & 4 deletions src/plots/geo/geo.js
Original file line number Diff line number Diff line change
Expand Up @@ -353,9 +353,12 @@ proto.updateProjection = function (geoCalcData, fullLayout) {
// so here's this hack to make it respond to 'geoLayout.center'
if (geoLayout._isAlbersUsa) {
var centerPx = projection([center.lon, center.lat]);
var tt = projection.translate();

projection.translate([tt[0] - (centerPx[0] - tt[0]), tt[1] - (centerPx[1] - tt[1])]);
// If center isn't within the Albers USA bounds (clipped to the USA),
// `projection(...)` returns null so skip the recentering
if (centerPx) {
var tt = projection.translate();
projection.translate([tt[0] - (centerPx[0] - tt[0]), tt[1] - (centerPx[1] - tt[1])]);
}
}
};

Expand Down Expand Up @@ -644,7 +647,9 @@ proto.saveViewInitial = function (geoLayout) {
} else if (geoLayout._isClipped) {
extra = {
'projection.rotation.lon': rotation.lon,
'projection.rotation.lat': rotation.lat
'projection.rotation.lat': rotation.lat,
'center.lon': center.lon,
'center.lat': center.lat
};
} else {
extra = {
Expand Down
8 changes: 4 additions & 4 deletions src/plots/geo/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ var attrs = (module.exports = overrideAll(
fitbounds: {
valType: 'enumerated',
values: [false, 'locations', 'geojson'],
dflt: false,
dflt: 'locations',
editType: 'plot',
description: [
"Determines if this subplot's view settings are auto-computed to fit trace data.",
Expand All @@ -74,9 +74,9 @@ var attrs = (module.exports = overrideAll(
// TODO we should auto-fill `projection.parallels` for maps
// with conic projection, but how?

"If *locations*, only the trace's visible locations are considered in the `fitbounds` computations.",
'If *geojson*, the entire trace input `geojson` (if provided) is considered in the `fitbounds` computations,',
'Defaults to *false*.'
"If *locations* (default), only the trace's visible locations are considered in the `fitbounds` computations.",
'If *geojson*, the entire trace input `geojson` (if provided) is considered in the `fitbounds` computations.',
'If *false*, the view settings are used as-is; set this to opt out of auto-fitting.'
].join(' ')
},

Expand Down
121 changes: 72 additions & 49 deletions src/plots/geo/layout_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,26 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {

function handleGeoDefaults(geoLayoutIn, geoLayoutOut, coerce, opts) {
var subplotData = getSubplotData(opts.fullData, 'geo', opts.id);
var traceIndices = subplotData.map(function(t) { return t.index; });
var traceIndices = subplotData.map(function (t) {
return t.index;
});

var resolution = coerce('resolution');
var scope = coerce('scope');
var scopeParams = constants.scopeDefaults[scope];

var projType = coerce('projection.type', scopeParams.projType);
var isAlbersUsa = geoLayoutOut._isAlbersUsa = projType === 'albers usa';
var isAlbersUsa = (geoLayoutOut._isAlbersUsa = projType === 'albers usa');

// no other scopes are allowed for 'albers usa' projection
if(isAlbersUsa) scope = geoLayoutOut.scope = 'usa';
if (isAlbersUsa) scope = geoLayoutOut.scope = 'usa';

var isScoped = geoLayoutOut._isScoped = (scope !== 'world');
var isSatellite = geoLayoutOut._isSatellite = projType === 'satellite';
var isConic = geoLayoutOut._isConic = projType.indexOf('conic') !== -1 || projType === 'albers';
var isClipped = geoLayoutOut._isClipped = !!constants.lonaxisSpan[projType];
var isScoped = (geoLayoutOut._isScoped = scope !== 'world');
var isSatellite = (geoLayoutOut._isSatellite = projType === 'satellite');
var isConic = (geoLayoutOut._isConic = projType.indexOf('conic') !== -1 || projType === 'albers');
var isClipped = (geoLayoutOut._isClipped = !!constants.lonaxisSpan[projType]);

if(geoLayoutIn.visible === false) {
if (geoLayoutIn.visible === false) {
// should override template.layout.geo.show* - see issue 4482

// make a copy
Expand All @@ -54,29 +56,26 @@ function handleGeoDefaults(geoLayoutIn, geoLayoutOut, coerce, opts) {
newTemplate.showocean = false;
newTemplate.showrivers = false;
newTemplate.showsubunits = false;
if(newTemplate.lonaxis) newTemplate.lonaxis.showgrid = false;
if(newTemplate.lataxis) newTemplate.lataxis.showgrid = false;
if (newTemplate.lonaxis) newTemplate.lonaxis.showgrid = false;
if (newTemplate.lataxis) newTemplate.lataxis.showgrid = false;

// set ref to copy
geoLayoutOut._template = newTemplate;
}
var visible = coerce('visible');

var show;
for(var i = 0; i < axesNames.length; i++) {
for (var i = 0; i < axesNames.length; i++) {
var axisName = axesNames[i];
var dtickDflt = [30, 10][i];
var rangeDflt;

if(isScoped) {
if (isScoped) {
rangeDflt = scopeParams[axisName + 'Range'];
} else {
var dfltSpans = constants[axisName + 'Span'];
var hSpan = (dfltSpans[projType] || dfltSpans['*']) / 2;
var rot = coerce(
'projection.rotation.' + axisName.slice(0, 3),
scopeParams.projRotate[i]
);
var rot = coerce('projection.rotation.' + axisName.slice(0, 3), scopeParams.projRotate[i]);
rangeDflt = [rot - hSpan, rot + hSpan];
}

Expand All @@ -85,7 +84,7 @@ function handleGeoDefaults(geoLayoutIn, geoLayoutOut, coerce, opts) {
coerce(axisName + '.dtick', dtickDflt);

show = coerce(axisName + '.showgrid', !visible ? false : undefined);
if(show) {
if (show) {
coerce(axisName + '.gridcolor');
coerce(axisName + '.gridwidth');
coerce(axisName + '.griddash');
Expand Down Expand Up @@ -114,27 +113,27 @@ function handleGeoDefaults(geoLayoutIn, geoLayoutOut, coerce, opts) {
var centerLon = (lon0 + lon1) / 2;
var projLon;

if(!isAlbersUsa) {
if (!isAlbersUsa) {
var dfltProjRotate = isScoped ? scopeParams.projRotate : [centerLon, 0, 0];

projLon = coerce('projection.rotation.lon', dfltProjRotate[0]);
coerce('projection.rotation.lat', dfltProjRotate[1]);
coerce('projection.rotation.roll', dfltProjRotate[2]);

show = coerce('showcoastlines', !isScoped && visible);
if(show) {
if (show) {
coerce('coastlinecolor');
coerce('coastlinewidth');
}

show = coerce('showocean', !visible ? false : undefined);
if(show) coerce('oceancolor');
if (show) coerce('oceancolor');
}

var centerLonDflt;
var centerLatDflt;

if(isAlbersUsa) {
if (isAlbersUsa) {
// 'albers usa' does not have a 'center',
// these values were found using via:
// projection.invert([geoLayout.center.lon, geoLayoutIn.center.lat])
Expand All @@ -148,12 +147,12 @@ function handleGeoDefaults(geoLayoutIn, geoLayoutOut, coerce, opts) {
coerce('center.lon', centerLonDflt);
coerce('center.lat', centerLatDflt);

if(isSatellite) {
if (isSatellite) {
coerce('projection.tilt');
coerce('projection.distance');
}

if(isConic) {
if (isConic) {
var dfltProjParallels = scopeParams.projParallels || [0, 60];
coerce('projection.parallels', dfltProjParallels);
}
Expand All @@ -163,24 +162,24 @@ function handleGeoDefaults(geoLayoutIn, geoLayoutOut, coerce, opts) {
coerce('projection.maxscale');

show = coerce('showland', !visible ? false : undefined);
if(show) coerce('landcolor');
if (show) coerce('landcolor');

show = coerce('showlakes', !visible ? false : undefined);
if(show) coerce('lakecolor');
if (show) coerce('lakecolor');

show = coerce('showrivers', !visible ? false : undefined);
if(show) {
if (show) {
coerce('rivercolor');
coerce('riverwidth');
}

show = coerce('showcountries', isScoped && scope !== 'usa' && visible);
if(show) {
if (show) {
coerce('countrycolor');
coerce('countrywidth');
}

if(scope === 'usa' || (scope === 'north america' && resolution === 50)) {
if (scope === 'usa' || (scope === 'north america' && resolution === 50)) {
// Only works for:
// USA states at 110m
// USA states + Canada provinces at 50m
Expand All @@ -189,37 +188,61 @@ function handleGeoDefaults(geoLayoutIn, geoLayoutOut, coerce, opts) {
coerce('subunitwidth');
}

if(!isScoped) {
if (!isScoped) {
// Does not work in non-world scopes
show = coerce('showframe', visible);
if(show) {
if (show) {
coerce('framecolor');
coerce('framewidth');
}
}

coerce('bgcolor');

var fitBounds = coerce('fitbounds');

// clear attributes that will get auto-filled later
if(fitBounds) {
delete geoLayoutOut.projection.scale;

if(isScoped) {
delete geoLayoutOut.center.lon;
delete geoLayoutOut.center.lat;
} else if(isClipped) {
delete geoLayoutOut.center.lon;
delete geoLayoutOut.center.lat;
delete geoLayoutOut.projection.rotation.lon;
delete geoLayoutOut.projection.rotation.lat;
delete geoLayoutOut.lonaxis.range;
delete geoLayoutOut.lataxis.range;
// `fitbounds` updates a selection of view attributes, specific to the projection type.
// Check to see if a user has set any of these. If they have, skip fitbounds. Otherwise
// null out the proper attributes and run the fitting logic.
coerce('fitbounds');
if (geoLayoutOut.fitbounds) {
const centerIn = geoLayoutIn.center || {};
const projectionIn = geoLayoutIn.projection || {};
const rotationIn = projectionIn.rotation || {};
const lonaxisIn = geoLayoutIn.lonaxis || {};
const lataxisIn = geoLayoutIn.lataxis || {};
// All projection types will set these attributes
const viewAttributes = [
{ dst: geoLayoutOut.center, key: 'lon', src: centerIn },
{ dst: geoLayoutOut.center, key: 'lat', src: centerIn },
{ dst: geoLayoutOut.projection, key: 'scale', src: projectionIn }
];
// Branch order is important because scoped projections can also be clipped,
// but these should be treated as scoped below
if (isScoped) {
// Scoped only sets center, so move on
} else if (isClipped) {
viewAttributes.push(
{ dst: geoLayoutOut.projection.rotation, key: 'lon', src: rotationIn },
{ dst: geoLayoutOut.projection.rotation, key: 'lat', src: rotationIn },
{ dst: geoLayoutOut.lonaxis, key: 'range', src: lonaxisIn },
{ dst: geoLayoutOut.lataxis, key: 'range', src: lataxisIn }
);
} else {
viewAttributes.push({ dst: geoLayoutOut.projection.rotation, key: 'lon', src: rotationIn });
}

// Add entries for axis ranges with no `dst` key for non-clipped projections.
// These ranges signal user view-config intent, but non-clipped projections should
// skip the null step because it would break the fit calc.
if (!isClipped) {
viewAttributes.push({ key: 'range', src: lonaxisIn }, { key: 'range', src: lataxisIn });
}
const hasUserView = viewAttributes.some(({ src, key }) => src[key] != null); // Use loose comparison so null/undefined count as unset
if (hasUserView || constants.fitboundsIncompatible.has(projType)) {
geoLayoutOut.fitbounds = false;
} else {
delete geoLayoutOut.center.lon;
delete geoLayoutOut.center.lat;
delete geoLayoutOut.projection.rotation.lon;
// Set auto-filled view attributes to null so updateProjection can
// compute the fit from scratch and fullLayout matches user input
viewAttributes.forEach(({ dst, key }) => dst && (dst[key] = null));
}
}
}
2 changes: 2 additions & 0 deletions src/plots/geo/zoom.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ function sync(geo, projection, cb) {

cb(set);
set('projection.scale', projection.scale() / geo.fitScale);
// Turn off fitbounds so subsequent replays don't re-run the auto-fit and
// overwrite the user's dragged/scrolled position
set('fitbounds', false);
gd.emit('plotly_relayout', eventData);
}
Expand Down
4 changes: 2 additions & 2 deletions src/types/generated/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11694,8 +11694,8 @@ export interface GeoLayout {
countrywidth?: number;
domain?: Domain;
/**
* Determines if this subplot's view settings are auto-computed to fit trace data. On scoped maps, setting `fitbounds` leads to `center.lon` and `center.lat` getting auto-filled. On maps with a non-clipped projection, setting `fitbounds` leads to `center.lon`, `center.lat`, and `projection.rotation.lon` getting auto-filled. On maps with a clipped projection, setting `fitbounds` leads to `center.lon`, `center.lat`, `projection.rotation.lon`, `projection.rotation.lat`, `lonaxis.range` and `lataxis.range` getting auto-filled. If *locations*, only the trace's visible locations are considered in the `fitbounds` computations. If *geojson*, the entire trace input `geojson` (if provided) is considered in the `fitbounds` computations, Defaults to *false*.
* @default false
* Determines if this subplot's view settings are auto-computed to fit trace data. On scoped maps, setting `fitbounds` leads to `center.lon` and `center.lat` getting auto-filled. On maps with a non-clipped projection, setting `fitbounds` leads to `center.lon`, `center.lat`, and `projection.rotation.lon` getting auto-filled. On maps with a clipped projection, setting `fitbounds` leads to `center.lon`, `center.lat`, `projection.rotation.lon`, `projection.rotation.lat`, `lonaxis.range` and `lataxis.range` getting auto-filled. If *locations* (default), only the trace's visible locations are considered in the `fitbounds` computations. If *geojson*, the entire trace input `geojson` (if provided) is considered in the `fitbounds` computations. If *false*, the view settings are used as-is; set this to opt out of auto-fitting.
* @default 'locations'
*/
fitbounds?: false | 'locations' | 'geojson';
/**
Expand Down
Binary file modified test/image/baselines/canada_geo_projections.png

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also seems wrong

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disallowed a few projections because the fitbounds math can lead to undesirable results. In this case, the result looks okay, but now it's not using fitbounds due to the disallow list. For now, I think we should keep the disallow list and I can follow up with a more nuanced approach after v4.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/geo_bg-color.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/geo_bubbles-colorscales.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/geo_bubbles-sizeref.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/geo_choropleth-text.png

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again not totally clear to me how this centerpoint was chosen.

I mean, there's no reason the center has to be the Europe-centric map we're used to, although that does have the advantage of splitting fewer countries in half.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment here.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/geo_connectgaps.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/geo_country-names.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/geo_europe-bubbles.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/geo_fitbounds-locations.png

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem correct

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment here.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/geo_fitbounds-scopes.png

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is due to disallowing fitbounds with the Albers USA projection.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/geo_legendonly.png

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Green dotted line is cut off the top. Maybe this is an existing limitation with fitbounds, if so, it's not the end of the world but let's open an issue.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's an existing issue and it's on my list to work on in a follow up.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/geo_multi-geos.png

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The top plot doesn't look right, why is the orange line forced to wrap off the right edge?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is happening because the smallest gap that contains the points (not the line) is what's shown. Adding the lines to the fit check is something I'm looking into.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/geo_point-selection.png

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does fitbounds choose a center when the geoJSON wraps all the way around the globe?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It creates one big bounding box around all of the geometry and finds the smallest gap that contains that box. We use d3-geo to figure that out now, but it used to be @turf/bbox, which didn't handle the antimeridian at all.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/geo_usa-states-on-world-scope.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/grid_subplot_types.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/plot_types.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/plot_types_grid_dash.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/various_geo_projections.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading