The above grid shows the effect of fisheye distortion. Move the mouse to change the focal point.
forked from mbostock's block: Fisheye Grid
license: gpl-3.0 |
The above grid shows the effect of fisheye distortion. Move the mouse to change the focal point.
forked from mbostock's block: Fisheye Grid
(function() { | |
d3.fisheye = function() { | |
var radius = 200, | |
power = 2, | |
k0, | |
k1, | |
center = [0, 0]; | |
function fisheye(d) { | |
var dx = d[0] - center[0], | |
dy = d[1] - center[1], | |
dd = Math.sqrt(dx * dx + dy * dy); | |
if (dd >= radius) return d; | |
var k = k0 * (1 - Math.exp(-dd * k1)) / dd * .75 + .25; | |
return [center[0] + dx * k, center[1] + dy * k]; | |
} | |
function rescale() { | |
k0 = Math.exp(power); | |
k0 = k0 / (k0 - 1) * radius; | |
k1 = power / radius; | |
return fisheye; | |
} | |
fisheye.radius = function(_) { | |
if (!arguments.length) return radius; | |
radius = +_; | |
return rescale(); | |
}; | |
fisheye.power = function(_) { | |
if (!arguments.length) return power; | |
power = +_; | |
return rescale(); | |
}; | |
fisheye.center = function(_) { | |
if (!arguments.length) return center; | |
center = _; | |
return fisheye; | |
}; | |
return rescale(); | |
}; | |
})(); |
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
.background { | |
fill: none; | |
pointer-events: all; | |
} | |
path { | |
fill: none; | |
stroke: #333; | |
} | |
</style> | |
<body> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script src="fisheye.js"></script> | |
<script> | |
var width = 960, | |
height = 500, | |
xStepsBig = d3.range(10, width, 20), | |
yStepsBig = d3.range(10, height, 20), | |
xStepsSmall = d3.range(0, width + 6, 6), | |
yStepsSmall = d3.range(0, height + 6, 6); | |
var fisheye = d3.fisheye(); | |
var line = d3.line(); | |
var svg = d3.select("body").append("svg") | |
.attr("width", width) | |
.attr("height", height) | |
.append("g") | |
.attr("transform", "translate(-.5,-.5)"); | |
svg.append("rect") | |
.attr("class", "background") | |
.attr("width", width) | |
.attr("height", height); | |
svg.selectAll(".x") | |
.data(xStepsBig) | |
.enter().append("path") | |
.attr("class", "x") | |
.datum(function(x) { return yStepsSmall.map(function(y) { return [x, y]; }); }); | |
svg.selectAll(".y") | |
.data(yStepsBig) | |
.enter().append("path") | |
.attr("class", "y") | |
.datum(function(y) { return xStepsSmall.map(function(x) { return [x, y]; }); }); | |
var path = svg.selectAll("path") | |
.attr("d", line); | |
svg.on("mousemove", function() { | |
fisheye.center(d3.mouse(this)); | |
path.attr("d", function(d) { return line(d.map(fisheye)); }); | |
}); | |
</script> |