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 ) ); }; };