简体   繁体   English

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

[英]D3.js map projections on a canvas image

I'm trying to take the contents of a canvas element (which really is just an image loaded onto the canvas) and distort them into different map projections using d3. 我正在尝试获取canvas元素的内容(实际上只是加载到画布上的图像),并使用d3将其扭曲为不同的地图投影。 So for I've found exactly one example that does this ( this other SO question). 因此,对于我来说,恰好找到了一个执行此操作的示例( 另一个 SO问题)。

The problem is that it doesn't work with every projection. 问题在于它并不适用于所有投影。 The code: 代码:

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);
}

In the above example, if I set the scale of the projection too low (say 80), then the variable p (in the for loop) ends up being null . 在上面的示例中,如果我将投影比例设置得太小(例如80),则变量p(在for循环中)最终为null I'm not sure why this happens and I need to set the scale so that the projection fits within the canvas area. 我不确定为什么会发生这种情况,因此我需要设置比例,以使投影适合画布区域。

A working jsfiddle example: http://jsfiddle.net/vjnfyd8t/ 一个有效的jsfiddle示例: http : //jsfiddle.net/vjnfyd8t/

(This is an interesting question) (这是个有趣的问题)

I can't quite decipher what's at play here, but FWIW, this is the implementation of the Lagrange invert() method . 我无法完全理解这里发生的事情,但是FWIW, 这是Lagrange invert()方法的实现 Evidently, there are cases when it returns null, presumably whenever x or y are outside some extents (x,y are pre-transformed here ). 显然,在某些情况下它返回null,大概是x或y在某些范围之外(x,y在此处预先转换 )。 So I guess you're supposed to ignore the nulls (by eg setting the output pixel to transparent), and you can still get a proper scaled map at the end. 因此,我猜您应该忽略空值(例如,通过将输出像素设置为透明),最后仍然可以得到适当的缩放比例图。

This is what I get by just ignoring null s (but highlighting them in red, to illustrate where it happens) 这就是我通过忽略null 得到的(但将其突出显示为红色以说明它发生的位置)

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

If the scale is set to 94, the red band disappears completely and it seems like a best fit (at least at that scale). 如果将比例设置为94,则红色带会完全消失,并且看起来是最合适的(至少在该比例下)。 Is that what you wanted? 那是你想要的吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM