Skip to content

Commit 651399e

Browse files
committed
fix choropleth hover for countries w/ have polygons that cross -180
- these countries are Russia and Fiji. - Note that other countries have polygons on either side of the antimeridian (e.g. some Aleutian island for the USA), but those don't confuse the 'contains' method.
1 parent 1d2ce2d commit 651399e

File tree

3 files changed

+64
-1
lines changed

3 files changed

+64
-1
lines changed

src/traces/choropleth/hover.js

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ module.exports = function hoverPoints(pointData, xval, yval) {
2828
if(pt._polygons[j].contains([xval, yval])) {
2929
isInside = !isInside;
3030
}
31+
// for polygons that cross antimeridian as xval is in [-180, 180]
32+
if(pt._polygons[j].contains([xval + 360, yval])) {
33+
isInside = !isInside;
34+
}
3135
}
3236

3337
if(isInside) break;

src/traces/choropleth/plot.js

+20-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ function calcGeoJSON(calcTrace, topojson) {
5555
var trace = calcTrace[0].trace;
5656
var len = calcTrace.length;
5757
var features = getTopojsonFeatures(trace, topojson);
58-
var i, j, k;
58+
var i, j, k, m;
5959

6060
for(i = 0; i < len; i++) {
6161
var calcPt = calcTrace[i];
@@ -74,6 +74,25 @@ function calcGeoJSON(calcTrace, topojson) {
7474
var coords = geometry.coordinates;
7575
calcPt._polygons = [];
7676

77+
// Russia and Fiji have landmasses that cross the antimeridian,
78+
// we need to add +360 to their longitude coordinates, so that
79+
// polygon 'contains' doesn't get confused when crossing the antimeridian.
80+
//
81+
// Note that other countries have polygons on either side of the antimeridian
82+
// (e.g. some Aleutian island for the USA), but those don't confuse
83+
// the 'contains' method; these are skipped here.
84+
if(calcPt.loc === 'RUS' || calcPt.loc === 'FJI') {
85+
for(j = 0; j < coords.length; j++) {
86+
for(k = 0; k < coords[j].length; k++) {
87+
for(m = 0; m < coords[j][k].length; m++) {
88+
if(coords[j][k][m][0] < 0) {
89+
coords[j][k][m][0] += 360;
90+
}
91+
}
92+
}
93+
}
94+
}
95+
7796
switch(geometry.type) {
7897
case 'MultiPolygon':
7998
for(j = 0; j < coords.length; j++) {

test/jasmine/tests/geo_test.js

+40
Original file line numberDiff line numberDiff line change
@@ -1290,6 +1290,46 @@ describe('Test geo interactions', function() {
12901290
.catch(fail)
12911291
.then(done);
12921292
});
1293+
1294+
it('should get hover right for choropleths involving landmasses that cross antimeridian', function(done) {
1295+
var gd = createGraphDiv();
1296+
1297+
function check(lonlat, hoverLabelCnt, msg) {
1298+
var projection = gd._fullLayout.geo._subplot.projection;
1299+
var px = projection(lonlat);
1300+
1301+
mouseEvent('mousemove', px[0], px[1]);
1302+
expect(d3.selectAll('g.hovertext').size()).toBe(hoverLabelCnt, msg);
1303+
1304+
delete gd._lastHoverTime;
1305+
}
1306+
1307+
Plotly.newPlot(gd, [{
1308+
type: 'choropleth',
1309+
locations: ['RUS', 'FJI'],
1310+
z: [0, 1]
1311+
}])
1312+
.then(function() {
1313+
check([81, 66], 1, 'spot in north-central Russia that polygon.contains gets wrong before +360 shift');
1314+
check([-80, 66], 0, 'spot north of Hudson bay that polygon.contains believe is in Russia before before +360 shift');
1315+
1316+
return Plotly.relayout(gd, 'geo.projection.rotation.lon', 180);
1317+
})
1318+
.then(function() {
1319+
check([-174, 65], 1, 'spot in Russia mainland beyond antimeridian');
1320+
1321+
return Plotly.relayout(gd, {
1322+
'geo.center.lat': -16,
1323+
'geo.projection.scale': 17
1324+
});
1325+
})
1326+
.then(function() {
1327+
check([179, -16.6], 1, 'spot on Fiji island that cross antimeridian west of antimeridian');
1328+
check([-179.9, -16.2], 1, 'spot on Fiji island that cross antimeridian east of antimeridian');
1329+
})
1330+
.catch(fail)
1331+
.then(done);
1332+
});
12931333
});
12941334

12951335
describe('Test event property of interactions on a geo plot:', function() {

0 commit comments

Comments
 (0)