title: Using D3.js to convert map projections on canvas
body: <p>What I'm doing:</p>
  
  <p>I have a way to upload an image onto a canvas. Then, I'm using d3's map projections to allow the selection of a different map projection to convert the image to.</p>
  
  <p>The problem:</p>
  
  <p>The conversion only works if the original image is an equirectangular projection. For example, if I upload an equirectangular Earth map, then tell it to convert it to a Robinson projection, it works fine. If I upload a Robinson map image, then try to convert to an equirectangular projection, all it does is fill in the transparent data with color (i.e. it doesn't work).</p>
  
  <p>The code I'm using:</p>
  
  <pre><code>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") &gt; -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 &lt; dy; ++y) {
              for (var x = 0; x &lt; 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 (λ &gt; 180 || λ &lt; -180 || φ &gt; 90 || φ &lt; -90) {
                      i += 4;
                      continue;
                  }
                  var q = ((90 - φ) / 180 * dy | 0) * dx + ((180 + λ) / 360 * dx | 0) &lt;&lt; 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();
  }
  </code></pre>
  
  <p>See <a href="http://jsfiddle.net/vjnfyd8t/3/" rel="nofollow noreferrer">this jsfiddle</a> for a working example. Notice that instead of actually converting the map, it's just filled in the previously transparent areas with white. The converted image <em>should</em> look like <a href="https://i.imgur.com/FJXtMkd.jpg" rel="nofollow noreferrer">this</a>.</p>