D3.js map display on canvas

I am trying to take the contents of a canvas element (which is actually just an image loaded onto the canvas) and distort them into different map projections using d3. So, I only found one example that does this ( this other question ).

The problem is, it doesn't work with every projection. 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 projection scale too low (say 80) then the p variable (in the for loop) ends up null

. I am not sure why this is happening and I need to set the scale so that the projection fits the canvas area.

Working jsfiddle example: http://jsfiddle.net/vjnfyd8t/

+3


source to share


1 answer


(This is an interesting question)

I can't decipher what's playing here, but FWIW, this is an implementation of the Lagrange methodinvert()

. Obviously there are times when it returns null, presumably whenever x or y is outside some extents (x, y are pre-converted here ). So my guess is that you should ignore the zeros (for example by setting the output pixel to transparent) and you can still end up with the correct scaled map at the end.

This is what I get by just ignoring null

(but highlighting them in red to illustrate where this is happening)



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

      

If the scale is set to 94, the red bar disappears completely and appears to be optimal (at least at this scale). Is this what you wanted?

+1


source







All Articles