From cb2e3d2743c0f88b430f14b7a396aa1a583dc978 Mon Sep 17 00:00:00 2001 From: Igor Sfiligoi Date: Tue, 22 Mar 2011 07:30:12 -0400 Subject: flot-0.7 --- jquery.flot.navigate.js | 292 +++++++++++++++++++++++++++++------------------- 1 file changed, 178 insertions(+), 114 deletions(-) (limited to 'jquery.flot.navigate.js') diff --git a/jquery.flot.navigate.js b/jquery.flot.navigate.js index e6f8834..f2b9760 100644 --- a/jquery.flot.navigate.js +++ b/jquery.flot.navigate.js @@ -7,20 +7,6 @@ plot.zoomOut() and plot.pan(offset) so you easily can add custom controls. It also fires a "plotpan" and "plotzoom" event when something happens, useful for synchronizing plots. -Example usage: - - plot = $.plot(...); - - // zoom default amount in on the pixel (100, 200) - plot.zoom({ center: { left: 10, top: 20 } }); - - // zoom out again - plot.zoomOut({ center: { left: 10, top: 20 } }); - - // pan 100 pixels to the left and 20 down - plot.pan({ left: -100, top: 20 }) - - Options: zoom: { @@ -31,25 +17,66 @@ Options: pan: { interactive: false + cursor: "move" // CSS mouse cursor value used when dragging, e.g. "pointer" + frameRate: 20 } xaxis, yaxis, x2axis, y2axis: { - zoomRange: null // or [number, number] (min range, max range) - panRange: null // or [number, number] (min, max) + zoomRange: null // or [number, number] (min range, max range) or false + panRange: null // or [number, number] (min, max) or false } -"interactive" enables the built-in drag/click behaviour. "amount" is -the amount to zoom the viewport relative to the current range, so 1 is -100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is 70% (zoom out). +"interactive" enables the built-in drag/click behaviour. If you enable +interactive for pan, then you'll have a basic plot that supports +moving around; the same for zoom. + +"amount" specifies the default amount to zoom in (so 1.5 = 150%) +relative to the current viewport. + +"cursor" is a standard CSS mouse cursor string used for visual +feedback to the user when dragging. + +"frameRate" specifies the maximum number of times per second the plot +will update itself while the user is panning around on it (set to null +to disable intermediate pans, the plot will then not update until the +mouse button is released). "zoomRange" is the interval in which zooming can happen, e.g. with zoomRange: [1, 100] the zoom will never scale the axis so that the difference between min and max is smaller than 1 or larger than 100. -You can set either of them to null to ignore. +You can set either end to null to ignore, e.g. [1, null]. If you set +zoomRange to false, zooming on that axis will be disabled. "panRange" confines the panning to stay within a range, e.g. with panRange: [-10, 20] panning stops at -10 in one end and at 20 in the -other. Either can be null. +other. Either can be null, e.g. [-10, null]. If you set +panRange to false, panning on that axis will be disabled. + +Example API usage: + + plot = $.plot(...); + + // zoom default amount in on the pixel (10, 20) + plot.zoom({ center: { left: 10, top: 20 } }); + + // zoom out again + plot.zoomOut({ center: { left: 10, top: 20 } }); + + // zoom 200% in on the pixel (10, 20) + plot.zoom({ amount: 2, center: { left: 10, top: 20 } }); + + // pan 100 pixels to the left and 20 down + plot.pan({ left: -100, top: 20 }) + +Here, "center" specifies where the center of the zooming should +happen. Note that this is defined in pixel space, not the space of the +data points (you can use the p2c helpers on the axes in Flot to help +you convert between these). + +"amount" is the amount to zoom the viewport relative to the current +range, so 1 is 100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is +70% (zoom out). You can set the default in the options. + */ @@ -92,51 +119,79 @@ Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-L amount: 1.5 // how much to zoom relative to current position, 2 = 200% (zoom in), 0.5 = 50% (zoom out) }, pan: { - interactive: false + interactive: false, + cursor: "move", + frameRate: 20 } }; function init(plot) { + function onZoomClick(e, zoomOut) { + var c = plot.offset(); + c.left = e.pageX - c.left; + c.top = e.pageY - c.top; + if (zoomOut) + plot.zoomOut({ center: c }); + else + plot.zoom({ center: c }); + } + + function onMouseWheel(e, delta) { + onZoomClick(e, delta < 0); + return false; + } + + var prevCursor = 'default', prevPageX = 0, prevPageY = 0, + panTimeout = null; + + function onDragStart(e) { + if (e.which != 1) // only accept left-click + return false; + var c = plot.getPlaceholder().css('cursor'); + if (c) + prevCursor = c; + plot.getPlaceholder().css('cursor', plot.getOptions().pan.cursor); + prevPageX = e.pageX; + prevPageY = e.pageY; + } + + function onDrag(e) { + var frameRate = plot.getOptions().pan.frameRate; + if (panTimeout || !frameRate) + return; + + panTimeout = setTimeout(function () { + plot.pan({ left: prevPageX - e.pageX, + top: prevPageY - e.pageY }); + prevPageX = e.pageX; + prevPageY = e.pageY; + + panTimeout = null; + }, 1 / frameRate * 1000); + } + + function onDragEnd(e) { + if (panTimeout) { + clearTimeout(panTimeout); + panTimeout = null; + } + + plot.getPlaceholder().css('cursor', prevCursor); + plot.pan({ left: prevPageX - e.pageX, + top: prevPageY - e.pageY }); + } + function bindEvents(plot, eventHolder) { var o = plot.getOptions(); if (o.zoom.interactive) { - function clickHandler(e, zoomOut) { - var c = plot.offset(); - c.left = e.pageX - c.left; - c.top = e.pageY - c.top; - if (zoomOut) - plot.zoomOut({ center: c }); - else - plot.zoom({ center: c }); - } - - eventHolder[o.zoom.trigger](clickHandler); - - eventHolder.mousewheel(function (e, delta) { - clickHandler(e, delta < 0); - return false; - }); + eventHolder[o.zoom.trigger](onZoomClick); + eventHolder.mousewheel(onMouseWheel); } + if (o.pan.interactive) { - var prevCursor = 'default', pageX = 0, pageY = 0; - - eventHolder.bind("dragstart", { distance: 10 }, function (e) { - if (e.which != 1) // only accept left-click - return false; - eventHolderCursor = eventHolder.css('cursor'); - eventHolder.css('cursor', 'move'); - pageX = e.pageX; - pageY = e.pageY; - }); - eventHolder.bind("drag", function (e) { - // unused at the moment, but we need it here to - // trigger the dragstart/dragend events - }); - eventHolder.bind("dragend", function (e) { - eventHolder.css('cursor', prevCursor); - plot.pan({ left: pageX - e.pageX, - top: pageY - e.pageY }); - }); + eventHolder.bind("dragstart", { distance: 10 }, onDragStart); + eventHolder.bind("drag", onDrag); + eventHolder.bind("dragend", onDragEnd); } } @@ -155,51 +210,53 @@ Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-L if (!args) args = {}; - var axes = plot.getAxes(), - options = plot.getOptions(), - c = args.center, - amount = args.amount ? args.amount : options.zoom.amount, + var c = args.center, + amount = args.amount || plot.getOptions().zoom.amount, w = plot.width(), h = plot.height(); if (!c) c = { left: w / 2, top: h / 2 }; var xf = c.left / w, - x1 = c.left - xf * w / amount, - x2 = c.left + (1 - xf) * w / amount, yf = c.top / h, - y1 = c.top - yf * h / amount, - y2 = c.top + (1 - yf) * h / amount; + minmax = { + x: { + min: c.left - xf * w / amount, + max: c.left + (1 - xf) * w / amount + }, + y: { + min: c.top - yf * h / amount, + max: c.top + (1 - yf) * h / amount + } + }; - function scaleAxis(min, max, name) { - var axis = axes[name], - axisOptions = options[name]; - - if (!axis.used) + $.each(plot.getAxes(), function(_, axis) { + var opts = axis.options, + min = minmax[axis.direction].min, + max = minmax[axis.direction].max, + zr = opts.zoomRange; + + if (zr === false) // no zooming on this axis return; min = axis.c2p(min); max = axis.c2p(max); - if (max < min) { // make sure min < max - var tmp = min + if (min > max) { + // make sure min < max + var tmp = min; min = max; max = tmp; } - var range = max - min, zr = axisOptions.zoomRange; + var range = max - min; if (zr && ((zr[0] != null && range < zr[0]) || (zr[1] != null && range > zr[1]))) return; - axisOptions.min = min; - axisOptions.max = max; - } - - scaleAxis(x1, x2, 'xaxis'); - scaleAxis(x1, x2, 'x2axis'); - scaleAxis(y1, y2, 'yaxis'); - scaleAxis(y1, y2, 'y2axis'); + opts.min = min; + opts.max = max; + }); plot.setupGrid(); plot.draw(); @@ -209,49 +266,45 @@ Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-L } plot.pan = function (args) { - var l = +args.left, t = +args.top, - axes = plot.getAxes(), options = plot.getOptions(); - - if (isNaN(l)) - l = 0; - if (isNaN(t)) - t = 0; - - function panAxis(delta, name) { - var axis = axes[name], - axisOptions = options[name], - min, max; - - if (!axis.used) - return; + var delta = { + x: +args.left, + y: +args.top + }; + + if (isNaN(delta.x)) + delta.x = 0; + if (isNaN(delta.y)) + delta.y = 0; - min = axis.c2p(axis.p2c(axis.min) + delta), - max = axis.c2p(axis.p2c(axis.max) + delta); + $.each(plot.getAxes(), function (_, axis) { + var opts = axis.options, + min, max, d = delta[axis.direction]; - var pr = axisOptions.panRange; + min = axis.c2p(axis.p2c(axis.min) + d), + max = axis.c2p(axis.p2c(axis.max) + d); + + var pr = opts.panRange; + if (pr === false) // no panning on this axis + return; + if (pr) { // check whether we hit the wall if (pr[0] != null && pr[0] > min) { - delta = pr[0] - min; - min += delta; - max += delta; + d = pr[0] - min; + min += d; + max += d; } if (pr[1] != null && pr[1] < max) { - delta = pr[1] - max; - min += delta; - max += delta; + d = pr[1] - max; + min += d; + max += d; } } - axisOptions.min = min; - axisOptions.max = max; - } - - panAxis(l, 'xaxis'); - panAxis(l, 'x2axis'); - panAxis(t, 'yaxis'); - panAxis(t, 'y2axis'); + opts.min = min; + opts.max = max; + }); plot.setupGrid(); plot.draw(); @@ -259,14 +312,25 @@ Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-L if (!args.preventEvent) plot.getPlaceholder().trigger("plotpan", [ plot ]); } + + function shutdown(plot, eventHolder) { + eventHolder.unbind(plot.getOptions().zoom.trigger, onZoomClick); + eventHolder.unbind("mousewheel", onMouseWheel); + eventHolder.unbind("dragstart", onDragStart); + eventHolder.unbind("drag", onDrag); + eventHolder.unbind("dragend", onDragEnd); + if (panTimeout) + clearTimeout(panTimeout); + } plot.hooks.bindEvents.push(bindEvents); + plot.hooks.shutdown.push(shutdown); } $.plot.plugins.push({ init: init, options: options, name: 'navigate', - version: '1.1' + version: '1.3' }); })(jQuery); -- cgit v1.2.3-2-g168b