From a96b8ba34c08682182bde256d505f7ae5ed9eee4 Mon Sep 17 00:00:00 2001 From: Adil Date: Wed, 28 Nov 2012 16:37:06 -0500 Subject: [PATCH] - Added xIsEpochDate option to save redundant encoding to Date objects when X axis is already in units of epoch time (performance improvement for large data sets). - Using requestAnimationFrame to make animatedZooms smoother. - Made doUnzoom() and predraw() methods public (to allow more graph control). - Renamed RGBColor to RGBColorParser to avoid a function name collision with: http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-RGBColor --- dygraph-canvas.js | 6 +++--- dygraph-utils.js | 53 +++++++++++++++++++++++++++++++++++++--------------- dygraph.js | 19 +++++++++++++++++-- rgbcolor/rgbcolor.js | 7 ++++++- 4 files changed, 64 insertions(+), 21 deletions(-) diff --git a/dygraph-canvas.js b/dygraph-canvas.js index 29e402e..fad3054 100644 --- a/dygraph-canvas.js +++ b/dygraph-canvas.js @@ -25,7 +25,7 @@ */ /*jshint globalstrict: true */ -/*global Dygraph:false,RGBColor:false */ +/*global Dygraph:false,RGBColorParser:false */ "use strict"; @@ -610,7 +610,7 @@ DygraphCanvasRenderer._errorPlotter = function(e) { 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 rgb = new RGBColorParser(color); var err_color = 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + fillAlpha + ')'; ctx.fillStyle = err_color; @@ -726,7 +726,7 @@ DygraphCanvasRenderer._fillPlotter = function(e) { var newYs; var yscale = axis.yscale; // should be same color as the lines but only 15% opaque. - var rgb = new RGBColor(color); + var rgb = new RGBColorParser(color); var err_color = 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + fillAlpha + ')'; ctx.fillStyle = err_color; diff --git a/dygraph-utils.js b/dygraph-utils.js index e306b3e..797adce 100644 --- a/dygraph-utils.js +++ b/dygraph-utils.js @@ -814,19 +814,35 @@ Dygraph.createIterator = function(array, start, length, opt_predicate) { return new Dygraph.Iterator(array, start, length, opt_predicate); }; +// Shim layer with setTimeout fallback. +// From: http://paulirish.com/2011/requestanimationframe-for-smart-animating/ +window.requestAnimFrame = (function(){ + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function (callback) { + window.setTimeout(callback, 1000 / 60); + }; +})(); + /** - * Call a function N times at a given interval, then call a cleanup function - * once. repeat_fn is called once immediately, then (times - 1) times - * asynchronously. If times=1, then cleanup_fn() is also called synchronously. - * @param {function(number)} repeat_fn Called repeatedly -- takes the number of - * calls (from 0 to times-1) as an argument. - * @param {number} times The number of times to call repeat_fn - * @param {number} every_ms Milliseconds between calls - * @param {function()} cleanup_fn A function to call after all repeat_fn calls. + * @private + * Call a function at most N times at an attempted given interval, then call a + * cleanup function once. repeat_fn is called once immediately, then (times - 1) + * times asynchronously. If times=1, then cleanup_fn() is also called + * synchronously. + * @param repeat_fn {Function} Called repeatedly -- takes the number of calls + * (from 0 to times-1) as an argument. + * @param times {number} The number of times max to call repeat_fn + * @param every_ms {number} Milliseconds to schedule between calls + * @param cleanup_fn {Function} A function to call after all repeat_fn calls. * @private */ Dygraph.repeatAndCleanup = function(repeat_fn, times, every_ms, cleanup_fn) { var count = 0; + var previous_count; var start_time = new Date().getTime(); repeat_fn(count); if (times == 1) { @@ -836,17 +852,24 @@ Dygraph.repeatAndCleanup = function(repeat_fn, times, every_ms, cleanup_fn) { (function loop() { if (count >= times) return; - var target_time = start_time + (1 + count) * every_ms; - setTimeout(function() { - count++; - repeat_fn(count); - if (count >= times - 1) { + window.requestAnimFrame(function(scheduled_epoch_time_ms) { + var delay = (scheduled_epoch_time_ms - start_time); + previous_count = count; + count = Math.floor(delay / every_ms); + if ((count - previous_count) > (times / 2)) { + count = previous_count + (times / 2); + } + if (count > times - 1) { + // Ensure call at max times. + if (previous_count !== (times - 1)) { + repeat_fn(times - 1); + } cleanup_fn(); } else { + repeat_fn(count); loop(); } - }, target_time - new Date().getTime()); - // TODO(danvk): adjust every_ms to produce evenly-timed function calls. + }); })(); }; diff --git a/dygraph.js b/dygraph.js index d42bb9f..3366fe3 100644 --- a/dygraph.js +++ b/dygraph.js @@ -91,7 +91,8 @@ Dygraph.DEFAULT_ROLL_PERIOD = 1; Dygraph.DEFAULT_WIDTH = 480; Dygraph.DEFAULT_HEIGHT = 320; -Dygraph.ANIMATION_STEPS = 10; +// For max 60 Hz. animation: +Dygraph.ANIMATION_STEPS = 12; Dygraph.ANIMATION_DURATION = 200; // These are defined before DEFAULT_ATTRS so that it can refer to them. @@ -273,6 +274,8 @@ Dygraph.DEFAULT_ATTRS = { rangeSelectorPlotStrokeColor: "#808FAB", rangeSelectorPlotFillColor: "#A7B1C4", + xIsEpochDate: false, + // The ordering here ensures that central lines always appear above any // fill bars/error bars. plotter: [ @@ -1455,6 +1458,10 @@ Dygraph.prototype.doZoomY_ = function(lowY, highY) { }); }; +Dygraph.prototype.doUnzoom = function() { + this.doUnzoom_(); +}; + /** * Reset the zoom to the original view coordinates. This is the same as * double-clicking on the graph. @@ -2135,6 +2142,10 @@ Dygraph.prototype.extremeValues_ = function(series) { return [minY, maxY]; }; +Dygraph.prototype.predraw = function() { + this.predraw_(); +}; + /** * @private * This function is called once when the chart's data is changed or the options @@ -3095,12 +3106,16 @@ Dygraph.prototype.parseArray_ = function(data) { } } - if (Dygraph.isDateLike(data[0][0])) { + if (this.attr_("xIsEpochDate") || Dygraph.isDateLike(data[0][0])) { // Some intelligent defaults for a date x-axis. this.attrs_.axes.x.valueFormatter = Dygraph.dateString_; this.attrs_.axes.x.axisLabelFormatter = Dygraph.dateAxisFormatter; this.attrs_.axes.x.ticker = Dygraph.dateTicker; + if (this.attr_("xIsEpochDate")) { + return data; + } + // Assume they're all dates. var parsedData = Dygraph.clone(data); for (i = 0; i < data.length; i++) { diff --git a/rgbcolor/rgbcolor.js b/rgbcolor/rgbcolor.js index 67b730e..5a88244 100644 --- a/rgbcolor/rgbcolor.js +++ b/rgbcolor/rgbcolor.js @@ -4,13 +4,18 @@ * NOTE: modified by danvk. I removed the "getHelpXML" function to reduce the * file size, added "use strict" and a few "var" declarations where needed. * + * Modifications by adilh: + * Original "RGBColor" function name collides with: + * http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-RGBColor + * so renamed to "RGBColorParser" + * * @author Stoyan Stefanov * @link http://www.phpied.com/rgb-color-parser-in-javascript/ * @license Use it if you like it */ "use strict"; -function RGBColor(color_string) +function RGBColorParser(color_string) { this.ok = false; -- 2.7.4