summaryrefslogtreecommitdiff
path: root/jquery.flot.navigate.js
diff options
context:
space:
mode:
Diffstat (limited to 'jquery.flot.navigate.js')
-rw-r--r--jquery.flot.navigate.js292
1 files changed, 178 insertions, 114 deletions
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);