Add new issue and PR templates
[dygraphs.git] / src / dygraph-canvas.js
index a688c43..7ba66ff 100644 (file)
  * @constructor
  */
 
-var DygraphCanvasRenderer = (function() {
 /*global Dygraph:false */
 "use strict";
 
+import * as utils from './dygraph-utils';
+import Dygraph from './dygraph';
+
 
 /**
  * @constructor
@@ -57,7 +59,7 @@ var DygraphCanvasRenderer = function(dygraph, element, elementContext, layout) {
   this.width = dygraph.width_;
 
   // --- check whether everything is ok before we return
-  if (!Dygraph.isCanvasSupported(this.element)) {
+  if (!utils.isCanvasSupported(this.element)) {
     throw "Canvas is not supported.";
   }
 
@@ -68,7 +70,7 @@ var DygraphCanvasRenderer = function(dygraph, element, elementContext, layout) {
   // This ensures that we don't overdraw.
   // on Android 3 and 4, setting a clipping area on a canvas prevents it from
   // displaying anything.
-  if (!Dygraph.isAndroid()) {
+  if (!utils.isAndroid()) {
     var ctx = this.dygraph_.canvas_ctx_;
     ctx.beginPath();
     ctx.rect(this.area.x, this.area.y, this.area.w, this.area.h);
@@ -135,7 +137,7 @@ DygraphCanvasRenderer._drawStyledLine = function(e,
   // TODO(konigsberg): Compute attributes outside this method call.
   var stepPlot = g.getBooleanOption("stepPlot", e.setName);
 
-  if (!Dygraph.isArrayLike(strokePattern)) {
+  if (!utils.isArrayLike(strokePattern)) {
     strokePattern = null;
   }
 
@@ -143,7 +145,7 @@ DygraphCanvasRenderer._drawStyledLine = function(e,
 
   var points = e.points;
   var setName = e.setName;
-  var iter = Dygraph.createIterator(points, 0, points.length,
+  var iter = utils.createIterator(points, 0, points.length,
       DygraphCanvasRenderer._getIteratorPredicate(
           g.getBooleanOption("connectSeparatedPoints", setName)));
 
@@ -152,7 +154,7 @@ DygraphCanvasRenderer._drawStyledLine = function(e,
   var ctx = e.drawingContext;
   ctx.save();
   if (stroking) {
-    ctx.installPattern(strokePattern);
+    if (ctx.setLineDash) ctx.setLineDash(strokePattern);
   }
 
   var pointsOnLine = DygraphCanvasRenderer._drawSeries(
@@ -161,7 +163,7 @@ DygraphCanvasRenderer._drawStyledLine = function(e,
       e, pointsOnLine, drawPointCallback, color, pointSize);
 
   if (stroking) {
-    ctx.uninstallPattern();
+    if (ctx.setLineDash) ctx.setLineDash([]);
   }
 
   ctx.restore();
@@ -334,7 +336,7 @@ DygraphCanvasRenderer.prototype._renderLineChart = function(opt_seriesName, opt_
   // Determine which series have specialized plotters.
   var plotter_attr = this.dygraph_.getOption("plotter");
   var plotters = plotter_attr;
-  if (!Dygraph.isArrayLike(plotters)) {
+  if (!utils.isArrayLike(plotters)) {
     plotters = [plotters];
   }
 
@@ -425,7 +427,7 @@ DygraphCanvasRenderer._linePlotter = function(e) {
   // this code a bit nasty.
   var borderWidth = g.getNumericOption("strokeBorderWidth", setName);
   var drawPointCallback = g.getOption("drawPointCallback", setName) ||
-      Dygraph.Circles.DEFAULT;
+      utils.Circles.DEFAULT;
   var strokePattern = g.getOption("strokePattern", setName);
   var drawPoints = g.getBooleanOption("drawPoints", setName);
   var pointSize = g.getNumericOption("pointSize", setName);
@@ -475,7 +477,7 @@ DygraphCanvasRenderer._errorPlotter = function(e) {
   var stepPlot = g.getBooleanOption("stepPlot", setName);
   var points = e.points;
 
-  var iter = Dygraph.createIterator(points, 0, points.length,
+  var iter = utils.createIterator(points, 0, points.length,
       DygraphCanvasRenderer._getIteratorPredicate(
           g.getBooleanOption("connectSeparatedPoints", setName)));
 
@@ -486,7 +488,7 @@ DygraphCanvasRenderer._errorPlotter = function(e) {
   var prevY = NaN;
   var prevYs = [-1, -1];
   // should be same color as the lines but only 15% opaque.
-  var rgb = Dygraph.toRGB_(color);
+  var rgb = utils.toRGB_(color);
   var err_color =
       'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + fillAlpha + ')';
   ctx.fillStyle = err_color;
@@ -548,6 +550,7 @@ DygraphCanvasRenderer._errorPlotter = function(e) {
 DygraphCanvasRenderer._fastCanvasProxy = function(context) {
   var pendingActions = [];  // array of [type, x, y] tuples
   var lastRoundedX = null;
+  var lastFlushedX = null;
 
   var LINE_TO = 1,
       MOVE_TO = 2;
@@ -626,6 +629,9 @@ DygraphCanvasRenderer._fastCanvasProxy = function(context) {
         context.moveTo(action[1], action[2]);
       }
     }
+    if (pendingActions.length) {
+      lastFlushedX = pendingActions[pendingActions.length - 1][1];
+    }
     actionCount += pendingActions.length;
     pendingActions = [];
   };
@@ -633,7 +639,12 @@ DygraphCanvasRenderer._fastCanvasProxy = function(context) {
   var addAction = function(action, x, y) {
     var rx = Math.round(x);
     if (lastRoundedX === null || rx != lastRoundedX) {
-      flushActions();
+      // if there are large gaps on the x-axis, it's essential to keep the
+      // first and last point as well.
+      var hasGapOnLeft = (lastRoundedX - lastFlushedX > 1),
+          hasGapOnRight = (rx - lastRoundedX > 1),
+          hasGap = hasGapOnLeft || hasGapOnRight;
+      flushActions(hasGap);
       lastRoundedX = rx;
     }
     pendingActions.push([action, x, y]);
@@ -698,7 +709,6 @@ DygraphCanvasRenderer._fillPlotter = function(e) {
   var sets = e.allSeriesPoints;
   var setCount = sets.length;
 
-  var fillAlpha = g.getNumericOption('fillAlpha');
   var stackedGraph = g.getBooleanOption("stackedGraph");
   var colors = g.getColors();
 
@@ -730,6 +740,7 @@ DygraphCanvasRenderer._fillPlotter = function(e) {
     var setName = setNames[setIdx];
     if (!g.getBooleanOption('fillGraph', setName)) continue;
 
+    var fillAlpha = g.getNumericOption('fillAlpha', setName);
     var stepPlot = g.getBooleanOption('stepPlot', setName);
     var color = colors[setIdx];
     var axis = g.axisPropertiesForSeries(setName);
@@ -739,7 +750,7 @@ DygraphCanvasRenderer._fillPlotter = function(e) {
     axisY = area.h * axisY + area.y;
 
     var points = sets[setIdx];
-    var iter = Dygraph.createIterator(points, 0, points.length,
+    var iter = utils.createIterator(points, 0, points.length,
         DygraphCanvasRenderer._getIteratorPredicate(
             g.getBooleanOption("connectSeparatedPoints", setName)));
 
@@ -748,7 +759,7 @@ DygraphCanvasRenderer._fillPlotter = function(e) {
     var prevYs = [-1, -1];
     var newYs;
     // should be same color as the lines but only 15% opaque.
-    var rgb = Dygraph.toRGB_(color);
+    var rgb = utils.toRGB_(color);
     var err_color =
         'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + fillAlpha + ')';
     ctx.fillStyle = err_color;
@@ -757,7 +768,7 @@ DygraphCanvasRenderer._fillPlotter = function(e) {
 
     // If the point density is high enough, dropping segments on their way to
     // the canvas justifies the overhead of doing so.
-    if (points.length > 2 * g.width_) {
+    if (points.length > 2 * g.width_ || Dygraph.FORCE_FAST_PROXY) {
       ctx = DygraphCanvasRenderer._fastCanvasProxy(ctx);
     }
 
@@ -773,7 +784,7 @@ DygraphCanvasRenderer._fillPlotter = function(e) {
     var point;
     while (iter.hasNext) {
       point = iter.next();
-      if (!Dygraph.isOK(point.y) && !stepPlot) {
+      if (!utils.isOK(point.y) && !stepPlot) {
         traceBackPath(ctx, prevX, prevYs[1], pathBack);
         pathBack = [];
         prevX = NaN;
@@ -857,6 +868,4 @@ DygraphCanvasRenderer._fillPlotter = function(e) {
   }
 };
 
-return DygraphCanvasRenderer;
-
-})();
+export default DygraphCanvasRenderer;