block by tophtucker 5f45926246ea3f806847d3285d21ae04

Photozoom

Full Screen

TODO: redo just using d3.interpolateZoom, duh.

index.html

<!DOCTYPE html>
<html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>

<link rel="stylesheet" type="text/css" href="main.css"/>

<body>
    
<div class="container">
  <img src="photo.jpg">
</div>

</body>

<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js" charset="utf-8"></script>
<script src="//cdn.rawgit.com/gka/d3-jetpack/master/d3-jetpack.js" charset="utf-8"></script>
<script src="main.js" charset="utf-8"></script>

</html>

main.css

html, body {
  margin: 0;
  padding: 0;
  height: 5000px;
}

.container {
  position: fixed;
}

.container img {
  position: absolute;
}

main.js

var container = d3.select('.container')
  .style('width', innerWidth + 'px')
  .style('height', innerHeight + 'px')
  .node();
var image = document.querySelector("img");

var start = {
  zoom: [.7, .7],
  center: [.5, .5]
}

var end = {
  zoom: [4, 4],
  center: [.33, .33]
}

var zoomerTween = zoomerTweener(start, end);

var scrollScale = d3.scale.linear()
  .domain([0,1000])
  .clamp(true);

window.addEventListener('scroll', handleScroll);
handleScroll();

function handleScroll() {

  var t = scrollScale(scrollY);
  var coords = zoomerTween(t);

  d3.select(image)
    .style('left', coords.x + 'px')
    .style('top', coords.y + 'px')
    .style('width', coords.width + 'px')
    .style('height', coords.height + 'px');

}

function zoomerTweener(start, end) {
  var zoomLerp = lerp(start.zoom, end.zoom);
  var centerLerp = lerp(start.center, end.center);
  return function(t) {
    var zoom = zoomLerp(t*t);
    var center = centerLerp(t);
    return zoomer(zoom, center);
  }
}

function zoomer(zoom, center) {

  var x = d3.scale.linear()
    .domain([center[0] * image.naturalWidth, center[0] * image.naturalWidth + 1])
    .range([container.offsetWidth/2, container.offsetWidth/2 + zoom[0]])
  
  var y = d3.scale.linear()
    .domain([center[1] * image.naturalHeight, center[1] * image.naturalHeight + 1])
    .range([container.offsetHeight/2, container.offsetHeight/2 + zoom[1]]);

  return {
    x: x(0),
    y: y(0),
    width: image.naturalWidth * zoom[0],
    height: image.naturalHeight * zoom[1]
  }

}

function lerp(array0,array1) {

  var scales = d3.range(array0.length).map(function(n) {
    return d3.scale.linear()
      .range([array0[n], array1[n]]);
  });
  return function(t) {
    return scales.map(function(d,i) {
      return d(t);
    })
  }
}

// https://gist.github.com/Rich-Harris/5894545
// UM NOT CURRENTLY BEING USED LOL but would be nice to ditch d3
var linearScale = function ( domain, range ) {
  var d0 = domain[0], r0 = range[0], multiplier = ( range[1] - r0 ) / ( domain[1] - d0 );

  // special case
  if ( r0 === range[1] ) {
    return function () {
      return r0;
    };
  }

  return function ( num ) {
    return r0 + ( multiplier * ( num - d0 ) );
  };
};