source: Dev/branches/jQueryUI/client/d3/d3.behavior.js @ 249

Last change on this file since 249 was 249, checked in by hendrikvanantwerpen, 13 years ago

This one's for Subversion, because it's so close...

First widget (stripped down sequencer).
Seperated client and server code in two direcotry trees.

File size: 5.9 KB
Line 
1(function(){d3.behavior = {};
2// TODO unbind zoom behavior?
3// TODO unbind listener?
4d3.behavior.zoom = function() {
5  var xyz = [0, 0, 0],
6      event = d3.dispatch("zoom");
7
8  function zoom() {
9    this
10        .on("mousedown.zoom", mousedown)
11        .on("mousewheel.zoom", mousewheel)
12        .on("DOMMouseScroll.zoom", dblclick)
13        .on("dblclick.zoom", dblclick)
14        .on("touchstart.zoom", touchstart);
15
16    d3.select(window)
17        .on("mousemove.zoom", d3_behavior_zoomMousemove)
18        .on("mouseup.zoom", d3_behavior_zoomMouseup)
19        .on("touchmove.zoom", d3_behavior_zoomTouchmove)
20        .on("touchend.zoom", d3_behavior_zoomTouchup);
21  }
22
23  // snapshot the local context for subsequent dispatch
24  function start() {
25    d3_behavior_zoomXyz = xyz;
26    d3_behavior_zoomDispatch = event.zoom.dispatch;
27    d3_behavior_zoomTarget = this;
28    d3_behavior_zoomArguments = arguments;
29  }
30
31  function mousedown() {
32    start.apply(this, arguments);
33    d3_behavior_zoomPanning = d3_behavior_zoomLocation(d3.svg.mouse(d3_behavior_zoomTarget));
34    d3.event.preventDefault();
35    window.focus();
36  }
37
38  // store starting mouse location
39  function mousewheel() {
40    start.apply(this, arguments);
41    if (!d3_behavior_zoomZooming) d3_behavior_zoomZooming = d3_behavior_zoomLocation(d3.svg.mouse(d3_behavior_zoomTarget));
42    d3_behavior_zoomTo(d3_behavior_zoomDelta() + xyz[2], d3.svg.mouse(d3_behavior_zoomTarget), d3_behavior_zoomZooming);
43  }
44
45  function dblclick() {
46    start.apply(this, arguments);
47    var mouse = d3.svg.mouse(d3_behavior_zoomTarget);
48    d3_behavior_zoomTo(d3.event.shiftKey ? Math.ceil(xyz[2] - 1) : Math.floor(xyz[2] + 1), mouse, d3_behavior_zoomLocation(mouse));
49  }
50
51  // doubletap detection
52  function touchstart() {
53    start.apply(this, arguments);
54    var touches = d3_behavior_zoomTouchup(),
55        touch,
56        now = Date.now();
57    if ((touches.length === 1) && (now - d3_behavior_zoomLast < 300)) {
58      d3_behavior_zoomTo(1 + Math.floor(xyz[2]), touch = touches[0], d3_behavior_zoomLocations[touch.identifier]);
59    }
60    d3_behavior_zoomLast = now;
61  }
62
63  zoom.on = function(type, listener) {
64    event[type].add(listener);
65    return zoom;
66  };
67
68  return zoom;
69};
70
71var d3_behavior_zoomDiv,
72    d3_behavior_zoomPanning,
73    d3_behavior_zoomZooming,
74    d3_behavior_zoomLocations = {}, // identifier -> location
75    d3_behavior_zoomLast = 0,
76    d3_behavior_zoomXyz,
77    d3_behavior_zoomDispatch,
78    d3_behavior_zoomTarget,
79    d3_behavior_zoomArguments;
80
81function d3_behavior_zoomLocation(point) {
82  return [
83    point[0] - d3_behavior_zoomXyz[0],
84    point[1] - d3_behavior_zoomXyz[1],
85    d3_behavior_zoomXyz[2]
86  ];
87}
88
89// detect the pixels that would be scrolled by this wheel event
90function d3_behavior_zoomDelta() {
91
92  // mousewheel events are totally broken!
93  // https://bugs.webkit.org/show_bug.cgi?id=40441
94  // not only that, but Chrome and Safari differ in re. to acceleration!
95  if (!d3_behavior_zoomDiv) {
96    d3_behavior_zoomDiv = d3.select("body").append("div")
97        .style("visibility", "hidden")
98        .style("top", 0)
99        .style("height", 0)
100        .style("width", 0)
101        .style("overflow-y", "scroll")
102      .append("div")
103        .style("height", "2000px")
104      .node().parentNode;
105  }
106
107  var e = d3.event, delta;
108  try {
109    d3_behavior_zoomDiv.scrollTop = 1000;
110    d3_behavior_zoomDiv.dispatchEvent(e);
111    delta = 1000 - d3_behavior_zoomDiv.scrollTop;
112  } catch (error) {
113    delta = e.wheelDelta || -e.detail;
114  }
115
116  return delta * .005;
117}
118
119// Note: Since we don't rotate, it's possible for the touches to become
120// slightly detached from their original positions. Thus, we recompute the
121// touch points on touchend as well as touchstart!
122function d3_behavior_zoomTouchup() {
123  var touches = d3.svg.touches(d3_behavior_zoomTarget),
124      i = -1,
125      n = touches.length,
126      touch;
127  while (++i < n) d3_behavior_zoomLocations[(touch = touches[i]).identifier] = d3_behavior_zoomLocation(touch);
128  return touches;
129}
130
131function d3_behavior_zoomTouchmove() {
132  var touches = d3.svg.touches(d3_behavior_zoomTarget);
133  switch (touches.length) {
134
135    // single-touch pan
136    case 1: {
137      var touch = touches[0];
138      d3_behavior_zoomTo(d3_behavior_zoomXyz[2], touch, d3_behavior_zoomLocations[touch.identifier]);
139      break;
140    }
141
142    // double-touch pan + zoom
143    case 2: {
144      var p0 = touches[0],
145          p1 = touches[1],
146          p2 = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2],
147          l0 = d3_behavior_zoomLocations[p0.identifier],
148          l1 = d3_behavior_zoomLocations[p1.identifier],
149          l2 = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2, l0[2]];
150      d3_behavior_zoomTo(Math.log(d3.event.scale) / Math.LN2 + l0[2], p2, l2);
151      break;
152    }
153  }
154}
155
156function d3_behavior_zoomMousemove() {
157  d3_behavior_zoomZooming = null;
158  if (d3_behavior_zoomPanning) d3_behavior_zoomTo(d3_behavior_zoomXyz[2], d3.svg.mouse(d3_behavior_zoomTarget), d3_behavior_zoomPanning);
159}
160
161function d3_behavior_zoomMouseup() {
162  if (d3_behavior_zoomPanning) {
163    d3_behavior_zoomMousemove();
164    d3_behavior_zoomPanning = null;
165  }
166}
167
168function d3_behavior_zoomTo(z, x0, x1) {
169  var K = Math.pow(2, (d3_behavior_zoomXyz[2] = z) - x1[2]),
170      x = d3_behavior_zoomXyz[0] = x0[0] - K * x1[0],
171      y = d3_behavior_zoomXyz[1] = x0[1] - K * x1[1],
172      o = d3.event, // Events can be reentrant (e.g., focus).
173      k = Math.pow(2, z);
174
175  d3.event = {
176    scale: k,
177    translate: [x, y],
178    transform: function(sx, sy) {
179      if (sx) transform(sx, x);
180      if (sy) transform(sy, y);
181    }
182  };
183
184  function transform(scale, o) {
185    var domain = scale.__domain || (scale.__domain = scale.domain()),
186        range = scale.range().map(function(v) { return (v - o) / k; });
187    scale.domain(domain).domain(range.map(scale.invert));
188  }
189
190  try {
191    d3_behavior_zoomDispatch.apply(d3_behavior_zoomTarget, d3_behavior_zoomArguments);
192  } finally {
193    d3.event = o;
194  }
195
196  o.preventDefault();
197}
198})();
Note: See TracBrowser for help on using the repository browser.