D3 v4反转功能
问题描述:
我想使用反投影将JPG底图投影到正投影上。我已经能够在D3的v3中使用它,但是我在D3的v4中遇到了问题。出于某种原因,v4将源图像的边缘作为背景(而不是我指定的黑色背景)。是否有任何已知的v4逆向投影问题或针对此问题的任何修复?D3 v4反转功能
-
<title>Final Project</title> <style> canvas { background-color: black; } </style> <body> <div id="canvas-image-orthographic"></div> <script src="//d3js.org/d3.v4.min.js"></script> <script> // Canvas element width and height var width = 960, height = 500; // Append the canvas element to the container div var div = d3.select('#canvas-image-orthographic'), canvas = div.append('canvas') .attr('width', width) .attr('height', height); // Get the 2D context of the canvas instance var context = canvas.node().getContext('2d'); // Create and configure the Equirectangular projection var equirectangular = d3.geoEquirectangular() .scale(width/(2 * Math.PI)) .translate([width/2, height/2]); // Create and configure the Orthographic projection var orthographic = d3.geoOrthographic() .scale(Math.sqrt(2) * height/Math.PI) .translate([width/2, height/2]) .clipAngle(90); // Create the image element var image = new Image(width, height); image.crossOrigin = "Anonymous"; image.onload = onLoad; image.src = 'https://tatornator12.github.io/classes/final-project/32908689360_24792ca036_k.jpg'; // Copy the image to the canvas context function onLoad() { // Copy the image to the canvas area context.drawImage(image, 0, 0, image.width, image.height); // Reads the source image data from the canvas context var sourceData = context.getImageData(0, 0, image.width, image.height).data; // Creates an empty target image and gets its data var target = context.createImageData(image.width, image.height), targetData = target.data; // Iterate in the target image for (var x = 0, w = image.width; x < w; x += 1) { for (var y = 0, h = image.height; y < h; y += 1) { // Compute the geographic coordinates of the current pixel var coords = orthographic.invert([x, y]); // Source and target image indices var targetIndex, sourceIndex, pixels; // Check if the inverse projection is defined if ((!isNaN(coords[0])) && (!isNaN(coords[1]))) { // Compute the source pixel coordinates pixels = equirectangular(coords); // Compute the index of the red channel sourceIndex = 4 * (Math.floor(pixels[0]) + w * Math.floor(pixels[1])); sourceIndex = sourceIndex - (sourceIndex % 4); targetIndex = 4 * (x + w * y); targetIndex = targetIndex - (targetIndex % 4); // Copy the red, green, blue and alpha channels targetData[targetIndex] = sourceData[sourceIndex]; targetData[targetIndex + 1] = sourceData[sourceIndex + 1]; targetData[targetIndex + 2] = sourceData[sourceIndex + 2]; targetData[targetIndex + 3] = sourceData[sourceIndex + 3]; } } } // Clear the canvas element and copy the target image context.clearRect(0, 0, image.width, image.height); context.putImageData(target, 0, 0); } </script>
答
的问题是,反转功能不是一一对应的。我知道有两种方法可以解决问题。一,计算组成投影的光盘区域,并跳过该半径之外的像素。或两个(其中下面我使用),计算你的坐标的前方突出,并查看它们是否匹配的X,Y坐标,你开始:
if (
(Math.abs(x - orthographic(coords)[0]) < 0.5) &&
(Math.abs(y - orthographic(coords)[1]) < 0.5)
)
本质上讲,这是问[x,y]
等于projection(projection.invert([x,y]))
。通过确保这个陈述是相等的(或接近相等),那么该像素确实在投影盘中。这是需要的,因为多个svg点可以代表一个给定的经验值,但是projection()
只会返回您想要的值。
在上面的代码块中有一个容差因子用于舍入误差,只要前向投影在原始x,y坐标的半个像素内,它将被绘制(这似乎工作得很好) :
我有一个更新斌here(点击运行,我未选中自动运行)。当然,与计算投影光盘的半径(但该方法仅限于投影到光盘的投影)相比,这是计算上涉及的计算过程。
这question的两个答案可能能够进一步解释 - 他们涵盖了两种方法。
非常感谢!我必须更清楚地阅读你的答案,以及你提供的其他SO问题。 – Lprox5
自从您的帮助以来,我已经能够将一个拖曳功能(使用versor)应用于画布图像的正投影。我也可以叠加一个SVG点(代表过去任务的“着陆点”)。但是,我无法使用SVG拖动功能来处理这些问题。我有一个新的JSBin设置[在这里](https://jsbin.com/moconod/edit?html,output)。任何想法为什么这可能是这种情况?我能够用画布绘制点,但是我发现为点创建工具提示太困难了。 – Lprox5
你可以不理会!我只是通过更新每个拖动功能中的地图路径来实现它的工作:) – Lprox5