D3.js在画布图像上的地图投影

5
我正在尝试使用d3将画布元素(实际上只是加载到画布上的图像)的内容变形成不同的地图投影。目前我只找到了一个能够实现此功能的例子(来自于Stack Overflow上的这个问题)。
问题在于它并不能适用于所有的投影方式。以下是代码:
var height = 375,
    width = 750;

var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
canvas.width = width;
canvas.height = height;

var context = canvas.getContext('2d');

var projection = d3.geo.lagrange()
    .translate([width/2, height/2])
    .scale(100); //SET SCALE HERE

var path = d3.geo.path().projection(projection);

var image = new Image();
image.crossOrigin = 'anonymous';
image.src = 'http://i.imgur.com/zZkxbz7.png';
image.onload = function() {
    var dx = width,
        dy = height;

    context.drawImage(image, 0, 0, dx, dy);

    var sourceData = context.getImageData(0, 0, dx, dy).data,
        target = context.createImageData(dx, dy),
        targetData = target.data;

    for (var y = 0, i = -1; y < height; ++y) {
        for (var x = 0; x < width; ++x) {
            var p = projection.invert([x, y]),    //ERROR HERE
                λ = p[0],
                φ = p[1];
            if (λ > 180 || λ < -180 || φ > 90 || φ < -90) {
                i += 4;
                continue;
            }
            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;
        }
    }

    context.clearRect(0, 0, width, height);
    context.putImageData(target, 0, 0);
}

在上面的例子中,如果我将投影的比例设置得太低(比如80),那么for循环中的变量p最终会变成null。我不确定为什么会发生这种情况,我需要设置比例使得投影适合画布区域。
一个可工作的jsfiddle示例:http://jsfiddle.net/vjnfyd8t/
1个回答

1

这是一个有趣的问题。

我无法完全理解其中的原理,但值得一提的是,这是拉格朗日反演方法invert()的实现。显然,当x或y超出某些范围时(x,y在此处进行了预转换),它会返回null。所以我猜你应该忽略null(例如通过将输出像素设置为透明),最终仍然可以得到一个合适的缩放地图。

忽略null后,这就是我得到的结果(但用红色突出显示了发生的位置)。

if (!p) {
  targetData[++i] = 255;
  targetData[++i] = 0;
  targetData[++i] = 0;
  targetData[++i] = 255;
  continue;
}

如果将比例尺设置为94,则红色带完全消失,似乎是最合适的(至少在该比例尺下)。 这就是你想要的吗?

1
我花了很多时间试图弄清楚为什么它是null。从库支持的所有投影中,有足足3个(至少我能看出来的)最终会产生null。所以我只是幸运(不幸?)在我的测试中恰好选择了其中之一。虽然还有其他一些投影的奇怪之处(例如collignon),但你已经回答了主要问题。谢谢。 - Kurt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接