Commit bad53abc authored by olau@iola.dk's avatar olau@iola.dk

Revamped internals to add support for extra axes, not just dual (sponsored by Flight Data Services)


git-svn-id: https://flot.googlecode.com/svn/trunk@251 1e0a6537-2640-0410-bfb7-f154510ff394
parent 6f969865
This diff is collapsed.
Flot x.x
--------
API changes:
Multiple axes support. Code using dual axes should be changed from
using x2axis/y2axis in the options to using an array. For instance,
{
xaxis: { ... }, x2axis: { ... },
yaxis: { ... }, y2axis: { ... }
}
becomes
{
xaxes: [ { ... }, { ... } ],
yaxes: [ { ... }, { ... } ]
}
Note that if you're just using one axis, continue to use the
xaxis/yaxis directly (it now sets the default settings for the
arrays). Plugins touching the axes must be ported to take the extra
axes into account, a couple of helper functions have been added for
that purpose, check the source.
Changes:
- Support for specifying a bottom for each point for line charts when
......@@ -15,9 +39,11 @@ Changes:
- Stacking plugin can stack horizontal bar charts.
- Navigate plugin now redraws the plot while panning instead of only
after the fact (can be disabled by setting the pan.frameRate option
to null). Issue 235.
to null), raised by lastthemy (issue 235).
- Date formatter now accepts %0m and %0d to get a zero-padded month or
day (issue raised by Maximillian Dornseif).
- Revamped internals to support an unlimited number of axes, not just
dual (sponsored by Flight Data Services, www.flightdataservices.com).
- New hooks: drawSeries
Bug fixes:
......
......@@ -33,7 +33,7 @@
<ul>
<li><a href="time.html">Plotting time series</a> and <a href="visitors.html">visitors per day with zooming and weekends</a> (with selection plugin)</li>
<li><a href="dual-axis.html">Dual axis support</a></li>
<li><a href="multiple-axes.html">Multiple axes</a></li>
<li><a href="thresholding.html">Thresholding the data</a> (with threshold plugin)</li>
<li><a href="stacking.html">Stacked charts</a> (with stacking plugin)</li>
<li><a href="percentiles.html">Using filled areas to plot percentiles</a> (with fillbetween plugin)</li>
......
/*
Flot plugin for showing a crosshair, thin lines, when the mouse hovers
Flot plugin for showing crosshairs, thin lines, when the mouse hovers
over the plot.
crosshair: {
......@@ -19,10 +19,11 @@ The plugin also adds four public methods:
- setCrosshair(pos)
Set the position of the crosshair. Note that this is cleared if
the user moves the mouse. "pos" should be on the form { x: xpos,
y: ypos } (or x2 and y2 if you're using the secondary axes), which
is coincidentally the same format as what you get from a "plothover"
event. If "pos" is null, the crosshair is cleared.
the user moves the mouse. "pos" is in coordinates of the plot and
should be on the form { x: xpos, y: ypos } (you can use x2/x3/...
if you're using multiple axes), which is coincidentally the same
format as what you get from a "plothover" event. If "pos" is null,
the crosshair is cleared.
- clearCrosshair()
......@@ -69,10 +70,9 @@ The plugin also adds four public methods:
if (!pos)
crosshair.x = -1;
else {
var axes = plot.getAxes();
crosshair.x = Math.max(0, Math.min(pos.x != null ? axes.xaxis.p2c(pos.x) : axes.x2axis.p2c(pos.x2), plot.width()));
crosshair.y = Math.max(0, Math.min(pos.y != null ? axes.yaxis.p2c(pos.y) : axes.y2axis.p2c(pos.y2), plot.height()));
var o = plot.p2c(pos);
crosshair.x = Math.max(0, Math.min(o.left, plot.width()));
crosshair.y = Math.max(0, Math.min(o.top, plot.height()));
}
plot.triggerRedrawOverlay();
......
This diff is collapsed.
......@@ -64,7 +64,7 @@ Example API usage:
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 c2p helpers on the axes in Flot to help
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
......@@ -192,51 +192,49 @@ 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)
return;
$.each(plot.getUsedAxes(), function(i, axis) {
var opts = axis.options,
min = minmax[axis.direction].min,
max = minmax[axis.direction].max
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, zr = opts.zoomRange;
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();
......@@ -246,49 +244,42 @@ 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;
$.each(plot.getUsedAxes(), function (i, axis) {
var opts = axis.options,
min, max, d = delta[axis.direction];
min = axis.c2p(axis.p2c(axis.min) + delta),
max = axis.c2p(axis.p2c(axis.max) + delta);
min = axis.c2p(axis.p2c(axis.min) + d),
max = axis.c2p(axis.p2c(axis.max) + d);
var pr = axisOptions.panRange;
var pr = opts.panRange;
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();
......
......@@ -8,20 +8,20 @@ The plugin defines the following options:
color: color
}
You enable selection support by setting the mode to one of "x", "y" or
Selection support is enabled by setting the mode to one of "x", "y" or
"xy". In "x" mode, the user will only be able to specify the x range,
similarly for "y" mode. For "xy", the selection becomes a rectangle
where both ranges can be specified. "color" is color of the selection.
When selection support is enabled, a "plotselected" event will be emitted
on the DOM element you passed into the plot function. The event
handler gets one extra parameter with the ranges selected on the axes,
When selection support is enabled, a "plotselected" event will be
emitted on the DOM element you passed into the plot function. The
event handler gets a parameter with the ranges selected on the axes,
like this:
placeholder.bind("plotselected", function(event, ranges) {
alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
// similar for yaxis, secondary axes are in x2axis
// and y2axis if present
// similar for yaxis - with multiple axes, the extra ones are in
// x2axis, x3axis, ...
});
The "plotselected" event is only fired when the user has finished
......@@ -37,17 +37,19 @@ The plugin allso adds the following methods to the plot object:
- setSelection(ranges, preventEvent)
Set the selection rectangle. The passed in ranges is on the same
form as returned in the "plotselected" event. If the selection
mode is "x", you should put in either an xaxis (or x2axis) object,
if the mode is "y" you need to put in an yaxis (or y2axis) object
and both xaxis/x2axis and yaxis/y2axis if the selection mode is
"xy", like this:
form as returned in the "plotselected" event. If the selection mode
is "x", you should put in either an xaxis range, if the mode is "y"
you need to put in an yaxis range and both xaxis and yaxis if the
selection mode is "xy", like this:
setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
setSelection will trigger the "plotselected" event when called. If
you don't want that to happen, e.g. if you're inside a
"plotselected" handler, pass true as the second parameter.
"plotselected" handler, pass true as the second parameter. If you
are using multiple axes, you can specify the ranges on any of those,
e.g. as x2axis/x3axis/... instead of xaxis, the plugin picks the
first one it sees.
- clearSelection(preventEvent)
......@@ -135,21 +137,13 @@ The plugin allso adds the following methods to the plot object:
if (!selectionIsSane())
return null;
var x1 = Math.min(selection.first.x, selection.second.x),
x2 = Math.max(selection.first.x, selection.second.x),
y1 = Math.max(selection.first.y, selection.second.y),
y2 = Math.min(selection.first.y, selection.second.y);
var r = {};
var axes = plot.getAxes();
if (axes.xaxis.used)
r.xaxis = { from: axes.xaxis.c2p(x1), to: axes.xaxis.c2p(x2) };
if (axes.x2axis.used)
r.x2axis = { from: axes.x2axis.c2p(x1), to: axes.x2axis.c2p(x2) };
if (axes.yaxis.used)
r.yaxis = { from: axes.yaxis.c2p(y1), to: axes.yaxis.c2p(y2) };
if (axes.y2axis.used)
r.y2axis = { from: axes.y2axis.c2p(y1), to: axes.y2axis.c2p(y2) };
var r = {}, c1 = selection.first, c2 = selection.second;
$.each(plot.getAxes(), function (name, axis) {
if (axis.used) {
var p1 = axis.c2p(c1[axis.direction]), p2 = axis.c2p(c2[axis.direction]);
r[name] = { from: Math.min(p1, p2), to: Math.max(p1, p2) };
}
});
return r;
}
......@@ -159,13 +153,12 @@ The plugin allso adds the following methods to the plot object:
plot.getPlaceholder().trigger("plotselected", [ r ]);
// backwards-compat stuff, to be removed in future
var axes = plot.getAxes();
if (axes.xaxis.used && axes.yaxis.used)
if (r.xaxis && r.yaxis)
plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]);
}
function clamp(min, value, max) {
return value < min? min: (value > max? max: value);
return value < min ? min: (value > max ? max: value);
}
function setSelectionPos(pos, e) {
......@@ -176,10 +169,10 @@ The plugin allso adds the following methods to the plot object:
pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height());
if (o.selection.mode == "y")
pos.x = pos == selection.first? 0: plot.width();
pos.x = pos == selection.first ? 0 : plot.width();
if (o.selection.mode == "x")
pos.y = pos == selection.first? 0: plot.height();
pos.y = pos == selection.first ? 0 : plot.height();
}
function updateSelection(pos) {
......@@ -204,19 +197,55 @@ The plugin allso adds the following methods to the plot object:
}
}
// taken from markings support
function extractRange(ranges, coord) {
var axis, from, to, axes, key;
axes = plot.getUsedAxes();
for (i = 0; i < axes.length; ++i) {
axis = axes[i];
if (axis.direction == coord) {
key = coord + axis.n + "axis";
if (!ranges[key] && axis.n == 1)
key = coord + "axis"; // support x1axis as xaxis
if (ranges[key]) {
from = ranges[key].from;
to = ranges[key].to;
break;
}
}
}
// backwards-compat stuff - to be removed in future
if (!ranges[key]) {
axis = coord == "x" ? plot.getXAxes()[0] : plot.getYAxes()[0];
from = ranges[coord + "1"];
to = ranges[coord + "2"];
}
// auto-reverse as an added bonus
if (from != null && to != null && from > to) {
var tmp = from;
from = to;
to = tmp;
}
return { from: from, to: to, axis: axis };
}
function setSelection(ranges, preventEvent) {
var axis, range, axes = plot.getAxes();
var o = plot.getOptions();
var axis, range, o = plot.getOptions();
if (o.selection.mode == "y") {
selection.first.x = 0;
selection.second.x = plot.width();
}
else {
axis = ranges["xaxis"]? axes["xaxis"]: (ranges["x2axis"]? axes["x2axis"]: axes["xaxis"]);
range = ranges["xaxis"] || ranges["x2axis"] || { from:ranges["x1"], to:ranges["x2"] }
selection.first.x = axis.p2c(Math.min(range.from, range.to));
selection.second.x = axis.p2c(Math.max(range.from, range.to));
range = extractRange(ranges, "x");
selection.first.x = range.axis.p2c(range.from);
selection.second.x = range.axis.p2c(range.to);
}
if (o.selection.mode == "x") {
......@@ -224,10 +253,10 @@ The plugin allso adds the following methods to the plot object:
selection.second.y = plot.height();
}
else {
axis = ranges["yaxis"]? axes["yaxis"]: (ranges["y2axis"]? axes["y2axis"]: axes["yaxis"]);
range = ranges["yaxis"] || ranges["y2axis"] || { from:ranges["y1"], to:ranges["y2"] }
selection.first.y = axis.p2c(Math.min(range.from, range.to));
selection.second.y = axis.p2c(Math.max(range.from, range.to));
range = extractRange(ranges, "y");
selection.first.y = range.axis.p2c(range.from);
selection.second.y = range.axis.p2c(range.to);
}
selection.show = true;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment