X-Git-Url: https://adrianiainlam.tk/git/?a=blobdiff_plain;f=dygraph-canvas.js;h=2f8821e17fad93e0d16d743508c6e04eb2119f6c;hb=44f29e932dcbe83c1bfaebb8735579392e27a5df;hp=830ed2aa5a05787c02264580b6acf7ed563df0a6;hpb=0abfbd7e563fc0e53015ec875c324890761071ba;p=dygraphs.git diff --git a/dygraph-canvas.js b/dygraph-canvas.js index 830ed2a..2f8821e 100644 --- a/dygraph-canvas.js +++ b/dygraph-canvas.js @@ -19,7 +19,7 @@ DygraphLayout = function(dygraph, options) { this.options = {}; // TODO(danvk): remove, use attr_ instead. Dygraph.update(this.options, options ? options : {}); this.datasets = new Array(); - this.annotations = new Array() + this.annotations = new Array(); }; DygraphLayout.prototype.attr_ = function(name) { @@ -32,9 +32,9 @@ DygraphLayout.prototype.addDataset = function(setname, set_xy) { DygraphLayout.prototype.setAnnotations = function(ann) { // The Dygraph object's annotations aren't parsed. We parse them here and - // save a copy. + // save a copy. If there is no parser, then the user must be using raw format. this.annotations = []; - var parse = this.attr_('xValueParser'); + var parse = this.attr_('xValueParser') || function(x) { return x; }; for (var i = 0; i < ann.length; i++) { var a = {}; if (!ann[i].xval && !ann[i].x) { @@ -88,6 +88,16 @@ DygraphLayout.prototype._evaluateLimits = function() { axis.maxyval = axis.computedValueRange[1]; axis.yrange = axis.maxyval - axis.minyval; axis.yscale = (axis.yrange != 0 ? 1.0 / axis.yrange : 1.0); + + if (axis.g.attr_("logscale")) { + axis.ylogrange = Dygraph.log10(axis.maxyval) - Dygraph.log10(axis.minyval); + axis.ylogscale = (axis.ylogrange != 0 ? 1.0 / axis.ylogrange : 1.0); + if (!isFinite(axis.ylogrange) || isNaN(axis.ylogrange)) { + axis.g.error('axis ' + i + ' of graph at ' + axis.g + + ' can\'t be displayed in log scale for range [' + + axis.minyval + ' - ' + axis.maxyval + ']'); + } + } } }; @@ -102,22 +112,22 @@ DygraphLayout.prototype._evaluateLineCharts = function() { for (var j = 0; j < dataset.length; j++) { var item = dataset[j]; + + var yval; + if (axis.logscale) { + yval = 1.0 - ((Dygraph.log10(parseFloat(item[1])) - Dygraph.log10(axis.minyval)) * axis.ylogscale); // really should just be yscale. + } else { + yval = 1.0 - ((parseFloat(item[1]) - axis.minyval) * axis.yscale); + } var point = { // TODO(danvk): here x: ((parseFloat(item[0]) - this.minxval) * this.xscale), - y: 1.0 - ((parseFloat(item[1]) - axis.minyval) * axis.yscale), + y: yval, xval: parseFloat(item[0]), yval: parseFloat(item[1]), name: setName }; - // limit the x, y values so they do not overdraw - if (point.y <= 0.0) { - point.y = 0.0; - } - if (point.y >= 1.0) { - point.y = 1.0; - } this.points.push(point); } } @@ -140,7 +150,7 @@ DygraphLayout.prototype._evaluateLineTicks = function() { for (var j = 0; j < axis.ticks.length; j++) { var tick = axis.ticks[j]; var label = tick.label; - var pos = 1.0 - (axis.yscale * (tick.v - axis.minyval)); + var pos = this.dygraph_.toPercentYCoord(tick.v, i); if ((pos >= 0.0) && (pos <= 1.0)) { this.yticks.push([i, pos, label]); } @@ -316,17 +326,21 @@ 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.element.getContext("2d"); + var ctx = this.dygraph_.canvas_.getContext("2d"); ctx.beginPath(); ctx.rect(this.area.x, this.area.y, this.area.w, this.area.h); ctx.clip(); - var ctx = this.dygraph_.hidden_.getContext("2d"); + ctx = this.dygraph_.hidden_.getContext("2d"); ctx.beginPath(); ctx.rect(this.area.x, this.area.y, this.area.w, this.area.h); ctx.clip(); }; +DygraphCanvasRenderer.prototype.attr_ = function(x) { + return this.dygraph_.attr_(x); +}; + DygraphCanvasRenderer.prototype.clear = function() { if (this.isIE) { // VML takes a while to start up, so we just poll every this.IEDelay @@ -350,15 +364,15 @@ DygraphCanvasRenderer.prototype.clear = function() { for (var i = 0; i < this.xlabels.length; i++) { var el = this.xlabels[i]; - el.parentNode.removeChild(el); + if (el.parentNode) el.parentNode.removeChild(el); } for (var i = 0; i < this.ylabels.length; i++) { var el = this.ylabels[i]; - el.parentNode.removeChild(el); + if (el.parentNode) el.parentNode.removeChild(el); } for (var i = 0; i < this.annotations.length; i++) { var el = this.annotations[i]; - el.parentNode.removeChild(el); + if (el.parentNode) el.parentNode.removeChild(el); } this.xlabels = new Array(); this.ylabels = new Array(); @@ -389,11 +403,16 @@ DygraphCanvasRenderer.isSupported = function(canvasName) { * Draw an X/Y grid on top of the existing plot */ DygraphCanvasRenderer.prototype.render = function() { - // Draw the new X/Y grid + // 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"); + function halfUp(x){return Math.round(x)+0.5}; + function halfDown(y){return Math.round(y)-0.5}; if (this.options.underlayCallback) { - this.options.underlayCallback(ctx, this.area, this.layout, this.dygraph_); + // NOTE: we pass the dygraph object to this callback twice to avoid breaking + // users who expect a deprecated form of this callback. + this.options.underlayCallback(ctx, this.area, this.dygraph_, this.dygraph_); } if (this.options.drawYGrid) { @@ -404,8 +423,8 @@ DygraphCanvasRenderer.prototype.render = function() { for (var i = 0; i < ticks.length; i++) { // TODO(danvk): allow secondary axes to draw a grid, too. if (ticks[i][0] != 0) continue; - var x = this.area.x; - var y = this.area.y + ticks[i][1] * this.area.h; + var x = halfUp(this.area.x); + var y = halfDown(this.area.y + ticks[i][1] * this.area.h); ctx.beginPath(); ctx.moveTo(x, y); ctx.lineTo(x + this.area.w, y); @@ -420,8 +439,8 @@ DygraphCanvasRenderer.prototype.render = function() { ctx.strokeStyle = this.options.gridLineColor; ctx.lineWidth = this.options.axisLineWidth; for (var i=0; i