Cannot Get Labels To Work With D3-tile Projection
Solution 1:
This is similar to your other question, just it is on the forward projection & zoom rather than the inverts. (I started writing this before the update, but had to run, I'll continue with your original code).
As with the paths, you append your labels as expected:
country_labels.selectAll("text")
.data(collection.features)
.enter().append("text")
.attr("x", function(d){returnpath.centroid(d)[0];})
.attr("y", function(d){returnpath.centroid(d)[1];})
.attr("dx", -40)
.text(function(d){ return d.properties.name })
.style("fill", "#aeaeaf")
.style("font-size", "15px")
There is one concern here, as the projection of most d3-tile examples, including yours, use a d3-projection scale of 1/tau, the world is projected within the space of 1 pixel, so the dx value is equal to 40 worlds, this won't work when applying the zoom, so let's drop that part
Now you are appending the features more or less just like the paths, but the issue is in the zoom handling:
d3.selectAll(".country_labels")
.attr("transform", function(d) {return"translate(" + path.centroid(d) + ")"})
The paths are given a similar treatment:
vector
.attr("transform", "translate(" + [transform.x, transform.y] + ")scale(" + transform.k + ")")
.style("stroke-width", 1 / transform.k);
But there are a couple differences here:
you are applying a different transform (scale and translate) to the paths as compared to the text: for the text there is no reference to the current zoom transform, instead, you only use the projection, which is anchored at 0,0 with all features lying within an area of one pixel (and anchored at 0,0 will have its baseline at y=0, the text will be largely out of view). If you inspect the svg, you'll see the text, just in the wrong spot.
The paths have a reduced stroke width as one zooms in (as we are zooming the svg, the stroke width itself increases), the same would apply for text, so even if the text was correctly positioned, it would be very very large (more than most any screen holding the browser).
One way we can address this is we apply the zoom transform on the x/y coordinates of the text, not the element itself (which would scale the text size as well, this way we don't need to resize the text at all):
country_labels.selectAll("text") .attr("x", function(d){return transform.apply(path.centroid(d))[0];}) .attr("y", function(d){return transform.apply(path.centroid(d))1;})
Like with the inversion from svg pixel to lat/long, we go through the same motions, but in reverse order: apply the projection, then apply the zoom.
Here's an updated fiddle.
However, I have bad news - the labels are positioned exactly where you are telling them to be positioned now. But they aren't where you want them to be (how's the saying go, the best thing about programming is that the code does exactly what you tell it, the worst thing about programming is that the code does exactly what you tell it?).
You are using path centroids to place labels, this works sometimes for some features, but it doesn't work all the time. Take the United States for example, the centroid of the US using a Mercator projection isn't in the United States because it is between Alaska and the lower 48 states (sorry Hawaii, you don't have much pull here). The centroid of Canada is partly in the Arctic Ocean, and in many datasets (not this one surprisingly), France is labelled in the middle of the Atlantic because of French Guiana, when using centroids as the text anchor.
You can improve the visual appearance slightly by using .style("text-anchor","middle")
, which at least centers labels where the are (very useful for smaller or equitorial countries), but ultimately centroid placement isn't ideal.
I'll just finish with: Annotations are the bane of cartography.
But, there is hope, here's one of the more promising futures I've seen.
Post a Comment for "Cannot Get Labels To Work With D3-tile Projection"