D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
nbremer
Full window
Github gist
Smooth Fisheye
Built with
blockbuilder.org
<!DOCTYPE html> <head> <meta charset="utf-8"> </head> <body> <!-- Based entirly on https://www.nytimes.com/newsgraphics/2014/02/14/fashion-week-editors-picks/ but only the required bits for 1 canvas --> <div id="monthFisheye"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script> <script> var width = 1000, height = 500; var monthFisheye = d3.selectAll("#monthFisheye"); var canvas = monthFisheye.append("canvas"); var pixelRatio = 1, storeRatio = 1, enabled = false; if (window.devicePixelRatio >= 2 && screen.availWidth >= 1280 // iPad can’t even handle it && canvas.node().getContext("2d").webkitBackingStorePixelRatio !== 2) { // Safari can’t even pixelRatio = 2; storeRatio = 2; }//if canvas .attr("height", height * storeRatio) .style("height", height + "px"); var context = canvas.node().getContext("2d"); context.scale(storeRatio, storeRatio); d3.select(window) .on("resize", resize); resize(); // Recompute bounding boxes due to reflow. function resize() { width = parseInt(monthFisheye.style("width")); monthFisheye.select("canvas") .attr("width", width * storeRatio) .style("width", width + "px"); enableFisheye(canvas); }//resize function enableFisheye() { var that = this, link = that.parentNode, touchtime; var image = new Image, desiredDistortion = 0, desiredFocus, idle = true; var numRows = 12, normalHeight = height / numRows, imageWidth = width, imageHeight = 300; var y = fisheye() .distortion(0) .extent([0, height]); canvas //.on("mousedown", mousedown) .on("mouseover", mouseover) .on("mousemove", mousemove) .on("mouseout", mouseout) .on("touchstart", touchstart) .on("touchmove", mousemove) .on("touchend", mouseout); render(); function render() { context.clearRect(0, 0, width, height); for (var i = 0, n = numRows; i < n; ++i) { var y0 = y(i * normalHeight), y1 = y((i + 1) * normalHeight), dy = Math.min(imageHeight, y1 - y0); // context.drawImage( // image, // 0, // Math.round((i * imageHeight + (imageHeight - dy) / 2) * pixelRatio), // imageWidth * pixelRatio, // dy * pixelRatio, // 0, // y0, // width, // dy); context.fillStyle = ('#'+ parseInt(i % 255, 16) + parseInt(255 - (i % 255), 16) + "000000").substr(0,7);; context.fillRect(0,y0,width,dy); context.strokeStyle = "rgba(255,255,255,0.8)"; context.beginPath(); context.moveTo(0, y0); context.lineTo(width, y0); context.stroke(); } context.strokeRect(0, 0, width, height); }//render function move() { if (idle) d3.timer(function() { var currentDistortion = y.distortion(), currentFocus = currentDistortion ? y.focus() : desiredFocus; idle = Math.abs(desiredDistortion - currentDistortion) < .01 && Math.abs(desiredFocus - currentFocus) < .5; y.distortion(idle ? desiredDistortion : currentDistortion + (desiredDistortion - currentDistortion) * .14); y.focus(idle ? desiredFocus : currentFocus + (desiredFocus - currentFocus) * .14); render(); return idle; }); } function mouseover() { desiredDistortion = imageHeight / normalHeight - 1; mousemove(); } function mouseout() { desiredDistortion = 0; mousemove(); } function mousemove() { desiredFocus = Math.max(0, Math.min(height - 1e-6, d3.mouse(this)[1])); move(); } // function mousedown() { // var m = Math.max(0, Math.min(height - 1e-6, d3.mouse(that)[1])); // for (var i = 0, n = numRows; i < n && y(i * normalHeight) < m; ++i); // link.href = "https://www.nytimes.com/fashion/runway/" + d.slug + "/spring-2014-rtw/" + i + "?fingerprint=true"; // } function touchstart() { d3.event.preventDefault(); mouseover(); if (d3.event.touches.length === 1) { var now = Date.now(); if (now - touchtime < 500) mousedown(), link.click(); touchtime = now; } } } function fisheye() { var min = 0, max = 1, distortion = 3, focus = 0; function G(x) { return (distortion + 1) * x / (distortion * x + 1); } function fisheye(x) { var Dmax_x = (x < focus ? min : max) - focus, Dnorm_x = x - focus; return G(Dnorm_x / Dmax_x) * Dmax_x + focus; } fisheye.extent = function(_) { if (!arguments.length) return [min, max]; min = +_[0], max = +_[1]; return fisheye; }; fisheye.distortion = function(_) { if (!arguments.length) return distortion; distortion = +_; return fisheye; }; fisheye.focus = function(_) { if (!arguments.length) return focus; focus = +_; return fisheye; }; return fisheye; } </script> </body> </html>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js