ctx.closePath();
ctx.stroke();
}
+ ctx.restore();
}
if (this.attr_('drawXGrid')) {
ctx.closePath();
ctx.stroke();
}
+ ctx.restore();
}
// Do the ordinary rendering, as before
var points = this.layout.annotated_points;
for (var i = 0; i < points.length; i++) {
var p = points[i];
- if (p.canvasx < this.area.x || p.canvasx > this.area.x + this.area.w) {
+ if (p.canvasx < this.area.x || p.canvasx > this.area.x + this.area.w ||
+ p.canvasy < this.area.y || p.canvasy > this.area.y + this.area.h) {
continue;
}
div.style.borderColor = this.colors[p.name];
a.div = div;
- Dygraph.addEvent(div, 'click',
+ this.dygraph_.addEvent(div, 'click',
bindEvt('clickHandler', 'annotationClickHandler', p, this));
- Dygraph.addEvent(div, 'mouseover',
+ this.dygraph_.addEvent(div, 'mouseover',
bindEvt('mouseOverHandler', 'annotationMouseOverHandler', p, this));
- Dygraph.addEvent(div, 'mouseout',
+ this.dygraph_.addEvent(div, 'mouseout',
bindEvt('mouseOutHandler', 'annotationMouseOutHandler', p, this));
- Dygraph.addEvent(div, 'dblclick',
+ this.dygraph_.addEvent(div, 'dblclick',
bindEvt('dblClickHandler', 'annotationDblClickHandler', p, this));
this.container.appendChild(div);
}
};
+DygraphCanvasRenderer.makeNextPointStep_ = function(connect, points, end) {
+ if (connect) {
+ return function(j) {
+ while (++j < end) {
+ if (!(points[j].yval === null)) break;
+ }
+ return j;
+ }
+ } else {
+ return function(j) { return j + 1 };
+ }
+};
+
DygraphCanvasRenderer.prototype._drawStyledLine = function(
ctx, i, setName, color, strokeWidth, strokePattern, drawPoints,
drawPointCallback, pointSize) {
if (!Dygraph.isArrayLike(strokePattern)) {
strokePattern = null;
}
+ var drawGapPoints = this.dygraph_.attr_('drawGapPoints', setName);
var point;
+ var next = DygraphCanvasRenderer.makeNextPointStep_(
+ this.attr_('connectSeparatedPoints'), points, afterLastIndexInSet);
ctx.save();
- for (var j = firstIndexInSet; j < afterLastIndexInSet; j++) {
+ for (var j = firstIndexInSet; j < afterLastIndexInSet; j = next(j)) {
point = points[j];
if (isNullOrNaN(point.canvasy)) {
if (stepPlot && prevX !== null) {
// and next points are null.
var isIsolated = (!prevX && (j == points.length - 1 ||
isNullOrNaN(points[j+1].canvasy)));
+ if (drawGapPoints) {
+ // Also consider a point to be is "isolated" if it's adjacent to a
+ // null point, excluding the graph edges.
+ if ((j > 0 && !prevX) ||
+ (j < points.length - 1 && isNullOrNaN(points[j+1].canvasy))) {
+ isIsolated = true;
+ }
+ }
if (prevX === null) {
prevX = point.canvasx;
prevY = point.canvasy;
this.dygraph_, setName, ctx, cb[0], cb[1], color, pointSize);
ctx.restore();
}
- firstIndexInSet = afterLastIndexInSet;
ctx.restore();
};
axis = this.dygraph_.axisPropertiesForSeries(setName);
color = this.colors[setName];
+ var firstIndexInSet = this.layout.setPointsOffsets[i];
+ var setLength = this.layout.setPointsLengths[i];
+ var afterLastIndexInSet = firstIndexInSet + setLength;
+
+ var next = DygraphCanvasRenderer.makeNextPointStep_(
+ this.attr_('connectSeparatedPoints'), points,
+ afterLastIndexInSet);
+
// setup graphics context
prevX = NaN;
prevY = NaN;
fillAlpha + ')';
ctx.fillStyle = err_color;
ctx.beginPath();
- for (j = 0; j < pointsLength; j++) {
+ for (j = firstIndexInSet; j < afterLastIndexInSet; j = next(j)) {
point = points[j];
- if (point.name == setName) {
+ if (point.name == setName) { // TODO(klausw): this is always true
if (!Dygraph.isOK(point.y)) {
prevX = NaN;
continue;
ctx.restore();
} else if (fillGraph) {
ctx.save();
- var baseline = []; // for stacked graphs: baseline for filling
+ var baseline = {}; // for stacked graphs: baseline for filling
+ var currBaseline;
// process sets in reverse order (needed for stacked graphs)
for (i = setCount - 1; i >= 0; i--) {
if (axisY < 0.0) axisY = 0.0;
else if (axisY > 1.0) axisY = 1.0;
axisY = this.area.h * axisY + this.area.y;
+ var firstIndexInSet = this.layout.setPointsOffsets[i];
+ var setLength = this.layout.setPointsLengths[i];
+ var afterLastIndexInSet = firstIndexInSet + setLength;
+
+ var next = DygraphCanvasRenderer.makeNextPointStep_(
+ this.attr_('connectSeparatedPoints'), points,
+ afterLastIndexInSet);
// setup graphics context
prevX = NaN;
fillAlpha + ')';
ctx.fillStyle = err_color;
ctx.beginPath();
- for (j = 0; j < pointsLength; j++) {
+ for (j = firstIndexInSet; j < afterLastIndexInSet; j = next(j)) {
point = points[j];
- if (point.name == setName) {
+ if (point.name == setName) { // TODO(klausw): this is always true
if (!Dygraph.isOK(point.y)) {
prevX = NaN;
continue;
}
if (stackedGraph) {
- var lastY = baseline[point.canvasx];
- if (lastY === undefined) lastY = axisY;
- baseline[point.canvasx] = point.canvasy;
+ currBaseline = baseline[point.canvasx];
+ var lastY;
+ if (currBaseline === undefined) {
+ lastY = axisY;
+ } else {
+ if(stepPlot) {
+ lastY = currBaseline[0];
+ } else {
+ lastY = currBaseline;
+ }
+ }
newYs = [ point.canvasy, lastY ];
+
+ if(stepPlot) {
+ // Step plots must keep track of the top and bottom of
+ // the baseline at each point.
+ if(prevYs[0] === -1) {
+ baseline[point.canvasx] = [ point.canvasy, axisY ];
+ } else {
+ baseline[point.canvasx] = [ point.canvasy, prevYs[0] ];
+ }
+ } else {
+ baseline[point.canvasx] = point.canvasy;
+ }
+
} else {
newYs = [ point.canvasy, axisY ];
}
if (!isNaN(prevX)) {
ctx.moveTo(prevX, prevYs[0]);
+
if (stepPlot) {
ctx.lineTo(point.canvasx, prevYs[0]);
+ if(currBaseline) {
+ // Draw to the bottom of the baseline
+ ctx.lineTo(point.canvasx, currBaseline[1]);
+ } else {
+ ctx.lineTo(point.canvasx, newYs[1]);
+ }
} else {
ctx.lineTo(point.canvasx, newYs[0]);
+ ctx.lineTo(point.canvasx, newYs[1]);
}
- ctx.lineTo(point.canvasx, newYs[1]);
+
ctx.lineTo(prevX, prevYs[1]);
ctx.closePath();
}
}
// Drawing the lines.
- var firstIndexInSet = 0;
- var afterLastIndexInSet = 0;
- var setLength = 0;
for (i = 0; i < setCount; i += 1) {
this._drawLine(ctx, i);
}