13551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)/* Flot plugin for adding the ability to pan and zoom the plot. 23551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 33551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)Copyright (c) 2007-2013 IOLA and Ole Laursen. 43551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)Licensed under the MIT license. 53551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 63551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)The default behaviour is double click and scrollwheel up/down to zoom in, drag 73551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)to pan. The plugin defines plot.zoom({ center }), plot.zoomOut() and 83551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)plot.pan( offset ) so you easily can add custom controls. It also fires 93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)"plotpan" and "plotzoom" events, useful for synchronizing plots. 103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)The plugin supports these options: 123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) zoom: { 143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) interactive: false 153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) trigger: "dblclick" // or "click" for single click 163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) amount: 1.5 // 2 = 200% (zoom in), 0.5 = 50% (zoom out) 173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) pan: { 203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) interactive: false 213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) cursor: "move" // CSS mouse cursor value used when dragging, e.g. "pointer" 223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) frameRate: 20 233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) xaxis, yaxis, x2axis, y2axis: { 263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) zoomRange: null // or [ number, number ] (min range, max range) or false 273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) panRange: null // or [ number, number ] (min, max) or false 283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) } 293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)"interactive" enables the built-in drag/click behaviour. If you enable 313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)interactive for pan, then you'll have a basic plot that supports moving 323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)around; the same for zoom. 333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)"amount" specifies the default amount to zoom in (so 1.5 = 150%) relative to 353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)the current viewport. 363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)"cursor" is a standard CSS mouse cursor string used for visual feedback to the 383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)user when dragging. 393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)"frameRate" specifies the maximum number of times per second the plot will 413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)update itself while the user is panning around on it (set to null to disable 423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)intermediate pans, the plot will then not update until the mouse button is 433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)released). 443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)"zoomRange" is the interval in which zooming can happen, e.g. with zoomRange: 463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)[1, 100] the zoom will never scale the axis so that the difference between min 473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)and max is smaller than 1 or larger than 100. You can set either end to null 483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)to ignore, e.g. [1, null]. If you set zoomRange to false, zooming on that axis 493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)will be disabled. 503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)"panRange" confines the panning to stay within a range, e.g. with panRange: 523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)[-10, 20] panning stops at -10 in one end and at 20 in the other. Either can 533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)be null, e.g. [-10, null]. If you set panRange to false, panning on that axis 543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)will be disabled. 553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)Example API usage: 573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) plot = $.plot(...); 593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // zoom default amount in on the pixel ( 10, 20 ) 613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) plot.zoom({ center: { left: 10, top: 20 } }); 623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // zoom out again 643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) plot.zoomOut({ center: { left: 10, top: 20 } }); 653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // zoom 200% in on the pixel (10, 20) 673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) plot.zoom({ amount: 2, center: { left: 10, top: 20 } }); 683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // pan 100 pixels to the left and 20 down 703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) plot.pan({ left: -100, top: 20 }) 713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)Here, "center" specifies where the center of the zooming should happen. Note 733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)that this is defined in pixel space, not the space of the data points (you can 743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)use the p2c helpers on the axes in Flot to help you convert between these). 753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)"amount" is the amount to zoom the viewport relative to the current range, so 773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)1 is 100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is 70% (zoom out). You 783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)can set the default in the options. 793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)*/// First two dependencies, jquery.event.drag.js and 813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// jquery.mousewheel.js, we put them inline here to save people the 823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// effort of downloading them. 833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)/* 843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)jquery.event.drag.js ~ v1.5 ~ Copyright (c) 2008, Three Dub Media (http://threedubmedia.com) 853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-LICENSE.txt 863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)*/(function(e){function t(i){var l,h=this,p=i.data||{};if(p.elem)h=i.dragTarget=p.elem,i.dragProxy=a.proxy||h,i.cursorOffsetX=p.pageX-p.left,i.cursorOffsetY=p.pageY-p.top,i.offsetX=i.pageX-i.cursorOffsetX,i.offsetY=i.pageY-i.cursorOffsetY;else if(a.dragging||p.which>0&&i.which!=p.which||e(i.target).is(p.not))return;switch(i.type){case"mousedown":return e.extend(p,e(h).offset(),{elem:h,target:i.target,pageX:i.pageX,pageY:i.pageY}),o.add(document,"mousemove mouseup",t,p),s(h,!1),a.dragging=null,!1;case!a.dragging&&"mousemove":if(r(i.pageX-p.pageX)+r(i.pageY-p.pageY)<p.distance)break;i.target=p.target,l=n(i,"dragstart",h),l!==!1&&(a.dragging=h,a.proxy=i.dragProxy=e(l||h)[0]);case"mousemove":if(a.dragging){if(l=n(i,"drag",h),u.drop&&(u.drop.allowed=l!==!1,u.drop.handler(i)),l!==!1)break;i.type="mouseup"};case"mouseup":o.remove(document,"mousemove mouseup",t),a.dragging&&(u.drop&&u.drop.handler(i),n(i,"dragend",h)),s(h,!0),a.dragging=a.proxy=p.elem=!1}return!0}function n(t,n,r){t.type=n;var i=e.event.dispatch.call(r,t);return i===!1?!1:i||t.result}function r(e){return Math.pow(e,2)}function i(){return a.dragging===!1}function s(e,t){e&&(e.unselectable=t?"off":"on",e.onselectstart=function(){return t},e.style&&(e.style.MozUserSelect=t?"":"none"))}e.fn.drag=function(e,t,n){return t&&this.bind("dragstart",e),n&&this.bind("dragend",n),e?this.bind("drag",t?t:e):this.trigger("drag")};var o=e.event,u=o.special,a=u.drag={not:":input",distance:0,which:1,dragging:!1,setup:function(n){n=e.extend({distance:a.distance,which:a.which,not:a.not},n||{}),n.distance=r(n.distance),o.add(this,"mousedown",t,n),this.attachEvent&&this.attachEvent("ondragstart",i)},teardown:function(){o.remove(this,"mousedown",t),this===a.dragging&&(a.dragging=a.proxy=!1),s(this,!0),this.detachEvent&&this.detachEvent("ondragstart",i)}};u.dragstart=u.dragend={setup:function(){},teardown:function(){}}})(jQuery),function(e){function t(t){var n=t||window.event,r=[].slice.call(arguments,1),i=0,s=0,o=0,t=e.event.fix(n);return t.type="mousewheel",n.wheelDelta&&(i=n.wheelDelta/120),n.detail&&(i=-n.detail/3),o=i,void 0!==n.axis&&n.axis===n.HORIZONTAL_AXIS&&(o=0,s=-1*i),void 0!==n.wheelDeltaY&&(o=n.wheelDeltaY/120),void 0!==n.wheelDeltaX&&(s=-1*n.wheelDeltaX/120),r.unshift(t,i,s,o),(e.event.dispatch||e.event.handle).apply(this,r)}var n=["DOMMouseScroll","mousewheel"];if(e.event.fixHooks)for(var r=n.length;r;)e.event.fixHooks[n[--r]]=e.event.mouseHooks;e.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var e=n.length;e;)this.addEventListener(n[--e],t,!1);else this.onmousewheel=t},teardown:function(){if(this.removeEventListener)for(var e=n.length;e;)this.removeEventListener(n[--e],t,!1);else this.onmousewheel=null}},e.fn.extend({mousewheel:function(e){return e?this.bind("mousewheel",e):this.trigger("mousewheel")},unmousewheel:function(e){return this.unbind("mousewheel",e)}})}(jQuery),function(e){function n(t){function n(e,n){var r=t.offset();r.left=e.pageX-r.left,r.top=e.pageY-r.top,n?t.zoomOut({center:r}):t.zoom({center:r})}function r(e,t){return e.preventDefault(),n(e,t<0),!1}function a(e){if(e.which!=1)return!1;var n=t.getPlaceholder().css("cursor");n&&(i=n),t.getPlaceholder().css("cursor",t.getOptions().pan.cursor),s=e.pageX,o=e.pageY}function f(e){var n=t.getOptions().pan.frameRate;if(u||!n)return;u=setTimeout(function(){t.pan({left:s-e.pageX,top:o-e.pageY}),s=e.pageX,o=e.pageY,u=null},1/n*1e3)}function l(e){u&&(clearTimeout(u),u=null),t.getPlaceholder().css("cursor",i),t.pan({left:s-e.pageX,top:o-e.pageY})}function c(e,t){var i=e.getOptions();i.zoom.interactive&&(t[i.zoom.trigger](n),t.mousewheel(r)),i.pan.interactive&&(t.bind("dragstart",{distance:10},a),t.bind("drag",f),t.bind("dragend",l))}function h(e,t){t.unbind(e.getOptions().zoom.trigger,n),t.unbind("mousewheel",r),t.unbind("dragstart",a),t.unbind("drag",f),t.unbind("dragend",l),u&&clearTimeout(u)}var i="default",s=0,o=0,u=null;t.zoomOut=function(e){e||(e={}),e.amount||(e.amount=t.getOptions().zoom.amount),e.amount=1/e.amount,t.zoom(e)},t.zoom=function(n){n||(n={});var r=n.center,i=n.amount||t.getOptions().zoom.amount,s=t.width(),o=t.height();r||(r={left:s/2,top:o/2});var u=r.left/s,a=r.top/o,f={x:{min:r.left-u*s/i,max:r.left+(1-u)*s/i},y:{min:r.top-a*o/i,max:r.top+(1-a)*o/i}};e.each(t.getAxes(),function(e,t){var n=t.options,r=f[t.direction].min,i=f[t.direction].max,s=n.zoomRange,o=n.panRange;if(s===!1)return;r=t.c2p(r),i=t.c2p(i);if(r>i){var u=r;r=i,i=u}o&&(o[0]!=null&&r<o[0]&&(r=o[0]),o[1]!=null&&i>o[1]&&(i=o[1]));var a=i-r;if(s&&(s[0]!=null&&a<s[0]||s[1]!=null&&a>s[1]))return;n.min=r,n.max=i}),t.setupGrid(),t.draw(),n.preventEvent||t.getPlaceholder().trigger("plotzoom",[t,n])},t.pan=function(n){var r={x:+n.left,y:+n.top};isNaN(r.x)&&(r.x=0),isNaN(r.y)&&(r.y=0),e.each(t.getAxes(),function(e,t){var n=t.options,i,s,o=r[t.direction];i=t.c2p(t.p2c(t.min)+o),s=t.c2p(t.p2c(t.max)+o);var u=n.panRange;if(u===!1)return;u&&(u[0]!=null&&u[0]>i&&(o=u[0]-i,i+=o,s+=o),u[1]!=null&&u[1]<s&&(o=u[1]-s,i+=o,s+=o)),n.min=i,n.max=s}),t.setupGrid(),t.draw(),n.preventEvent||t.getPlaceholder().trigger("plotpan",[t,n])},t.hooks.bindEvents.push(c),t.hooks.shutdown.push(h)}var t={xaxis:{zoomRange:null,panRange:null},zoom:{interactive:!1,trigger:"dblclick",amount:1.5},pan:{interactive:!1,cursor:"move",frameRate:20}};e.plot.plugins.push({init:n,options:t,name:"navigate",version:"1.3"})}(jQuery);