132 строки
3.0 KiB
JavaScript
132 строки
3.0 KiB
JavaScript
(function(){d3.behavior = {};
|
|
// TODO unbind zoom behavior?
|
|
// TODO unbind listener?
|
|
d3.behavior.zoom = function() {
|
|
|
|
// https://bugs.webkit.org/show_bug.cgi?id=40441
|
|
var bug40441 = /WebKit\/533/.test(navigator.userAgent) ? -1 : 0,
|
|
bug40441Last = 0,
|
|
x = 0,
|
|
y = 0,
|
|
z = 0,
|
|
listeners = [],
|
|
pan,
|
|
zoom;
|
|
|
|
function zoom() {
|
|
var container = this
|
|
.on("mousedown", mousedown)
|
|
.on("mousewheel", mousewheel)
|
|
.on("DOMMouseScroll", mousewheel)
|
|
.on("dblclick", mousewheel);
|
|
|
|
d3.select(window)
|
|
.on("mousemove", mousemove)
|
|
.on("mouseup", mouseup);
|
|
}
|
|
|
|
function mousedown(d, i) {
|
|
pan = {
|
|
x0: x - d3.event.clientX,
|
|
y0: y - d3.event.clientY,
|
|
target: this,
|
|
data: d,
|
|
index: i
|
|
};
|
|
d3.event.preventDefault();
|
|
window.focus(); // TODO focusableParent
|
|
}
|
|
|
|
function mousemove() {
|
|
zoom = null;
|
|
if (pan) {
|
|
x = d3.event.clientX + pan.x0;
|
|
y = d3.event.clientY + pan.y0;
|
|
dispatch.call(pan.target, pan.data, pan.index);
|
|
}
|
|
}
|
|
|
|
function mouseup() {
|
|
if (pan) {
|
|
mousemove();
|
|
pan = null;
|
|
}
|
|
}
|
|
|
|
function mousewheel(d, i) {
|
|
var e = d3.event;
|
|
|
|
// initialize the mouse location for zooming (to avoid drift)
|
|
if (!zoom) {
|
|
var p = d3.svg.mouse(this.nearestViewportElement || this);
|
|
zoom = {
|
|
x0: x,
|
|
y0: y,
|
|
z0: z,
|
|
x1: x - p[0],
|
|
y1: y - p[1]
|
|
};
|
|
}
|
|
|
|
// adjust zoom level
|
|
if (e.type == "dblclick") {
|
|
z = e.shiftKey ? Math.ceil(z - 1) : Math.floor(z + 1);
|
|
} else {
|
|
var delta = (e.wheelDelta / 120 || -e.detail) * .1;
|
|
|
|
/* Detect fast & large wheel events on WebKit. */
|
|
if (bug40441 < 0) {
|
|
var now = Date.now(), since = now - bug40441Last;
|
|
if ((since > 9) && (Math.abs(e.wheelDelta) / since >= 50)) bug40441 = 1;
|
|
bug40441Last = now;
|
|
}
|
|
if (bug40441 == 1) delta *= .03;
|
|
|
|
z += delta;
|
|
}
|
|
|
|
// adjust x and y to center around mouse location
|
|
var k = Math.pow(2, z - zoom.z0) - 1;
|
|
x = zoom.x0 + zoom.x1 * k;
|
|
y = zoom.y0 + zoom.y1 * k;
|
|
|
|
// dispatch redraw
|
|
dispatch.call(this, d, i);
|
|
}
|
|
|
|
function dispatch(d, i) {
|
|
var o = d3.event, // Events can be reentrant (e.g., focus).
|
|
k = Math.pow(2, z);
|
|
|
|
d3.event = {
|
|
scale: k,
|
|
translate: [x, y],
|
|
transform: function(sx, sy) {
|
|
if (sx) transform(sx, x);
|
|
if (sy) transform(sy, y);
|
|
}
|
|
};
|
|
|
|
function transform(scale, o) {
|
|
var domain = scale.__domain || (scale.__domain = scale.domain());
|
|
range = scale.range().map(function(v) { return (v - o) / k; });
|
|
scale.domain(domain).domain(range.map(scale.invert));
|
|
}
|
|
|
|
try {
|
|
for (var j = 0, m = listeners.length; j < m; j++) {
|
|
listeners[j].call(this, d, i);
|
|
}
|
|
} finally {
|
|
d3.event = o;
|
|
}
|
|
}
|
|
|
|
zoom.on = function(type, listener) {
|
|
if (type == "zoom") listeners.push(listener);
|
|
return zoom;
|
|
};
|
|
|
|
return zoom;
|
|
};
|
|
})() |