Commit 60689d24 authored by olau@iola.dk's avatar olau@iola.dk

Support for partial bars, this is useful for stacked bars


git-svn-id: https://flot.googlecode.com/svn/trunk@142 1e0a6537-2640-0410-bfb7-f154510ff394
parent b993ceef
...@@ -50,6 +50,9 @@ drawing. As a special case, a null value for lines is interpreted as a ...@@ -50,6 +50,9 @@ drawing. As a special case, a null value for lines is interpreted as a
line segment end, i.e. the point before and after the null value are line segment end, i.e. the point before and after the null value are
not connected. not connected.
Lines and points take two coordinates. For bars, you can specify a
third coordinate which is the bottom of the bar (defaults to 0).
The format of a single series object is as follows: The format of a single series object is as follows:
{ {
...@@ -182,7 +185,7 @@ Customizing the axes ...@@ -182,7 +185,7 @@ Customizing the axes
tickDecimals: null or number tickDecimals: null or number
} }
The axes have the same kind of options. The "mode" option All axes have the same kind of options. The "mode" option
determines how the data is interpreted, the default of null means as determines how the data is interpreted, the default of null means as
decimal numbers. Use "time" for time series data, see the next section. decimal numbers. Use "time" for time series data, see the next section.
...@@ -212,8 +215,8 @@ round tick interval size. Then it generates the ticks. ...@@ -212,8 +215,8 @@ round tick interval size. Then it generates the ticks.
You can specify how many ticks the algorithm aims for by setting You can specify how many ticks the algorithm aims for by setting
"ticks" to a number. The algorithm always tries to generate reasonably "ticks" to a number. The algorithm always tries to generate reasonably
round tick values so even if you ask for three ticks, you might get round tick values so even if you ask for three ticks, you might get
five if that fits better with the rounding. If you don't want ticks, five if that fits better with the rounding. If you don't want any
set "ticks" to 0 or an empty array. ticks at all, set "ticks" to 0 or an empty array.
Another option is to skip the rounding part and directly set the tick Another option is to skip the rounding part and directly set the tick
interval size with "tickSize". If you set it to 2, you'll get ticks at interval size with "tickSize". If you set it to 2, you'll get ticks at
...@@ -335,8 +338,8 @@ programming environments have some means of getting the timezone ...@@ -335,8 +338,8 @@ programming environments have some means of getting the timezone
offset for a specific date (note that you need to get the offset for offset for a specific date (note that you need to get the offset for
each individual timestamp to account for daylight savings). each individual timestamp to account for daylight savings).
Once you've got the timestamps into the data and specified "time" as Once you've gotten the timestamps into the data and specified "time"
the axis mode, Flot will automatically generate relevant ticks and as the axis mode, Flot will automatically generate relevant ticks and
format them. As always, you can tweak the ticks via the "ticks" option format them. As always, you can tweak the ticks via the "ticks" option
- just remember that the values should be timestamps (numbers), not - just remember that the values should be timestamps (numbers), not
Date objects. Date objects.
...@@ -344,11 +347,9 @@ Date objects. ...@@ -344,11 +347,9 @@ Date objects.
Tick generation and formatting can also be controlled separately Tick generation and formatting can also be controlled separately
through the following axis options: through the following axis options:
xaxis, yaxis: { minTickSize: array
minTickSize: array timeformat: null or format string
timeformat: null or format string monthNames: null or array of size 12 of strings
monthNames: null or array of size 12 of strings
}
Here "timeformat" is a format string to use. You might use it like Here "timeformat" is a format string to use. You might use it like
this: this:
......
...@@ -58,6 +58,10 @@ Changes: ...@@ -58,6 +58,10 @@ Changes:
- Horizontal bars (based on patch by Jason LeBrun). - Horizontal bars (based on patch by Jason LeBrun).
- Support for partial bars by specifying a third coordinate, i.e. they
don't have to start from the axis. This can be used to make stacked
bars.
Bug fixes: Bug fixes:
- Fixed two corner-case bugs when drawing filled curves (report and - Fixed two corner-case bugs when drawing filled curves (report and
......
...@@ -276,7 +276,7 @@ ...@@ -276,7 +276,7 @@
function processData() { function processData() {
var topSentry = Number.POSITIVE_INFINITY, var topSentry = Number.POSITIVE_INFINITY,
bottomSentry = Number.NEGATIVE_INFINITY, bottomSentry = Number.NEGATIVE_INFINITY,
axis, i, j, k; axis, i, j, k, m, s;
for (axis in axes) { for (axis in axes) {
axes[axis].datamin = topSentry; axes[axis].datamin = topSentry;
...@@ -287,35 +287,39 @@ ...@@ -287,35 +287,39 @@
} }
for (i = 0; i < series.length; ++i) { for (i = 0; i < series.length; ++i) {
var s = series[i]; s = series[i];
s.datapoints = { points: [], incr: 2 }; s.datapoints = { points: [], incr: 2 };
var data = s.data, var data = s.data,
points = s.datapoints.points, points = s.datapoints.points,
incr = s.datapoints.incr,
axisx = s.xaxis, axisy = s.yaxis, axisx = s.xaxis, axisy = s.yaxis,
xmin = topSentry, xmax = bottomSentry, xmin = topSentry, xmax = bottomSentry,
ymin = topSentry, ymax = bottomSentry, ymin = topSentry, ymax = bottomSentry,
x, y, p; x, y, p, incr, format = [];
/*
// determine the increment // determine the increment
if (s.bars.show) {
s.datapoints.incr = 3;
format.push({ default: 0 });
}
/*
// examine data to find out how to copy // examine data to find out how to copy
for (j = 0; j < data.length; ++j) { for (j = 0; j < data.length; ++j) {
}*/ }*/
axisx.used = axisy.used = true; axisx.used = axisy.used = true;
incr = s.datapoints.incr;
for (j = k = 0; j < data.length; ++j, k += incr) { for (j = k = 0; j < data.length; ++j, k += incr) {
p = data[j];
x = null; x = null;
y = null; y = null;
if (data[j] != null) { if (data[j] != null) {
x = data[j][0]; x = p[0];
y = data[j][1]; y = p[1];
} }
// convert to number // convert to number
...@@ -340,6 +344,9 @@ ...@@ -340,6 +344,9 @@
if (x == null || y == null) if (x == null || y == null)
x = y = null; // make sure everything is cleared x = y = null; // make sure everything is cleared
for (m = 2; m < incr; ++m)
points[k + m] = p[m] == null ? format[m-2].default : p[m];
points[k + 1] = y; points[k + 1] = y;
points[k] = x; points[k] = x;
} }
...@@ -1465,22 +1472,24 @@ ...@@ -1465,22 +1472,24 @@
ctx.restore(); ctx.restore();
} }
function drawBar(x, y, barLeft, barRight, offset, fillStyleCallback, axisx, axisy, c, horizontal) { function drawBar(x, y, b, barLeft, barRight, offset, fillStyleCallback, axisx, axisy, c, horizontal) {
var left, right, bottom, top, var left, right, bottom, top,
drawLeft, drawRight, drawTop, drawBottom; drawLeft, drawRight, drawTop, drawBottom,
tmp;
if (horizontal) { if (horizontal) {
drawBottom = drawRight = drawTop = true; drawBottom = drawRight = drawTop = true;
drawLeft = false; drawLeft = false;
left = 0; left = b;
right = x; right = x;
top = y + barLeft; top = y + barLeft;
bottom = y + barRight; bottom = y + barRight;
// account for negative bars // account for negative bars
if (right < left) { if (right < left) {
right = 0; tmp = right;
left = x; right = left;
left = tmp;
drawLeft = true; drawLeft = true;
drawRight = false; drawRight = false;
} }
...@@ -1490,13 +1499,14 @@ ...@@ -1490,13 +1499,14 @@
drawBottom = false; drawBottom = false;
left = x + barLeft; left = x + barLeft;
right = x + barRight; right = x + barRight;
bottom = 0; bottom = b;
top = y; top = y;
// account for negative bars // account for negative bars
if (top < bottom) { if (top < bottom) {
top = 0; tmp = top;
bottom = y; top = bottom;
bottom = tmp;
drawBottom = true; drawBottom = true;
drawTop = false; drawTop = false;
} }
...@@ -1576,13 +1586,12 @@ ...@@ -1576,13 +1586,12 @@
for (var i = 0; i < points.length; i += incr) { for (var i = 0; i < points.length; i += incr) {
if (points[i] == null) if (points[i] == null)
continue; continue;
drawBar(points[i], points[i + 1], barLeft, barRight, offset, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal); drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, offset, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal);
} }
} }
ctx.save(); ctx.save();
ctx.translate(plotOffset.left, plotOffset.top); ctx.translate(plotOffset.left, plotOffset.top);
ctx.lineJoin = "round";
// FIXME: figure out a way to add shadows (for instance along the right edge) // FIXME: figure out a way to add shadows (for instance along the right edge)
ctx.lineWidth = series.bars.lineWidth; ctx.lineWidth = series.bars.lineWidth;
...@@ -1740,16 +1749,16 @@ ...@@ -1740,16 +1749,16 @@
barRight = barLeft + s.bars.barWidth; barRight = barLeft + s.bars.barWidth;
for (j = 0; j < points.length; j += incr) { for (j = 0; j < points.length; j += incr) {
var x = points[j], y = points[j + 1]; var x = points[j], y = points[j + 1], b = points[j + 2];
if (x == null) if (x == null)
continue; continue;
// for a bar graph, the cursor must be inside the bar // for a bar graph, the cursor must be inside the bar
if (series[i].bars.horizontal ? if (series[i].bars.horizontal ?
(mx <= Math.max(0, x) && mx >= Math.min(0, x) && (mx <= Math.max(b, x) && mx >= Math.min(b, x) &&
my >= y + barLeft && my <= y + barRight) : my >= y + barLeft && my <= y + barRight) :
(mx >= x + barLeft && mx <= x + barRight && (mx >= x + barLeft && mx <= x + barRight &&
my >= Math.min(0, y) && my <= Math.max(0, y))) my >= Math.min(b, y) && my <= Math.max(b, y)))
item = [i, j / incr]; item = [i, j / incr];
} }
} }
...@@ -1908,7 +1917,7 @@ ...@@ -1908,7 +1917,7 @@
octx.clearRect(0, 0, canvasWidth, canvasHeight); octx.clearRect(0, 0, canvasWidth, canvasHeight);
octx.translate(plotOffset.left, plotOffset.top); octx.translate(plotOffset.left, plotOffset.top);
var i, hi; var i, hi;
for (i = 0; i < highlights.length; ++i) { for (i = 0; i < highlights.length; ++i) {
hi = highlights[i]; hi = highlights[i];
...@@ -1935,18 +1944,18 @@ ...@@ -1935,18 +1944,18 @@
} }
// redraw crosshair // redraw crosshair
if (options.crosshair.mode != null && crosshair.pos.x != -1) { var pos = crosshair.pos, mode = options.crosshair.mode;
if (mode != null && pos.x != -1) {
octx.strokeStyle = parseColor(options.crosshair.color).scale(null, null, null, 0.8).toString(); octx.strokeStyle = parseColor(options.crosshair.color).scale(null, null, null, 0.8).toString();
octx.lineWidth = 1; octx.lineWidth = 1;
ctx.lineJoin = "round"; ctx.lineJoin = "round";
var pos = crosshair.pos;
octx.beginPath(); octx.beginPath();
if (options.crosshair.mode.indexOf("x") != -1) { if (mode.indexOf("x") != -1) {
octx.moveTo(pos.x, 0); octx.moveTo(pos.x, 0);
octx.lineTo(pos.x, plotHeight); octx.lineTo(pos.x, plotHeight);
} }
if (options.crosshair.mode.indexOf("y") != -1) { if (mode.indexOf("y") != -1) {
octx.moveTo(0, pos.y); octx.moveTo(0, pos.y);
octx.lineTo(plotWidth, pos.y); octx.lineTo(plotWidth, pos.y);
} }
...@@ -2015,12 +2024,11 @@ ...@@ -2015,12 +2024,11 @@
} }
function drawBarHighlight(series, point) { function drawBarHighlight(series, point) {
octx.lineJoin = "round";
octx.lineWidth = series.bars.lineWidth; octx.lineWidth = series.bars.lineWidth;
octx.strokeStyle = parseColor(series.color).scale(1, 1, 1, 0.5).toString(); octx.strokeStyle = parseColor(series.color).scale(1, 1, 1, 0.5).toString();
var fillStyle = parseColor(series.color).scale(1, 1, 1, 0.5).toString(); var fillStyle = parseColor(series.color).scale(1, 1, 1, 0.5).toString();
var barLeft = series.bars.align == "left" ? 0 : -series.bars.barWidth/2; var barLeft = series.bars.align == "left" ? 0 : -series.bars.barWidth/2;
drawBar(point[0], point[1], barLeft, barLeft + series.bars.barWidth, drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth,
0, function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal); 0, function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal);
} }
......
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