Update data/params after Bugzilla 4.2.11 upgrade
[WebKit-https.git] / Websites / perf.webkit.org / public / js / jquery.flot.navigate.js
1 /* Flot plugin for adding the ability to pan and zoom the plot.
2
3 Copyright (c) 2007-2012 IOLA and Ole Laursen.
4 Licensed under the MIT license.
5
6 The default behaviour is double click and scrollwheel up/down to zoom in, drag
7 to pan. The plugin defines plot.zoom({ center }), plot.zoomOut() and
8 plot.pan( offset ) so you easily can add custom controls. It also fires
9 "plotpan" and "plotzoom" events, useful for synchronizing plots.
10
11 The plugin supports these options:
12
13     zoom: {
14         interactive: false
15         trigger: "dblclick" // or "click" for single click
16         amount: 1.5         // 2 = 200% (zoom in), 0.5 = 50% (zoom out)
17     }
18
19     pan: {
20         interactive: false
21         cursor: "move"      // CSS mouse cursor value used when dragging, e.g. "pointer"
22         frameRate: 20
23     }
24
25     xaxis, yaxis, x2axis, y2axis: {
26         zoomRange: null  // or [ number, number ] (min range, max range) or false
27         panRange: null   // or [ number, number ] (min, max) or false
28     }
29
30 "interactive" enables the built-in drag/click behaviour. If you enable
31 interactive for pan, then you'll have a basic plot that supports moving
32 around; the same for zoom.
33
34 "amount" specifies the default amount to zoom in (so 1.5 = 150%) relative to
35 the current viewport.
36
37 "cursor" is a standard CSS mouse cursor string used for visual feedback to the
38 user when dragging.
39
40 "frameRate" specifies the maximum number of times per second the plot will
41 update itself while the user is panning around on it (set to null to disable
42 intermediate pans, the plot will then not update until the mouse button is
43 released).
44
45 "zoomRange" is the interval in which zooming can happen, e.g. with zoomRange:
46 [1, 100] the zoom will never scale the axis so that the difference between min
47 and max is smaller than 1 or larger than 100. You can set either end to null
48 to ignore, e.g. [1, null]. If you set zoomRange to false, zooming on that axis
49 will be disabled.
50
51 "panRange" confines the panning to stay within a range, e.g. with panRange:
52 [-10, 20] panning stops at -10 in one end and at 20 in the other. Either can
53 be null, e.g. [-10, null]. If you set panRange to false, panning on that axis
54 will be disabled.
55
56 Example API usage:
57
58     plot = $.plot(...);
59
60     // zoom default amount in on the pixel ( 10, 20 )
61     plot.zoom({ center: { left: 10, top: 20 } });
62
63     // zoom out again
64     plot.zoomOut({ center: { left: 10, top: 20 } });
65
66     // zoom 200% in on the pixel (10, 20)
67     plot.zoom({ amount: 2, center: { left: 10, top: 20 } });
68
69     // pan 100 pixels to the left and 20 down
70     plot.pan({ left: -100, top: 20 })
71
72 Here, "center" specifies where the center of the zooming should happen. Note
73 that this is defined in pixel space, not the space of the data points (you can
74 use the p2c helpers on the axes in Flot to help you convert between these).
75
76 "amount" is the amount to zoom the viewport relative to the current range, so
77 1 is 100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is 70% (zoom out). You
78 can set the default in the options.
79
80 */
81
82 // First two dependencies, jquery.event.drag.js and
83 // jquery.mousewheel.js, we put them inline here to save people the
84 // effort of downloading them.
85
86 /*
87 jquery.event.drag.js ~ v1.5 ~ Copyright (c) 2008, Three Dub Media (http://threedubmedia.com)
88 Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-LICENSE.txt
89 */
90 (function(E){E.fn.drag=function(L,K,J){if(K){this.bind("dragstart",L)}if(J){this.bind("dragend",J)}return !L?this.trigger("drag"):this.bind("drag",K?K:L)};var A=E.event,B=A.special,F=B.drag={not:":input",distance:0,which:1,dragging:false,setup:function(J){J=E.extend({distance:F.distance,which:F.which,not:F.not},J||{});J.distance=I(J.distance);A.add(this,"mousedown",H,J);if(this.attachEvent){this.attachEvent("ondragstart",D)}},teardown:function(){A.remove(this,"mousedown",H);if(this===F.dragging){F.dragging=F.proxy=false}G(this,true);if(this.detachEvent){this.detachEvent("ondragstart",D)}}};B.dragstart=B.dragend={setup:function(){},teardown:function(){}};function H(L){var K=this,J,M=L.data||{};if(M.elem){K=L.dragTarget=M.elem;L.dragProxy=F.proxy||K;L.cursorOffsetX=M.pageX-M.left;L.cursorOffsetY=M.pageY-M.top;L.offsetX=L.pageX-L.cursorOffsetX;L.offsetY=L.pageY-L.cursorOffsetY}else{if(F.dragging||(M.which>0&&L.which!=M.which)||E(L.target).is(M.not)){return }}switch(L.type){case"mousedown":E.extend(M,E(K).offset(),{elem:K,target:L.target,pageX:L.pageX,pageY:L.pageY});A.add(document,"mousemove mouseup",H,M);G(K,false);F.dragging=null;return false;case !F.dragging&&"mousemove":if(I(L.pageX-M.pageX)+I(L.pageY-M.pageY)<M.distance){break}L.target=M.target;J=C(L,"dragstart",K);if(J!==false){F.dragging=K;F.proxy=L.dragProxy=E(J||K)[0]}case"mousemove":if(F.dragging){J=C(L,"drag",K);if(B.drop){B.drop.allowed=(J!==false);B.drop.handler(L)}if(J!==false){break}L.type="mouseup"}case"mouseup":A.remove(document,"mousemove mouseup",H);if(F.dragging){if(B.drop){B.drop.handler(L)}C(L,"dragend",K)}G(K,true);F.dragging=F.proxy=M.elem=false;break}return true}function C(M,K,L){M.type=K;var J=E.event.handle.call(L,M);return J===false?false:J||M.result}function I(J){return Math.pow(J,2)}function D(){return(F.dragging===false)}function G(K,J){if(!K){return }K.unselectable=J?"off":"on";K.onselectstart=function(){return J};if(K.style){K.style.MozUserSelect=J?"":"none"}}})(jQuery);
91
92 /* jquery.mousewheel.min.js
93  * Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
94  * Licensed under the MIT License (LICENSE.txt).
95  * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
96  * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
97  * Thanks to: Seamus Leahy for adding deltaX and deltaY
98  *
99  * Version: 3.0.6
100  *
101  * Requires: 1.2.2+
102  */
103 (function(d){function e(a){var b=a||window.event,c=[].slice.call(arguments,1),f=0,e=0,g=0,a=d.event.fix(b);a.type="mousewheel";b.wheelDelta&&(f=b.wheelDelta/120);b.detail&&(f=-b.detail/3);g=f;void 0!==b.axis&&b.axis===b.HORIZONTAL_AXIS&&(g=0,e=-1*f);void 0!==b.wheelDeltaY&&(g=b.wheelDeltaY/120);void 0!==b.wheelDeltaX&&(e=-1*b.wheelDeltaX/120);c.unshift(a,f,e,g);return(d.event.dispatch||d.event.handle).apply(this,c)}var c=["DOMMouseScroll","mousewheel"];if(d.event.fixHooks)for(var h=c.length;h;)d.event.fixHooks[c[--h]]=d.event.mouseHooks;d.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=c.length;a;)this.addEventListener(c[--a],e,!1);else this.onmousewheel=e},teardown:function(){if(this.removeEventListener)for(var a=c.length;a;)this.removeEventListener(c[--a],e,!1);else this.onmousewheel=null}};d.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery);
104
105
106
107
108 (function ($) {
109     var options = {
110         xaxis: {
111             zoomRange: null, // or [number, number] (min range, max range)
112             panRange: null // or [number, number] (min, max)
113         },
114         zoom: {
115             interactive: false,
116             trigger: "dblclick", // or "click" for single click
117             amount: 1.5 // how much to zoom relative to current position, 2 = 200% (zoom in), 0.5 = 50% (zoom out)
118         },
119         pan: {
120             interactive: false,
121             cursor: "move",
122             frameRate: 20
123         }
124     };
125
126     function init(plot) {
127         function onZoomClick(e, zoomOut) {
128             var c = plot.offset();
129             c.left = e.pageX - c.left;
130             c.top = e.pageY - c.top;
131             if (zoomOut)
132                 plot.zoomOut({ center: c });
133             else
134                 plot.zoom({ center: c });
135         }
136
137         function onMouseWheel(e, delta) {
138             onZoomClick(e, delta < 0);
139             return false;
140         }
141         
142         var prevCursor = 'default', prevPageX = 0, prevPageY = 0,
143             panTimeout = null;
144
145         function onDragStart(e) {
146             if (e.which != 1)  // only accept left-click
147                 return false;
148             var c = plot.getPlaceholder().css('cursor');
149             if (c)
150                 prevCursor = c;
151             plot.getPlaceholder().css('cursor', plot.getOptions().pan.cursor);
152             prevPageX = e.pageX;
153             prevPageY = e.pageY;
154         }
155         
156         function onDrag(e) {
157             var frameRate = plot.getOptions().pan.frameRate;
158             if (panTimeout || !frameRate)
159                 return;
160
161             panTimeout = setTimeout(function () {
162                 plot.pan({ left: prevPageX - e.pageX,
163                            top: prevPageY - e.pageY });
164                 prevPageX = e.pageX;
165                 prevPageY = e.pageY;
166                                                     
167                 panTimeout = null;
168             }, 1 / frameRate * 1000);
169         }
170
171         function onDragEnd(e) {
172             if (panTimeout) {
173                 clearTimeout(panTimeout);
174                 panTimeout = null;
175             }
176                     
177             plot.getPlaceholder().css('cursor', prevCursor);
178             plot.pan({ left: prevPageX - e.pageX,
179                        top: prevPageY - e.pageY });
180         }
181         
182         function bindEvents(plot, eventHolder) {
183             var o = plot.getOptions();
184             if (o.zoom.interactive) {
185                 eventHolder[o.zoom.trigger](onZoomClick);
186                 eventHolder.mousewheel(onMouseWheel);
187             }
188
189             if (o.pan.interactive) {
190                 eventHolder.bind("dragstart", { distance: 10 }, onDragStart);
191                 eventHolder.bind("drag", onDrag);
192                 eventHolder.bind("dragend", onDragEnd);
193             }
194         }
195
196         plot.zoomOut = function (args) {
197             if (!args)
198                 args = {};
199             
200             if (!args.amount)
201                 args.amount = plot.getOptions().zoom.amount;
202
203             args.amount = 1 / args.amount;
204             plot.zoom(args);
205         };
206         
207         plot.zoom = function (args) {
208             if (!args)
209                 args = {};
210             
211             var c = args.center,
212                 amount = args.amount || plot.getOptions().zoom.amount,
213                 w = plot.width(), h = plot.height();
214
215             if (!c)
216                 c = { left: w / 2, top: h / 2 };
217                 
218             var xf = c.left / w,
219                 yf = c.top / h,
220                 minmax = {
221                     x: {
222                         min: c.left - xf * w / amount,
223                         max: c.left + (1 - xf) * w / amount
224                     },
225                     y: {
226                         min: c.top - yf * h / amount,
227                         max: c.top + (1 - yf) * h / amount
228                     }
229                 };
230
231             $.each(plot.getAxes(), function(_, axis) {
232                 var opts = axis.options,
233                     min = minmax[axis.direction].min,
234                     max = minmax[axis.direction].max,
235                     zr = opts.zoomRange,
236                     pr = opts.panRange;
237
238                 if (zr === false) // no zooming on this axis
239                     return;
240                     
241                 min = axis.c2p(min);
242                 max = axis.c2p(max);
243                 if (min > max) {
244                     // make sure min < max
245                     var tmp = min;
246                     min = max;
247                     max = tmp;
248                 }
249
250                 //Check that we are in panRange
251                 if (pr) {
252                     if (pr[0] != null && min < pr[0]) {
253                         min = pr[0];
254                     }
255                     if (pr[1] != null && max > pr[1]) {
256                         max = pr[1];
257                     }
258                 }
259
260                 var range = max - min;
261                 if (zr &&
262                     ((zr[0] != null && range < zr[0]) ||
263                      (zr[1] != null && range > zr[1])))
264                     return;
265             
266                 opts.min = min;
267                 opts.max = max;
268             });
269             
270             plot.setupGrid();
271             plot.draw();
272             
273             if (!args.preventEvent)
274                 plot.getPlaceholder().trigger("plotzoom", [ plot, args ]);
275         };
276
277         plot.pan = function (args) {
278             var delta = {
279                 x: +args.left,
280                 y: +args.top
281             };
282
283             if (isNaN(delta.x))
284                 delta.x = 0;
285             if (isNaN(delta.y))
286                 delta.y = 0;
287
288             $.each(plot.getAxes(), function (_, axis) {
289                 var opts = axis.options,
290                     min, max, d = delta[axis.direction];
291
292                 min = axis.c2p(axis.p2c(axis.min) + d),
293                 max = axis.c2p(axis.p2c(axis.max) + d);
294
295                 var pr = opts.panRange;
296                 if (pr === false) // no panning on this axis
297                     return;
298                 
299                 if (pr) {
300                     // check whether we hit the wall
301                     if (pr[0] != null && pr[0] > min) {
302                         d = pr[0] - min;
303                         min += d;
304                         max += d;
305                     }
306                     
307                     if (pr[1] != null && pr[1] < max) {
308                         d = pr[1] - max;
309                         min += d;
310                         max += d;
311                     }
312                 }
313                 
314                 opts.min = min;
315                 opts.max = max;
316             });
317             
318             plot.setupGrid();
319             plot.draw();
320             
321             if (!args.preventEvent)
322                 plot.getPlaceholder().trigger("plotpan", [ plot, args ]);
323         };
324
325         function shutdown(plot, eventHolder) {
326             eventHolder.unbind(plot.getOptions().zoom.trigger, onZoomClick);
327             eventHolder.unbind("mousewheel", onMouseWheel);
328             eventHolder.unbind("dragstart", onDragStart);
329             eventHolder.unbind("drag", onDrag);
330             eventHolder.unbind("dragend", onDragEnd);
331             if (panTimeout)
332                 clearTimeout(panTimeout);
333         }
334         
335         plot.hooks.bindEvents.push(bindEvents);
336         plot.hooks.shutdown.push(shutdown);
337     }
338     
339     $.plot.plugins.push({
340         init: init,
341         options: options,
342         name: 'navigate',
343         version: '1.3'
344     });
345 })(jQuery);