我正在尝试使用geojson为阿联酋酋长国绘制地图。
geojson在geojson.io上是有效的并经过验证,结果显示为而不是地图的矩形,此处的代码为:
$valueBeforeLastUnderscore = rtrim(strrev(strstr(strrev($value), '_')), '_');
$valueAfterLastUnderscore = ltrim(strrchr($value, '_'), '_');
JSON数据在这里:https://files.fm/f/ndsz3v85
这是来自geojson的示例功能:
var width = 20,
height = 20;
var scal = (1 << 10) / 2 / Math.PI;
//Define map projection
var projection = d3.geo.mercator();
projection
.scale(scal)///3.5
.translate([width/2, height/2]);
//Define path generator
var path = d3.geo.path().projection(projection);
d3.json("http://localhost/data/uae-em.json", function(error,json) {
if(error) alert("error fetching data");
var svg = d3.select("article")
.append("svg")
.attr("width",width)
.attr("height",height);
//draw map
var map = svg.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path)
.style("fill", "#3498db");
});
答案 0 :(得分:0)
这里有一些问题。
首先,获得矩形的原因是由于缠绕顺序。 D3不包含geojson规范的缠绕顺序-它遵循shapefile的缠绕顺序。这很奇怪,因为D3是我想到的唯一在图纸上缠绕顺序很重要的框架,因为它使用的是球形几何图形而不是平面几何图形。就您而言,您正在绘制除阿联酋以外的所有内容:
我添加了一个笔画,我们可以看到世界的边缘(东西向+/- 180度,而不是顶部),因为墨卡托延伸到y轴上的无穷大,即使经过了倒圆或切除,限制超出了SVG的范围),我们还可以看到阿联酋的轮廓(至少是其中一部分)。因此,我们需要反转缠绕顺序,这意味着反转包含定义多边形中每个环的坐标的数组。
为此,我们可以使用turf.js预先准备数据或在每次加载数据时调用它:
json.features.forEach(function(feature) {
feature.geometry = turf.rewind(feature.geometry, {reverse:true});
})
现在我们已经按照正确的缠绕顺序获取了数据,我们得到:
该功能看起来更大,因为我们可以看到所有功能,在第一个图像中,只有最后绘制的功能才是真正可见的:它覆盖了其余功能。
现在我们有另一个问题,我已经在960x500像素的帧上显示了您的地图(使用您的代码(fiddle))。如果我们使用20x20帧和您的初始比例,则看不到任何东西。地图以[0,0]
为中心,位于非洲海岸附近的大西洋:
正方形使用您的比例尺和平移线勾勒出20x20版本中显示的地图的粗糙区域,我添加了世界地图,并将尺寸增加到200x200,以便为我们所查找的内容提供视觉效果在20像素版本中
如果目标是向全世界展示,我们需要适当的规模。圆柱投影,例如墨卡托(Mercator)(如果圆柱朝北/朝南),则围绕地球(沿赤道)旋转360度,并以地图单位将其拉伸一定距离。在d3中,比例尺是此转换因子,默认值假设整个地图上的960像素显示整个行星,地球周围为2π弧度,因此比例尺值为960 /2π(每2π弧度960像素)。因此,我们可以将您的比例尺设置为width/Math.PI/2
:
这将导致一个新问题,阿联酋跨度大约为5度,全世界大约为360度,大约占世界“宽度”的1%。在20像素乘20像素的SVG上显示地图时,这有点问题:阿联酋的宽度约为0.2像素,有些东西渲染得并不令人满意。唯一的选择是增大地图的大小,或者将地图放在阿联酋的中心并增大比例。
自动魔术贴图居中已经讨论过很多次了,我再也不会覆盖以前的出色解释(我只能说v4 / 5提供了一种出色的fitSize / fitExtent方法,但是v3居中信息可以在此question中找到)。但是,为了演示起见,我将在下面手动将阿联酋居中。
阿联酋的质心约为24 N,54E(来自here)。
如果我们假设阿联酋的宽度大于身高,并假设一个数字(例如约5度),并且要在20像素上显示这五个度,那么我们知道世界的宽度约为1440像素(mapWidthPixels * earthWidthDegrees / mapWidthDegrees = 20 * 360/5)。然后比例为1440/2 /π,向下舍入一点就得到200的额外余量。
因此使用:
var width = 20;
var height = 20;
var scale = 200;
var center = [54,24];
我们可以得到这个:
虽然很小,但是具有上述原理,很容易扩展。
我在上面的20像素SVG上添加了边框,以提供SVG的边界,因为它的尺寸较小,并且没有区分SVG边缘的位置