- // setup graphics context
- var prevX = NaN;
- var prevY = NaN;
- var prevYs = [-1, -1];
- var yscale = axis.yscale;
- // should be same color as the lines but only 15% opaque.
- var rgb = new RGBColor(color);
- var err_color =
- 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + fillAlpha + ')';
- ctx.fillStyle = err_color;
- ctx.beginPath();
- while (iter.hasNext) {
- var point = iter.next();
- if (point.name == setName) { // TODO(klausw): this is always true
- if (!Dygraph.isOK(point.y)) {
- prevX = NaN;
- continue;
+ newYs = [ point.y_bottom, point.y_top ];
+ if (stepPlot) {
+ prevY = point.y;
+ }
+
+ // The documentation specifically disallows nulls inside the point arrays,
+ // but in case it happens we should do something sensible.
+ if (isNaN(newYs[0])) newYs[0] = point.y;
+ if (isNaN(newYs[1])) newYs[1] = point.y;
+
+ newYs[0] = e.plotArea.h * newYs[0] + e.plotArea.y;
+ newYs[1] = e.plotArea.h * newYs[1] + e.plotArea.y;
+ if (!isNaN(prevX)) {
+ if (stepPlot) {
+ ctx.moveTo(prevX, prevYs[0]);
+ ctx.lineTo(point.canvasx, prevYs[0]);
+ ctx.lineTo(point.canvasx, prevYs[1]);
+ } else {
+ ctx.moveTo(prevX, prevYs[0]);
+ ctx.lineTo(point.canvasx, newYs[0]);
+ ctx.lineTo(point.canvasx, newYs[1]);
+ }
+ ctx.lineTo(prevX, prevYs[1]);
+ ctx.closePath();
+ }
+ prevYs = newYs;
+ prevX = point.canvasx;
+ }
+ ctx.fill();
+};
+
+
+/**
+ * Proxy for CanvasRenderingContext2D which drops moveTo/lineTo calls which are
+ * superfluous. It accumulates all movements which haven't changed the x-value
+ * and only applies the two with the most extreme y-values.
+ *
+ * Calls to lineTo/moveTo must have non-decreasing x-values.
+ */
+DygraphCanvasRenderer._fastCanvasProxy = function(context) {
+ var pendingActions = []; // array of [type, x, y] tuples
+ var lastRoundedX = null;
+
+ var LINE_TO = 1,
+ MOVE_TO = 2;
+
+ var actionCount = 0; // number of moveTos and lineTos passed to context.
+
+ // Drop superfluous motions
+ // Assumes all pendingActions have the same (rounded) x-value.
+ var compressActions = function(opt_losslessOnly) {
+ if (pendingActions.length <= 1) return;
+
+ // Lossless compression: drop inconsequential moveTos.
+ for (var i = pendingActions.length - 1; i > 0; i--) {
+ var action = pendingActions[i];
+ if (action[0] == MOVE_TO) {
+ var prevAction = pendingActions[i - 1];
+ if (prevAction[1] == action[1] && prevAction[2] == action[2]) {
+ pendingActions.splice(i, 1);