我尝试在this example之后使用 map 的栅格投影。如果我将示例kavrayskiy7投影更改为Azimuthal等距投影,

var projection = d3.geo.azimuthalEquidistant()
    .scale(90)
    .translate([width / 2, height / 2])
    .clipAngle(180 - 1e-3)
    .precision(.1);

它应该将地球投影到光盘上(投影图的图像)。但是,栅格重新投影超出了该光盘范围,并用扩展的图片填充了整个 Canvas (反向投影功能不是注入(inject)性的, map 上的几个x/y点对应于一个lon/lat坐标)。在原始示例中,应避免使用以下行
if (λ > 180 || λ < -180 || φ > 90 || φ < -90) { i += 4; continue; }

但对于此示例不起作用。例如,在使用Mollweide投影时,我发现了其他故障(由于极点效果,两条线出现在极点处)。

为了解决这个问题,一种方法是固定反投影,以使它们在x/y输入超出范围时返回错误或“无”。我的尝试是使用整个球体的正向投影检查点是否在范围内,以获取具有 map 边界的SVG路径,如以下代码所示:
var path = d3.geo.path()
    .projection(projection);

var bdry = svg.append("defs").append("path")
    .datum({type: "Sphere"})
    .attr("id", "sphere")
    .attr("d", path);

(例如,参见this example)。但是,我发现没有简单的方法来检查点[x,y]是否在SVG封闭路径内。

所以我的问题是:
  • 反投影上是否有错误,或者我使用不正确?
  • 假设这是最好的方法,如何找到[x,y]点是否在svg路径内?
  • 出于好奇,d3 path函数的算法代码在哪里,以获取 map 的边界轮廓?我在github仓库上找不到它。

  • 谢谢。

    编辑:我遍历了this example中的所有44个投影,并发现了以下25个故障:

    阿尔伯斯,布罗姆利,科利尼翁,埃克特二世,埃克特四世,埃克特六世,锤子,希尔,古德·霍莫罗辛,兰伯特圆柱等面积,拉里维,拉斯科夫斯基,麦克布赖德-托马斯平板抛物线,麦克布赖德-托马斯平板极四边形,麦克布里德托马斯·平极正弦波,莫尔维德,自然地球,内尔·汉默,多圆锥,辛努·莫尔维德,范德格林顿,范德格林顿四世,瓦格纳四世,瓦格纳七世,温克尔·崔佩尔。

    最佳答案

    我之所以使用第二个答案,是因为这是解决同一问题的另一种方法。同样,此答案是一种替代方法,尝试避免在多边形解决方案中使用投影范围的svg轮廓的点。

    对于任何投影,此替代方法都应该(我只尝试了几次),而我的其他答案仅适用于投影到光盘上的投影。其次,此方法不会尝试定义投影区域来确定是否应渲染像素,而是使用d3.projection本身。

    由于多点可以通过projection.invert返回相同的值,因此我们可以运行正向投影以验证是否应绘制像素。

    如果是projection(projection.invert(point)) == point,则该点在我们投影的范围内。

    当然,这可能会有一些精度/舍入误差,因此可以指定一定程度的公差。

    此检查适合for循环:

    for (var y = 0, i = -1; y < height; ++y) {
        for (var x = 0; x < width; ++x) {
    
            var p = projection.invert([x, y]), λ = p[0], φ = p[1];
    
            var pxy = projection(p);
    
            var tolerance = 0.5;
            if ( λ > 180 || λ < -180 || φ > 90 || φ < -90 ) { i += 4; continue; }
            if ( (Math.abs(pxy[0] - x) < tolerance ) && (Math.abs(pxy[1] - y) < tolerance ) ) {
    
                var q = ((90 - φ) / 180 * dy | 0) * dx + ((180 + λ) / 360 * dx | 0) << 2;
                targetData[++i] = sourceData[q];
                targetData[++i] = sourceData[++q];
                targetData[++i] = sourceData[++q];
                targetData[++i] = 255;
    
            }
            else {
                i += 4;
            }
        }
    }
    

    与其他答案一样,我从here中构建了一个块。

    我尚未检查此答案的性能,似乎需要这种检查似乎很奇怪,但这可能是您问题中提出的svg方法的合适替代方法。

    关于javascript - 如何在d3制图栅格重投影上固定 map 边界?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41832043/

    10-11 22:11
    查看更多