From 2cf95fff7f77658eccb3d00e7d52d081863c61ff Mon Sep 17 00:00:00 2001 From: Robert Konigsberg Date: Mon, 25 Apr 2011 15:25:17 -0400 Subject: [PATCH] Expose function that can be replaced during tests for mocking out the HTML5 canvas context. --- dygraph-canvas.js | 22 +++++++++++++--------- dygraph.js | 34 ++++++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/dygraph-canvas.js b/dygraph-canvas.js index 522629c..2874990 100644 --- a/dygraph-canvas.js +++ b/dygraph-canvas.js @@ -277,10 +277,13 @@ DygraphLayout.prototype.unstackPointAtIndex = function(idx) { /** * Sets some PlotKit.CanvasRenderer options * @param {Object} element The canvas to attach to + * @param {Object} elementContext The 2d context of the canvas (injected so it + * can be mocked for testing.) * @param {Layout} layout The DygraphLayout object for this graph. * @param {Object} options Options to pass on to CanvasRenderer */ -DygraphCanvasRenderer = function(dygraph, element, layout, options) { +DygraphCanvasRenderer = function(dygraph, element, elementContext, layout, + options) { // TODO(danvk): remove options, just use dygraph.attr_. this.dygraph_ = dygraph; @@ -306,6 +309,7 @@ DygraphCanvasRenderer = function(dygraph, element, layout, options) { this.layout = layout; this.element = element; + this.elementContext = elementContext; this.container = this.element.parentNode; this.height = this.element.height; @@ -360,12 +364,12 @@ DygraphCanvasRenderer = function(dygraph, element, layout, options) { // Set up a clipping area for the canvas (and the interaction canvas). // This ensures that we don't overdraw. - var ctx = this.dygraph_.canvas_.getContext("2d"); + var ctx = this.dygraph_.canvas_ctx_; ctx.beginPath(); ctx.rect(this.area.x, this.area.y, this.area.w, this.area.h); ctx.clip(); - ctx = this.dygraph_.hidden_.getContext("2d"); + ctx = this.dygraph_.hidden_ctx_; ctx.beginPath(); ctx.rect(this.area.x, this.area.y, this.area.w, this.area.h); ctx.clip(); @@ -383,7 +387,7 @@ DygraphCanvasRenderer.prototype.clear = function() { this.clearDelay.cancel(); this.clearDelay = null; } - var context = this.element.getContext("2d"); + var context = this.elementContext; } catch (e) { // TODO(danvk): this is broken, since MochiKit.Async is gone. @@ -393,7 +397,7 @@ DygraphCanvasRenderer.prototype.clear = function() { } } - var context = this.element.getContext("2d"); + var context = this.elementContext; context.clearRect(0, 0, this.width, this.height); for (var i = 0; i < this.xlabels.length; i++) { @@ -445,7 +449,7 @@ DygraphCanvasRenderer.isSupported = function(canvasName) { DygraphCanvasRenderer.prototype.render = function() { // Draw the new X/Y grid. Lines appear crisper when pixels are rounded to // half-integers. This prevents them from drawing in two rows/cols. - var ctx = this.element.getContext("2d"); + var ctx = this.elementContext; function halfUp(x){return Math.round(x)+0.5}; function halfDown(y){return Math.round(y)-0.5}; @@ -505,7 +509,7 @@ DygraphCanvasRenderer.prototype._renderAxis = function() { function halfUp(x){return Math.round(x)+0.5}; function halfDown(y){return Math.round(y)-0.5}; - var context = this.element.getContext("2d"); + var context = this.elementContext; var labelStyle = { "position": "absolute", @@ -823,7 +827,7 @@ DygraphCanvasRenderer.prototype._renderAnnotations = function() { this.container.appendChild(div); this.annotations.push(div); - var ctx = this.element.getContext("2d"); + var ctx = this.elementContext; ctx.strokeStyle = this.colors[p.name]; ctx.beginPath(); if (!a.attachAtBottom) { @@ -844,7 +848,7 @@ DygraphCanvasRenderer.prototype._renderAnnotations = function() { */ DygraphCanvasRenderer.prototype._renderLineChart = function() { // TODO(danvk): use this.attr_ for many of these. - var context = this.element.getContext("2d"); + var context = this.elementContext; var colorCount = this.options.colorScheme.length; var colorScheme = this.options.colorScheme; var fillAlpha = this.options.fillAlpha; diff --git a/dygraph.js b/dygraph.js index ae1faba..4ab665e 100644 --- a/dygraph.js +++ b/dygraph.js @@ -161,6 +161,22 @@ Dygraph.VERTICAL = 2; // Used for initializing annotation CSS rules only once. Dygraph.addedAnnotationCSS = false; +/** + * Return the 2d context for a dygraph canvas. + * + * This method is only exposed for the sake of replacing the function in + * automated tests, e.g. + * + * var oldFunc = Dygraph.getContext(); + * Dygraph.getContext = function(canvas) { + * var realContext = oldFunc(canvas); + * return new Proxy(realContext); + * }; + */ +Dygraph.getContext = function(canvas) { + return canvas.getContext("2d"); +}; + Dygraph.prototype.__old_init__ = function(div, file, labels, attrs) { // Labels is no longer a constructor parameter, since it's typically set // directly from the data source. It also conains a name for the x-axis, @@ -657,8 +673,11 @@ Dygraph.prototype.createInterface_ = function() { this.canvas_.style.width = this.width_ + "px"; // for IE this.canvas_.style.height = this.height_ + "px"; // for IE + this.canvas_ctx_ = Dygraph.getContext(this.canvas_); + // ... and for static parts of the chart. this.hidden_ = this.createPlotKitCanvas_(this.canvas_); + this.hidden_ctx_ = Dygraph.getContext(this.hidden_); // The interactive parts of the graph are drawn on top of the chart. this.graphDiv.appendChild(this.hidden_); @@ -1218,9 +1237,7 @@ Dygraph.endZoom = function(event, g, context) { g.doZoomY_(Math.min(context.dragStartY, context.dragEndY), Math.max(context.dragStartY, context.dragEndY)); } else { - g.canvas_.getContext("2d").clearRect(0, 0, - g.canvas_.width, - g.canvas_.height); + g.canvas_ctx_.clearRect(0, 0, g.canvas_.width, g.canvas_.height); } context.dragStartX = null; context.dragStartY = null; @@ -1398,7 +1415,7 @@ Dygraph.prototype.createDragInterface_ = function() { Dygraph.prototype.drawZoomRect_ = function(direction, startX, endX, startY, endY, prevDirection, prevEndX, prevEndY) { - var ctx = this.canvas_.getContext("2d"); + var ctx = this.canvas_ctx_; // Clean up from the previous rect if necessary if (prevDirection == Dygraph.HORIZONTAL) { @@ -1681,7 +1698,7 @@ Dygraph.prototype.setLegendHTML_ = function(x, sel_points) { */ Dygraph.prototype.updateSelection_ = function() { // Clear the previously drawn vertical, if there is one - var ctx = this.canvas_.getContext("2d"); + var ctx = this.canvas_ctx_; if (this.previousVerticalX_ >= 0) { // Determine the maximum highlight circle size. var maxCircleSize = 0; @@ -1780,8 +1797,7 @@ Dygraph.prototype.mouseOut_ = function(event) { */ Dygraph.prototype.clearSelection = function() { // Get rid of the overlay data - var ctx = this.canvas_.getContext("2d"); - ctx.clearRect(0, 0, this.width_, this.height_); + this.canvas_ctx_.clearRect(0, 0, this.width_, this.height_); this.setLegendHTML_(); this.selPoints_ = []; this.lastx_ = -1; @@ -2429,7 +2445,9 @@ Dygraph.prototype.predraw_ = function() { // Create a new plotter. if (this.plotter_) this.plotter_.clear(); this.plotter_ = new DygraphCanvasRenderer(this, - this.hidden_, this.layout_, + this.hidden_, + this.hidden_ctx_, + this.layout_, this.renderOptions_); // The roller sits in the bottom left corner of the chart. We don't know where -- 2.7.4