问题描述
我正在尝试将一些简单的国家/地区标签添加到D3矢量地图中,该地图位于D3瓦片栅格地图的顶部.标签正在按预期方式创建,但是我无法在地图上正确投影它们. D3区块中的投影有些混乱(我的意思是它的工作方式不像在正常"矢量地图上,我也不理解).
I am trying to add some simple country labels to a D3 vector map which is layered on top of a D3-tile raster map. The labels are being created in as expected, but I am not able to project them properly on the map. The projection in D3-tile is a bit messed up (by which I mean it doesn't work like on a 'normal' vector map, and I don't understand it).
我已经创建了jsfiddle ,在其中创建地图,然后尝试对其进行投影这样他们就可以与用户互动.
I have created a jsfiddle where I create the maps and then try to project them so that they move around with user interaction.
无法实现这一点的代码在这里:
Bit of code that fails to achieve this is here:
d3.selectAll(".country_labels")
.attr("transform", function(d) {return "translate(" + path.centroid(d) + ")"})
更新
我怀疑我在此问题上的问题类似于我今天早些时候提出的问题这里.我还注意到,在这里提出了类似的问题 .
I suspect my issue on this question is similar to the one I raised earlier today on here. I also note that a similar-ish question was raised here too.
我已经取得了一些进展,并将这个新的 fiddle 组合在一起.这些标签现在都在地图上,但是漂浮在几内亚湾附近,靠近地理坐标[0,0].对我来说,这意味着它们可能已经正确投影,但是变焦未达到预期的效果.这里的问题是此脚本中有三种单独的坐标类型:
I have made some progress and put together this new fiddle. The labels are now all on the map, but floating around the gulf of guinea, close to geocoordinates [0,0]. To me, this means they may have been projected properly but that the zoom has not functioned as expected. The issue here is that there are three separate types of coordinates in this script:
- 地理坐标-这些是起点,并且始终是固定的
- "d3-tile"坐标.适合单个像素的像素,因此总是非常接近零
- 像素坐标-这些对应于屏幕上的实际坐标
- Geocoordinates - these are the starting point and always fixed
- The 'd3-tile' coordinates. The ones that fit within a single pixel, and therefore always very close to zero
- Pixel coordinates - these correspond to the actual coordinates on the screen
推荐答案
这与您的其他问题类似,只是正向投影&缩放而不是反转. (我在更新之前就开始编写此代码,但是必须运行,我将继续使用您的原始代码).
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){return path.centroid(d)[0];})
.attr("y", function(d){return path.centroid(d)[1];})
.attr("dx", -40)
.text(function(d){ return d.properties.name })
.style("fill", "#aeaeaf")
.style("font-size", "15px")
这里有一个问题,因为大多数d3-tile实例(包括您的实例)的投影使用的d3投影比例为1/tau,世界投影在1个像素的空间内,因此dx值等于40个世界,在应用缩放功能时将无法使用,因此请放下该部分
现在,您或多或少像路径一样附加了要素,但是问题出在缩放处理上:
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);
但是这里有一些区别:
-
与文本相比,您正在对路径应用不同的变换(缩放和平移):对于文本,没有引用当前的缩放变换,而是仅使用锚定的投影在0,0处,所有要素都位于一个像素的区域内(锚定在0,0处,其基线在y = 0处,文本将在很大程度上看不见).如果您检查svg,则会在错误的位置看到文本.
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.
随着路径的放大,路径的笔画宽度减小(当我们缩放svg时,笔画宽度本身会增加),这同样适用于文本,因此即使文本正确放置,它也会非常大(比大多数装有浏览器的屏幕都要大).
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).
我们可以解决此问题的一种方法是,将缩放变换应用于文本的x/y坐标,而不是元素本身(这也会缩放文本大小,因此无需调整文本大小)完全没有):
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){返回transform.apply(path.centroid(d)) 1 ;})
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;})
与从svg像素反转为经/纬度类似,我们经历了相同的动作,但顺序相反:应用投影,然后应用缩放.
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.
这是更新的小提琴.
但是,我有个坏消息-标签的位置正好在您告诉他们现在要放置的位置.但是它们并不是您想要的地方(俗话说,关于编程的最好的事情是代码完全按照您说的去做,而关于编程的最糟糕的事情是代码确实在做到底是你所说的吗?).
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?).
您正在使用路径质心来放置标签,此功能有时对某些功能有效,但并非始终有效.以美国为例,使用墨卡托投影的美国质心不在美国,因为它位于阿拉斯加和下48个州之间(对不起,夏威夷,您在这里没有太多的吸引力).加拿大的质心部分位于北冰洋,并且在许多数据集中(不足为奇),由于法属圭亚那,使用质心作为文本锚点时,法国被标记为大西洋中部.
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.
您可以使用.style("text-anchor","middle")
稍微改善视觉外观,将其至少居中放置在标签上(对较小的国家或衡平国家来说非常有用),但最终质心放置并不理想.
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.
这篇关于无法使标签与D3瓦片投影配合使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!