Использование D3.js для преобразования картографических проекций на холсте
Что я делаю:
У меня есть способ загрузить изображение на холст. Затем я использую проекции карты d3, чтобы позволить выбрать другую проекцию карты для преобразования изображения в.
Эта проблема:
Преобразование работает только в том случае, если исходное изображение является равноугольной проекцией. Например, если я загружаю равностороннюю карту Земли, а затем говорю ей преобразовать ее в проекцию Робинсона, она работает нормально. Если я загружаю изображение карты Робинсона, а затем пытаюсь преобразовать его в равноугольную проекцию, все, что он делает, это заполняет прозрачные данные цветом (т.е. это не работает).
Код, который я использую:
function updateMapProjection(selection) {
var projection = options[selection.selectedIndex].projection;
//projection var will be something like 'd3.geo.robinson()`
var projCanvas = document.getElementById('projectionCanvas');
var projCtx = projCanvas.getContext('2d');
projCtx.clearRect(0, 0, projCanvas.width, projCanvas.height);
var tempImage = new Image();
if (mapFile.indexOf("imgur.com") > -1) {
tempImage.crossOrigin = "Anonymous";
}
tempImage.onload = function() {
projCtx.drawImage(tempImage,0,0, projCanvas.width, projCanvas.height);
var dx = projCanvas.width;
var dy = projCanvas.height;
var sourceData = projCtx.getImageData(0, 0, dx, dy).data;
var target = projCtx.createImageData(dx, dy);
var targetData = target.data;
for (var y = 0, i = -1; y < dy; ++y) {
for (var x = 0; x < dx; ++x) {
var p = projection.invert([x, y]);
if (!p) {
targetData[++i] = 0;
targetData[++i] = 0;
targetData[++i] = 0;
targetData[++i] = 0;
continue;
}
var λ = 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;
}
}
projCtx.clearRect(0, 0, dx, dy);
projCtx.putImageData(target, 0, 0);
}
tempImage.src = mapFile;
$(".loaderWrapper").hide();
}
Смотрите этот jsfiddle для рабочего примера. Обратите внимание, что вместо фактического преобразования карты она просто заполняет ранее прозрачные области белым цветом. Преобразованное изображение должно выглядеть следующим образом.