A modified version of Mike Bostock’s mesmerising stereographic projection example.
A NASA Blue Marble raster image is reprojected using d3.geo.stereographic().invert
from the geo.projection D3 plugin.
A modified version of Mike Bostock’s mesmerising stereographic projection example.
A NASA Blue Marble raster image is reprojected using d3.geo.stereographic().invert
from the geo.projection D3 plugin.
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
body { padding: 0px 230px; background: #000; } | |
</style> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="https://raw.github.com/d3/d3-plugins/master/geo/projection/projection.js"></script> | |
<canvas id="canvas" width="540" height="500" style="width: 1080px; height: 1000px"></canvas> | |
<script> | |
var width = 500 / 2, | |
height = 500 / 2; | |
var projection = d3.geo.stereographic() | |
.scale(50) | |
.translate([width / 2, height / 2]); | |
var path = d3.geo.path() | |
.projection(projection); | |
var x = d3.scale.linear() | |
.domain([180, -180]) | |
.range([0, width * 2]); | |
var y = d3.scale.linear() | |
.domain([90, -90]) | |
.range([height * 2, 0]); | |
var image = new Image; | |
image.onload = onload; | |
image.src = "readme-world.jpeg"; | |
function onload() { | |
var canvas = document.getElementById("canvas"), | |
context = canvas.getContext("2d"), | |
sourceWidth = image.width, | |
sourceHeight = image.height; | |
context.drawImage(image, 0, 0, sourceWidth, sourceHeight); | |
var source = context.getImageData(0, 0, sourceWidth, sourceHeight).data, | |
out = context.createImageData(width, height), | |
data = out.data, | |
interpolate = bilinear(function(x, y, offset) { | |
return source[(y * sourceWidth + x) * 4 + offset]; | |
}); | |
context.clearRect(0, 0, sourceWidth, sourceHeight); | |
refresh(); | |
d3.select(window).on("mousemove", function() { | |
var p = d3.mouse(canvas); | |
projection.rotate([x.invert(p[0]), y.invert(p[1])]); | |
refresh(); | |
}); | |
function refresh() { | |
for (var y = 0; y < height; y++) { | |
for (var x = 0; x < width; x++) { | |
var i = (y * width + x) * 4, | |
location = projection.invert([x, y]), | |
sx = (180 + location[0]) / 360 * sourceWidth, | |
sy = (90 - location[1]) / 180 * sourceHeight; | |
data[i++] = interpolate(sx, sy, 0); | |
data[i++] = interpolate(sx, sy, 1); | |
data[i++] = interpolate(sx, sy, 2); | |
data[i++] = 0xff; | |
} | |
} | |
context.putImageData(out, 0, 0); | |
} | |
} | |
function bilinear(f) { | |
return function(x, y, o) { | |
var x0 = Math.floor(x), | |
y0 = Math.floor(y), | |
x1 = Math.ceil(x), | |
y1 = Math.ceil(y); | |
if (x0 === x1 || y0 === y1) return f(x0, y0, o); | |
return (f(x0, y0, o) * (x1 - x) * (y1 - y) | |
+ f(x1, y0, o) * (x - x0) * (y1 - y) | |
+ f(x0, y1, o) * (x1 - x) * (y - y0) | |
+ f(x1, y1, o) * (x - x0) * (y - y0)) / ((x1 - x0) * (y1 - y0)); | |
}; | |
} | |
</script> |