Cannot Hide Labels 'behind' Spinning D3 Globe
Solution 1:
I noted a potential hurdle with using coordinates to determine label visibility in my comment above. However, there is another way to determine if a label should be visible: determining if a country's svg path has an attribute 'd' that is not null.
First, id's will need to be set properly, currently d.properties.name includes spaces, so setting ids with:
.attr("id", function(d) { return d.properties.name.split(' ').join('_'); })
will allow for better identification of places such as the United Kingdom and United States.
By selecting each path based on id, we can see if it has any data defining its shape. If it is not shown, the 'd' property of the path will be null.
if (d3.select("#"+d.properties.name.split(' ').join('_')).attr('d') != null) {
return'inline';
}
else {
return'none';
}
Updated fiddle: here
Using a different text anchor might center your text better as well:
.style("text-anchor","middle");
Fiddle with text anchor of middle: here
--- Update --- While the code above will hide labels for countries not drawn (completely behind the globe), if any portion of the country is drawn then a label will be created. A lot of issues around this can be addressed by not drawing labels that are a certain distance from the center: fiddle, as mentioned in comment below.
However, for some large countries such as Russia, the geographic centroid (and thus label location) can fall within the specified radius and will be drawn if a tiny sliver of the country is rendered. When this happens the geographic centroid, rather than the svg centroid, will be used to label the country. In these cases, the geographic centroid is on the far side of the earth, but rendered as though it were on the visible side.
Also, in the case of France, the svg centroid and geographic centroid will be problematic:
A couple methods could be used to aid in toggling of labels, such as computing and recording the geographic centroids in the geographic data and using the angular distance from the map projection center to show/hide the labels. In the case of France, splitting Guiana off would be useful.
Without modifying the data, another criterion can be used to select which labels should be visible: seeing if the center of the bounding box of the country as drawn is near the edge of the map. It adds an extra layer of computation, but if each criterion is only checked if needed, it should be ok: http://jsfiddle.net/0ptcy7f3/1/
var country = d3.select("#"+d.properties.name.split(' ').join('_'));
// Exclude labels this far from center:var r = 350;
// Check to see if the country has a path visible as beforeif (country.attr('d') != null) {
// Then check to see if the bounding box // for the country as drawn is far from centervar BB = country.node().getBBox();
var x = (BB.x + (BB.x + BB.width)) / 2;
var y = (BB.y + (BB.y + BB.height)) / 2;
if ( ( (width-x)*(width-x) + (height-y)*(height-y) ) < (r * r) ) {
// And ensure the geographic centroid is also not on the edge:
center = path.centroid(d);
x = center[0];
y = center[1];
if ( ( (width-x)*(width-x) + (height-y)*(height-y) ) < (r * r) ) {
return'inline';
}
else {
return'none';
}
}
else { return'none'; }
else { return'none'; }
The case of France is not addressed, as it's geographic path includes Guiana. A special case could be built in to the code to force the label to a particular place and to evaluate that location as a valid location. Otherwise, the data needs to be edited. This update should take care of Russia or other large/long countries.
A tweak that could be made is changing the exclusion radius as the map is zoomed in (or not doing that check at all if the map fills the whole frame).
Post a Comment for "Cannot Hide Labels 'behind' Spinning D3 Globe"