'];
+ $.each(allAxes(), function (_, axis) {
+ var box = axis.box,
+ legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis",
+ layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles,
+ font = axis.options.font || "flot-tick-label tickLabel",
+ tick, x, y, halign, valign;
+
+ // Remove text before checking for axis.show and ticks.length;
+ // otherwise plugins, like flot-tickrotor, that draw their own
+ // tick labels will end up with both theirs and the defaults.
+
+ surface.removeText(layer);
+
+ if (!axis.show || axis.ticks.length == 0)
+ return;
- var axes = allAxes();
- for (var j = 0; j < axes.length; ++j) {
- var axis = axes[j], box = axis.box;
- if (!axis.show)
- continue;
- //debug: html.push('
')
- html.push('
');
for (var i = 0; i < axis.ticks.length; ++i) {
- var tick = axis.ticks[i];
+
+ tick = axis.ticks[i];
if (!tick.label || tick.v < axis.min || tick.v > axis.max)
continue;
- var pos = {}, align;
-
if (axis.direction == "x") {
- align = "center";
- pos.left = Math.round(plotOffset.left + axis.p2c(tick.v) - axis.labelWidth/2);
- if (axis.position == "bottom")
- pos.top = box.top + box.padding;
- else
- pos.bottom = canvasHeight - (box.top + box.height - box.padding);
- }
- else {
- pos.top = Math.round(plotOffset.top + axis.p2c(tick.v) - axis.labelHeight/2);
+ halign = "center";
+ x = plotOffset.left + axis.p2c(tick.v);
+ if (axis.position == "bottom") {
+ y = box.top + box.padding;
+ } else {
+ y = box.top + box.height - box.padding;
+ valign = "bottom";
+ }
+ } else {
+ valign = "middle";
+ y = plotOffset.top + axis.p2c(tick.v);
if (axis.position == "left") {
- pos.right = canvasWidth - (box.left + box.width - box.padding)
- align = "right";
- }
- else {
- pos.left = box.left + box.padding;
- align = "left";
+ x = box.left + box.width - box.padding;
+ halign = "right";
+ } else {
+ x = box.left + box.padding;
}
}
- pos.width = axis.labelWidth;
-
- var style = ["position:absolute", "text-align:" + align ];
- for (var a in pos)
- style.push(a + ":" + pos[a] + "px")
-
- html.push('
' + tick.label + '
');
+ surface.addText(layer, x, y, tick.label, font, null, null, halign, valign);
}
- html.push('
');
- }
-
- html.push('
');
-
- placeholder.append(html.join(""));
+ });
}
function drawSeries(series) {
@@ -2001,6 +2493,15 @@
sw = series.shadowSize,
radius = series.points.radius,
symbol = series.points.symbol;
+
+ // If the user sets the line width to 0, we change it to a very
+ // small value. A line width of 0 seems to force the default of 1.
+ // Doing the conditional here allows the shadow setting to still be
+ // optional even with a lineWidth of 0.
+
+ if( lw == 0 )
+ lw = 0.0001;
+
if (lw > 0 && sw > 0) {
// draw shadow in two steps
var w = sw / 2;
@@ -2022,7 +2523,7 @@
ctx.restore();
}
- function drawBar(x, y, b, barLeft, barRight, offset, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) {
+ function drawBar(x, y, b, barLeft, barRight, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) {
var left, right, bottom, top,
drawLeft, drawRight, drawTop, drawBottom,
tmp;
@@ -2097,13 +2598,8 @@
// fill the bar
if (fillStyleCallback) {
- c.beginPath();
- c.moveTo(left, bottom);
- c.lineTo(left, top);
- c.lineTo(right, top);
- c.lineTo(right, bottom);
c.fillStyle = fillStyleCallback(bottom, top);
- c.fill();
+ c.fillRect(left, top, right - left, bottom - top)
}
// draw outline
@@ -2111,35 +2607,35 @@
c.beginPath();
// FIXME: inline moveTo is buggy with excanvas
- c.moveTo(left, bottom + offset);
+ c.moveTo(left, bottom);
if (drawLeft)
- c.lineTo(left, top + offset);
+ c.lineTo(left, top);
else
- c.moveTo(left, top + offset);
+ c.moveTo(left, top);
if (drawTop)
- c.lineTo(right, top + offset);
+ c.lineTo(right, top);
else
- c.moveTo(right, top + offset);
+ c.moveTo(right, top);
if (drawRight)
- c.lineTo(right, bottom + offset);
+ c.lineTo(right, bottom);
else
- c.moveTo(right, bottom + offset);
+ c.moveTo(right, bottom);
if (drawBottom)
- c.lineTo(left, bottom + offset);
+ c.lineTo(left, bottom);
else
- c.moveTo(left, bottom + offset);
+ c.moveTo(left, bottom);
c.stroke();
}
}
function drawSeriesBars(series) {
- function plotBars(datapoints, barLeft, barRight, offset, fillStyleCallback, axisx, axisy) {
+ function plotBars(datapoints, barLeft, barRight, fillStyleCallback, axisx, axisy) {
var points = datapoints.points, ps = datapoints.pointsize;
for (var i = 0; i < points.length; i += ps) {
if (points[i] == null)
continue;
- drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, offset, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth);
+ drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth);
}
}
@@ -2149,9 +2645,22 @@
// FIXME: figure out a way to add shadows (for instance along the right edge)
ctx.lineWidth = series.bars.lineWidth;
ctx.strokeStyle = series.color;
- var barLeft = series.bars.align == "left" ? 0 : -series.bars.barWidth/2;
+
+ var barLeft;
+
+ switch (series.bars.align) {
+ case "left":
+ barLeft = 0;
+ break;
+ case "right":
+ barLeft = -series.bars.barWidth;
+ break;
+ default:
+ barLeft = -series.bars.barWidth / 2;
+ }
+
var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top); } : null;
- plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, 0, fillStyleCallback, series.xaxis, series.yaxis);
+ plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, fillStyleCallback, series.xaxis, series.yaxis);
ctx.restore();
}
@@ -2170,18 +2679,57 @@
}
function insertLegend() {
- placeholder.find(".legend").remove();
- if (!options.legend.show)
+ if (options.legend.container != null) {
+ $(options.legend.container).html("");
+ } else {
+ placeholder.find(".legend").remove();
+ }
+
+ if (!options.legend.show) {
return;
+ }
- var fragments = [], rowStarted = false,
+ var fragments = [], entries = [], rowStarted = false,
lf = options.legend.labelFormatter, s, label;
+
+ // Build a list of legend entries, with each having a label and a color
+
for (var i = 0; i < series.length; ++i) {
s = series[i];
- label = s.label;
- if (!label)
- continue;
+ if (s.label) {
+ label = lf ? lf(s.label, s) : s.label;
+ if (label) {
+ entries.push({
+ label: label,
+ color: s.color
+ });
+ }
+ }
+ }
+
+ // Sort the legend using either the default or a custom comparator
+
+ if (options.legend.sorted) {
+ if ($.isFunction(options.legend.sorted)) {
+ entries.sort(options.legend.sorted);
+ } else if (options.legend.sorted == "reverse") {
+ entries.reverse();
+ } else {
+ var ascending = options.legend.sorted != "descending";
+ entries.sort(function(a, b) {
+ return a.label == b.label ? 0 : (
+ (a.label < b.label) != ascending ? 1 : -1 // Logical XOR
+ );
+ });
+ }
+ }
+
+ // Generate markup for the list of entries, in their final order
+
+ for (var i = 0; i < entries.length; ++i) {
+
+ var entry = entries[i];
if (i % options.legend.noColumns == 0) {
if (rowStarted)
@@ -2190,13 +2738,12 @@
rowStarted = true;
}
- if (lf)
- label = lf(label, s);
-
fragments.push(
- '