Subversion Repositories Integrator Subversion

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 espaco 1
/* Flot plugin for adding the ability to pan and zoom the plot.
2
 
3
Copyright (c) 2007-2014 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(a){function e(h){var k,j=this,l=h.data||{};if(l.elem)j=h.dragTarget=l.elem,h.dragProxy=d.proxy||j,h.cursorOffsetX=l.pageX-l.left,h.cursorOffsetY=l.pageY-l.top,h.offsetX=h.pageX-h.cursorOffsetX,h.offsetY=h.pageY-h.cursorOffsetY;else if(d.dragging||l.which>0&&h.which!=l.which||a(h.target).is(l.not))return;switch(h.type){case"mousedown":return a.extend(l,a(j).offset(),{elem:j,target:h.target,pageX:h.pageX,pageY:h.pageY}),b.add(document,"mousemove mouseup",e,l),i(j,!1),d.dragging=null,!1;case!d.dragging&&"mousemove":if(g(h.pageX-l.pageX)+g(h.pageY-l.pageY)<l.distance)break;h.target=l.target,k=f(h,"dragstart",j),k!==!1&&(d.dragging=j,d.proxy=h.dragProxy=a(k||j)[0]);case"mousemove":if(d.dragging){if(k=f(h,"drag",j),c.drop&&(c.drop.allowed=k!==!1,c.drop.handler(h)),k!==!1)break;h.type="mouseup"}case"mouseup":b.remove(document,"mousemove mouseup",e),d.dragging&&(c.drop&&c.drop.handler(h),f(h,"dragend",j)),i(j,!0),d.dragging=d.proxy=l.elem=!1}return!0}function f(b,c,d){b.type=c;var e=a.event.dispatch.call(d,b);return e===!1?!1:e||b.result}function g(a){return Math.pow(a,2)}function h(){return d.dragging===!1}function i(a,b){a&&(a.unselectable=b?"off":"on",a.onselectstart=function(){return b},a.style&&(a.style.MozUserSelect=b?"":"none"))}a.fn.drag=function(a,b,c){return b&&this.bind("dragstart",a),c&&this.bind("dragend",c),a?this.bind("drag",b?b:a):this.trigger("drag")};var b=a.event,c=b.special,d=c.drag={not:":input",distance:0,which:1,dragging:!1,setup:function(c){c=a.extend({distance:d.distance,which:d.which,not:d.not},c||{}),c.distance=g(c.distance),b.add(this,"mousedown",e,c),this.attachEvent&&this.attachEvent("ondragstart",h)},teardown:function(){b.remove(this,"mousedown",e),this===d.dragging&&(d.dragging=d.proxy=!1),i(this,!0),this.detachEvent&&this.detachEvent("ondragstart",h)}};c.dragstart=c.dragend={setup:function(){},teardown:function(){}}})(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
            e.preventDefault();
139
            onZoomClick(e, delta < 0);
140
            return false;
141
        }
142
 
143
        var prevCursor = 'default', prevPageX = 0, prevPageY = 0,
144
            panTimeout = null;
145
 
146
        function onDragStart(e) {
147
            if (e.which != 1)  // only accept left-click
148
                return false;
149
            var c = plot.getPlaceholder().css('cursor');
150
            if (c)
151
                prevCursor = c;
152
            plot.getPlaceholder().css('cursor', plot.getOptions().pan.cursor);
153
            prevPageX = e.pageX;
154
            prevPageY = e.pageY;
155
        }
156
 
157
        function onDrag(e) {
158
            var frameRate = plot.getOptions().pan.frameRate;
159
            if (panTimeout || !frameRate)
160
                return;
161
 
162
            panTimeout = setTimeout(function () {
163
                plot.pan({ left: prevPageX - e.pageX,
164
                           top: prevPageY - e.pageY });
165
                prevPageX = e.pageX;
166
                prevPageY = e.pageY;
167
 
168
                panTimeout = null;
169
            }, 1 / frameRate * 1000);
170
        }
171
 
172
        function onDragEnd(e) {
173
            if (panTimeout) {
174
                clearTimeout(panTimeout);
175
                panTimeout = null;
176
            }
177
 
178
            plot.getPlaceholder().css('cursor', prevCursor);
179
            plot.pan({ left: prevPageX - e.pageX,
180
                       top: prevPageY - e.pageY });
181
        }
182
 
183
        function bindEvents(plot, eventHolder) {
184
            var o = plot.getOptions();
185
            if (o.zoom.interactive) {
186
                eventHolder[o.zoom.trigger](onZoomClick);
187
                eventHolder.mousewheel(onMouseWheel);
188
            }
189
 
190
            if (o.pan.interactive) {
191
                eventHolder.bind("dragstart", { distance: 10 }, onDragStart);
192
                eventHolder.bind("drag", onDrag);
193
                eventHolder.bind("dragend", onDragEnd);
194
            }
195
        }
196
 
197
        plot.zoomOut = function (args) {
198
            if (!args)
199
                args = {};
200
 
201
            if (!args.amount)
202
                args.amount = plot.getOptions().zoom.amount;
203
 
204
            args.amount = 1 / args.amount;
205
            plot.zoom(args);
206
        };
207
 
208
        plot.zoom = function (args) {
209
            if (!args)
210
                args = {};
211
 
212
            var c = args.center,
213
                amount = args.amount || plot.getOptions().zoom.amount,
214
                w = plot.width(), h = plot.height();
215
 
216
            if (!c)
217
                c = { left: w / 2, top: h / 2 };
218
 
219
            var xf = c.left / w,
220
                yf = c.top / h,
221
                minmax = {
222
                    x: {
223
                        min: c.left - xf * w / amount,
224
                        max: c.left + (1 - xf) * w / amount
225
                    },
226
                    y: {
227
                        min: c.top - yf * h / amount,
228
                        max: c.top + (1 - yf) * h / amount
229
                    }
230
                };
231
 
232
            $.each(plot.getAxes(), function(_, axis) {
233
                var opts = axis.options,
234
                    min = minmax[axis.direction].min,
235
                    max = minmax[axis.direction].max,
236
                    zr = opts.zoomRange,
237
                    pr = opts.panRange;
238
 
239
                if (zr === false) // no zooming on this axis
240
                    return;
241
 
242
                min = axis.c2p(min);
243
                max = axis.c2p(max);
244
                if (min > max) {
245
                    // make sure min < max
246
                    var tmp = min;
247
                    min = max;
248
                    max = tmp;
249
                }
250
 
251
                //Check that we are in panRange
252
                if (pr) {
253
                    if (pr[0] != null && min < pr[0]) {
254
                        min = pr[0];
255
                    }
256
                    if (pr[1] != null && max > pr[1]) {
257
                        max = pr[1];
258
                    }
259
                }
260
 
261
                var range = max - min;
262
                if (zr &&
263
                    ((zr[0] != null && range < zr[0] && amount >1) ||
264
                     (zr[1] != null && range > zr[1] && amount <1)))
265
                    return;
266
 
267
                opts.min = min;
268
                opts.max = max;
269
            });
270
 
271
            plot.setupGrid();
272
            plot.draw();
273
 
274
            if (!args.preventEvent)
275
                plot.getPlaceholder().trigger("plotzoom", [ plot, args ]);
276
        };
277
 
278
        plot.pan = function (args) {
279
            var delta = {
280
                x: +args.left,
281
                y: +args.top
282
            };
283
 
284
            if (isNaN(delta.x))
285
                delta.x = 0;
286
            if (isNaN(delta.y))
287
                delta.y = 0;
288
 
289
            $.each(plot.getAxes(), function (_, axis) {
290
                var opts = axis.options,
291
                    min, max, d = delta[axis.direction];
292
 
293
                min = axis.c2p(axis.p2c(axis.min) + d),
294
                max = axis.c2p(axis.p2c(axis.max) + d);
295
 
296
                var pr = opts.panRange;
297
                if (pr === false) // no panning on this axis
298
                    return;
299
 
300
                if (pr) {
301
                    // check whether we hit the wall
302
                    if (pr[0] != null && pr[0] > min) {
303
                        d = pr[0] - min;
304
                        min += d;
305
                        max += d;
306
                    }
307
 
308
                    if (pr[1] != null && pr[1] < max) {
309
                        d = pr[1] - max;
310
                        min += d;
311
                        max += d;
312
                    }
313
                }
314
 
315
                opts.min = min;
316
                opts.max = max;
317
            });
318
 
319
            plot.setupGrid();
320
            plot.draw();
321
 
322
            if (!args.preventEvent)
323
                plot.getPlaceholder().trigger("plotpan", [ plot, args ]);
324
        };
325
 
326
        function shutdown(plot, eventHolder) {
327
            eventHolder.unbind(plot.getOptions().zoom.trigger, onZoomClick);
328
            eventHolder.unbind("mousewheel", onMouseWheel);
329
            eventHolder.unbind("dragstart", onDragStart);
330
            eventHolder.unbind("drag", onDrag);
331
            eventHolder.unbind("dragend", onDragEnd);
332
            if (panTimeout)
333
                clearTimeout(panTimeout);
334
        }
335
 
336
        plot.hooks.bindEvents.push(bindEvents);
337
        plot.hooks.shutdown.push(shutdown);
338
    }
339
 
340
    $.plot.plugins.push({
341
        init: init,
342
        options: options,
343
        name: 'navigate',
344
        version: '1.3'
345
    });
346
})(jQuery);