キャンバス要素 (実際にはキャンバスにロードされた単なる画像) のコンテンツを取得し、d3 を使用してそれらをさまざまなマップ投影に歪めようとしています。したがって、これを行う例を1つだけ見つけました( this other SO question )。
問題は、すべての投影で機能しないことです。コード:
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/