A widget that can be used to compare two images by dragging.
Photos are taken from Google Earth, I do not own them. The grayscale one is from 2003, while the other is from 2013. By dragging the photos, you can see the bridge that has been destroyed in 2009 at the bottom of the picture.
Inspired in part by this ABC page on the Fukushima disaster.
The technique used leverages SVG image patterns. A hack (an overlayed gray rectangle) is used to hide the ugly progressive rendering of image loading.
(function() {
window.main = function() {
var WIDTH, drag, status;
WIDTH = 535;
status = {
x: WIDTH - 135
};
/* do an intitial transition
*/
d3.select('#after').transition().duration(1600).attr('x', status.x).attr('width', WIDTH - status.x);
/* define a drag behavior
*/
drag = d3.behavior.drag().origin(function(d) {
return d;
}).on('drag', function(d) {
/* move the layer
*/ d.x = d3.event.x;
return d3.select('#after').attr('x', Math.max(0, d.x)).attr('width', Math.max(0, WIDTH - Math.max(0, d.x)));
});
/* drag anywhere to move the slider
*/
/* the slider is also used to hide image preloading
*/
return d3.select('#overlay').datum(status).style('fill', 'transparent').call(drag);
};
}).call(this);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Before/after image</title>
<link type="text/css" href="index.css" rel="stylesheet"/>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="index.js"></script>
</head>
<body onload="main()">
<svg width="960" height="500">
<defs>
<pattern id="before_pattern" patternUnits="userSpaceOnUse" width="535" height="500">
<image xlink:href="before.png" x="0" y="0" width="535" height="500" />
</pattern>
<pattern id="after_pattern" patternUnits="userSpaceOnUse" width="535" height="500">
<image xlink:href="after.png" x="0" y="0" width="535" height="500" />
</pattern>
</defs>
<g transform="translate(230,24) scale(0.9)">
<rect id="before" fill="url(#before_pattern)" x="0" y="0" width="535" height="500"/>
<rect id="after" fill="url(#after_pattern)" x="0" y="0" width="535" height="500"/>
<rect id="overlay" fill="transparent" x="-20" y="0" width="575" height="500"/>
</g>
</svg>
</body>
</html>
window.main = () ->
WIDTH = 535
status = {x: WIDTH-135}
### do an intitial transition ###
d3.select('#after')
.transition().duration(1600)
.attr('x', status.x)
.attr('width', WIDTH-status.x)
### define a drag behavior ###
drag = d3.behavior.drag()
.origin((d) -> d)
.on 'drag', (d) ->
### move the layer ###
d.x = d3.event.x
d3.select('#after')
.attr('x', Math.max(0, d.x))
.attr('width', Math.max(0, WIDTH-Math.max(0, d.x)))
### drag anywhere to move the slider ###
### the slider is also used to hide image preloading ###
d3.select('#overlay')
.datum(status)
.style('fill', 'transparent')
.call drag
#overlay {
fill: #333333;
cursor: move;
}
body {
background: #333333;
}
#overlay
fill: #333
cursor: move
body
background: #333