From: Dan Vanderkam Date: Mon, 22 Jul 2013 02:12:01 +0000 (-0400) Subject: closurize dygraph-layout.js X-Git-Url: https://adrianiainlam.tk/git/?a=commitdiff_plain;h=7bc6574f660a7af0fa777739999bd91a83e05939;p=dygraphs.git closurize dygraph-layout.js --- diff --git a/closure-todo.txt b/closure-todo.txt index 392ede4..f9c0357 100644 --- a/closure-todo.txt +++ b/closure-todo.txt @@ -11,7 +11,7 @@ under the Closure Compiler without any errors or warnings. Core: - dygraph-canvas.js - dygraph-interaction-model.js -- dygraph-layout.js +x dygraph-layout.js x dygraph-options.js - dygraph.js x dygraph-gviz.js @@ -32,6 +32,6 @@ Plugins: Here's a command that can be used to build dygraphs using the closure compiler: -java -jar ../../closure-compiler-read-only/build/compiler.jar --js=dygraph-utils.js --js=dashed-canvas.js --js=dygraph-options-reference.js --js=dygraph-tickers.js --js=dygraph-gviz.js --js=dygraph-options.js --js_output_file=/tmp/out.js --compilation_level ADVANCED_OPTIMIZATIONS --warning_level VERBOSE --externs dygraph-externs.js +java -jar ../../closure-compiler-read-only/build/compiler.jar --js=dygraph-utils.js --js=dashed-canvas.js --js=dygraph-options-reference.js --js=dygraph-tickers.js --js=dygraph-gviz.js --js=dygraph-options.js --js=dygraph-layout.js --js_output_file=/tmp/out.js --compilation_level ADVANCED_OPTIMIZATIONS --warning_level VERBOSE --externs dygraph-externs.js As each file is closurized, it can be added as a "--js" parameter. diff --git a/dygraph-externs.js b/dygraph-externs.js index ed5de4c..c40139c 100644 --- a/dygraph-externs.js +++ b/dygraph-externs.js @@ -63,14 +63,32 @@ function GVizDataTable() {} function Dygraph(div, file, attrs) {} /** - * @constructor - */ -function DygraphLayout() {} - -/** - * @type {Array} + * @typedef {{ + * idx: number, + * name: string, + * x: ?number, + * xval: ?number, + * y_bottom: ?number, + * y: ?number, + * y_stacked: ?number, + * y_top: ?number, + * yval_minus: ?number, + * yval: ?number, + * yval_plus: ?number, + * yval_stacked + * }} */ -DygraphLayout.prototype.datasets; +Dygraph.PointType; + +// /** +// * @constructor +// */ +// function DygraphLayout() {} +// +// /** +// * @type {Array.>} +// */ +// DygraphLayout.prototype.points; // TODO: DygraphOptions should not reach inside Dygraph private data like this. /** @type {Object} */ @@ -79,15 +97,122 @@ Dygraph.prototype.attrs_; Dygraph.prototype.user_attrs_; /** + * @param {string} name the name of the option. + */ +Dygraph.prototype.attr_ = function(name) {}; + +/** + * @return {{w: number, h: number}} object. + */ +Dygraph.prototype.size; + +/** * @type {DygraphLayout} */ Dygraph.prototype.layout_; +/** + * @type {!HTMLDivElement} + */ +Dygraph.prototype.graphDiv; + +/** + * @type {!DygraphOptions} + */ +Dygraph.prototype.attributes_; + /** @type {function(): string} */ Dygraph.prototype.getHighlightSeries; -/** @type {Array.<{elem:Element,type:string,fn:function(!Event):(boolean|undefined|null)}>} */ +/** + * @param {string} name Event name. + * @param {Object} extra_props Event-specific properties. + * @return {boolean} Whether to perform the default action. + */ +Dygraph.prototype.cascadeEvents_ = function(name, extra_props) {}; + +/** + * @type {Array.<{ + * elem: !Element, + * type: string, + * fn: function(?Event):(boolean|undefined) + * }>} + */ Dygraph.prototype.registeredEvents_; +/** + * @return {!Array.} two element [left, right] array. + */ +Dygraph.prototype.xAxisRange = function() {}; + +/** + * @param {string} setName Set name. + * @return {Object} axis properties for the series. + */ +Dygraph.prototype.axisPropertiesForSeries = function(setName) {}; + +/** + * @param {number} y The data y-coordinate. + * @param {number} axis The axis number on which the data coordinate lives. + * @return {number} A fraction in [0, 1] where 0 = the top edge. + */ +Dygraph.prototype.toPercentYCoord = function(y, axis) {}; + /** @type {{axes: Object}} */ Dygraph.DEFAULT_ATTRS; + +/** + * @typedef {{ + * xval: (number|undefined), + * x: string, + * series: string, + * icon: (string|undefined), + * width: (number|undefined), + * height: (number|undefined), + * shortText: (string|undefined), + * text: (string|undefined) + * }} + */ +Dygraph.AnnotationType; + +/** + * @typedef {Array.<{ + * v:number, + * label:string, + * label_v:(string|undefined) + * }>} + */ +Dygraph.TickList; + +/** + * @typedef {(function( + * number, + * number, + * number, + * function(string):*, + * Dygraph=, + * Array.= + * ): Dygraph.TickList)} + */ +Dygraph.Ticker; + +/** + * @typedef {{ + * x: number, + * y: number, + * w: number, + * h: number + * }} + */ +Dygraph.Rect; + +/** + * @typedef {{ + * g: !Dygraph, + * minyval: number, + * maxyval: number, + * ticks: Array, + * computedValueRange: Array. + * }} + */ +Dygraph.AxisType; diff --git a/dygraph-gviz.js b/dygraph-gviz.js index 988e0ac..58e14d2 100644 --- a/dygraph-gviz.js +++ b/dygraph-gviz.js @@ -73,7 +73,8 @@ Dygraph.GVizChart.prototype.getSelection = function() { if (row < 0) return selection; - var points = this.date_graph.layout_.points; + var layout = /** @type {DygraphLayout} */(this.date_graph.layout_); + var points = layout.points; for (var setIdx = 0; setIdx < points.length; ++setIdx) { selection.push({row: row, column: setIdx + 1}); } diff --git a/dygraph-layout.js b/dygraph-layout.js index 2d80857..79f4b27 100644 --- a/dygraph-layout.js +++ b/dygraph-layout.js @@ -9,11 +9,7 @@ * dygraphs. */ -var DygraphLayout = (function() { - -/*jshint globalstrict: true */ -/*global Dygraph:false */ -"use strict"; +// Note: @constructor must live outside (function() {})() for Closure Compiler. /** * Creates a new DygraphLayout object. @@ -29,10 +25,12 @@ var DygraphLayout = (function() { * * The naming is a vestige of Dygraph's original PlotKit roots. * + * @param {!Dygraph} dygraph The dygraph object. * @constructor */ var DygraphLayout = function(dygraph) { this.dygraph_ = dygraph; + /** * Array of points for each series. * @@ -45,16 +43,45 @@ var DygraphLayout = function(dygraph) { * @type {Array.>} */ this.points = []; + + /** @type {Array.} */ this.setNames = []; + + /** @type {Array.} */ this.annotations = []; + + /** @type {Array.} */ this.yAxes_ = null; // TODO(danvk): it's odd that xTicks_ and yTicks_ are inputs, but xticks and // yticks are outputs. Clean this up. + /** @type {Dygraph.TickList} */ this.xTicks_ = null; + /** @type {Dygraph.TickList} */ this.yTicks_ = null; + + /** @type {?Dygraph.Rect} */ + this.area_ = null; + + // TODO(danvk): these fields should be objects, not arrays of arrays, which + // can't be easily described in the closure type system. + /** @type {Array.} */ + this.xticks = null; + /** @type {Array.} */ + this.yticks = null; }; + +(function() { + +/*jshint globalstrict: true */ +/*global Dygraph:false */ +"use strict"; + +/** + * @param {string} name Name of the attribute. + * @return {*} Attribute value. + */ DygraphLayout.prototype.attr_ = function(name) { return this.dygraph_.attr_(name); }; @@ -63,7 +90,7 @@ DygraphLayout.prototype.attr_ = function(name) { * Add points for a single series. * * @param {string} setname Name of the series. - * @param {Array.} set_xy Points for the series. + * @param {Array.} set_xy Points for the series. */ DygraphLayout.prototype.addDataset = function(setname, set_xy) { this.points.push(set_xy); @@ -74,7 +101,7 @@ DygraphLayout.prototype.addDataset = function(setname, set_xy) { * Returns the box which the chart should be drawn in. This is the canvas's * box, less space needed for the axis and chart labels. * - * @return {{x: number, y: number, w: number, h: number}} + * @return {?Dygraph.Rect} */ DygraphLayout.prototype.getPlotArea = function() { return this.area_; @@ -90,8 +117,9 @@ DygraphLayout.prototype.computePlotArea = function() { y: 0 }; - area.w = this.dygraph_.width_ - area.x - this.attr_('rightGap'); - area.h = this.dygraph_.height_; + var size = this.dygraph_.size(); + area.w = size.w - area.x - /** @type{number} */(this.attr_('rightGap')); + area.h = size.h; // Let plugins reserve space. var e = { @@ -147,13 +175,31 @@ DygraphLayout.prototype.computePlotArea = function() { this.area_ = area; }; +/** + * @param {Array.} ann The annotations + */ DygraphLayout.prototype.setAnnotations = function(ann) { // The Dygraph object's annotations aren't parsed. We parse them here and // save a copy. If there is no parser, then the user must be using raw format. + + /** @type {Array.} */ this.annotations = []; - var parse = this.attr_('xValueParser') || function(x) { return x; }; + + var parse = /** @type {function(string):number} */(this.attr_('xValueParser')) || function(x) { return parseFloat(x); }; + for (var i = 0; i < ann.length; i++) { - var a = {}; + // lame that closure compiler wants all these undefineds! + /** @type {Dygraph.AnnotationType} */ + var a = { + x: ann[i].x, + series: ann[i].series, + xval: undefined, + icon: undefined, + width: undefined, + height: undefined, + shortText: undefined, + text: undefined + }; if (!ann[i].xval && ann[i].x === undefined) { Dygraph.error("Annotations must have an 'x' property"); return; @@ -171,11 +217,16 @@ DygraphLayout.prototype.setAnnotations = function(ann) { } }; +/** + * @param {!Dygraph.TickList} xTicks The x-axis ticks. + */ DygraphLayout.prototype.setXTicks = function(xTicks) { this.xTicks_ = xTicks; }; -// TODO(danvk): add this to the Dygraph object's API or move it into Layout. +/** + * @param {Array.} yAxes The y-axes. + */ DygraphLayout.prototype.setYAxes = function (yAxes) { this.yAxes_ = yAxes; }; @@ -299,6 +350,9 @@ DygraphLayout.prototype._evaluateAnnotations = function() { annotations[a.xval + "," + a.series] = a; } + /** + * @type {Array.} + */ this.annotated_points = []; // Exit the function early if there are no annotations. diff --git a/dygraph-options.js b/dygraph-options.js index e912aa7..de15512 100644 --- a/dygraph-options.js +++ b/dygraph-options.js @@ -10,19 +10,6 @@ * Still tightly coupled to Dygraphs, we could remove some of that, you know. */ -var DygraphOptions = (function() { - -/*jshint sub:true */ -/*global Dygraph:false */ -"use strict"; - -/* - * Interesting member variables: (REMOVING THIS LIST AS I CLOSURIZE) - * global_ - global attributes (common among all graphs, AIUI) - * user - attributes set by the user - * series_ - { seriesName -> { idx, yAxis, options }} - */ - /** * This parses attributes into an object that can be easily queried. * @@ -30,7 +17,7 @@ var DygraphOptions = (function() { * if labels are not yet available, since those drive details of the per-series * and per-axis options. * - * @param {Dygraph} dygraph The chart to which these options belong. + * @param {!Dygraph} dygraph The chart to which these options belong. * @constructor */ var DygraphOptions = function(dygraph) { @@ -50,7 +37,8 @@ var DygraphOptions = function(dygraph) { * Contains x-axis specific options, which are stored in the options key. * This matches the yAxes_ object structure (by being a dictionary with an * options element) allowing for shared code. - * @type {options: Object} @private + * @type {Object} + * @private */ this.xAxis_ = {}; this.series_ = {}; @@ -69,6 +57,20 @@ var DygraphOptions = function(dygraph) { this.reparseSeries(); }; +(function() { + +/*jshint sub:true */ +/*global Dygraph:false */ +"use strict"; + +/* + * Interesting member variables: (REMOVING THIS LIST AS I CLOSURIZE) + * global_ - global attributes (common among all graphs, AIUI) + * user - attributes set by the user + * series_ - { seriesName -> { idx, yAxis, options }} + */ + + /** * Not optimal, but does the trick when you're only using two axes. * If we move to more axes, this can just become a function. @@ -370,6 +372,4 @@ DygraphOptions.prototype.seriesNames = function() { return this.labels_; }; -return DygraphOptions; - })(); diff --git a/dygraph-tickers.js b/dygraph-tickers.js index 2e8178c..9d799b1 100644 --- a/dygraph-tickers.js +++ b/dygraph-tickers.js @@ -64,24 +64,7 @@ /*global Dygraph:false */ "use strict"; -// Constants, defined below. -var PREFERRED_LOG_TICK_VALUES; - -/** @typedef {Array.<{v:number, label:string, label_v:(string|undefined)}>} */ -var TickList; - -/** @typedef {function( - * number, - * number, - * number, - * function(string):*, - * Dygraph=, - * Array.= - * ): TickList} - */ -var Ticker; - -/** @type {Ticker} */ +/** @type {Dygraph.Ticker} */ Dygraph.numericLinearTicks = function(a, b, pixels, opts, dygraph, vals) { var nonLogscaleOpts = function(opt) { if (opt === 'logscale') return false; @@ -90,7 +73,27 @@ Dygraph.numericLinearTicks = function(a, b, pixels, opts, dygraph, vals) { return Dygraph.numericTicks(a, b, pixels, nonLogscaleOpts, dygraph, vals); }; -/** @type {Ticker} */ +/** + * This is a list of human-friendly values at which to show tick marks on a log + * scale. It is k * 10^n, where k=1..9 and n=-39..+39, so: + * ..., 1, 2, 3, 4, 5, ..., 9, 10, 20, 30, ..., 90, 100, 200, 300, ... + * NOTE: this assumes that Dygraph.LOG_SCALE = 10. + * @type {Array.} + */ +var PREFERRED_LOG_TICK_VALUES = (function() { + var vals = []; + for (var power = -39; power <= 39; power++) { + var range = Math.pow(10, power); + for (var mult = 1; mult <= 9; mult++) { + var val = range * mult; + vals.push(val); + } + } + return vals; +})(); + + +/** @type {Dygraph.Ticker} */ Dygraph.numericTicks = function(a, b, pixels, opts, dygraph, vals) { var pixels_per_tick = /** @type{number} */(opts('pixelsPerLabel')); var ticks = []; @@ -209,7 +212,7 @@ Dygraph.numericTicks = function(a, b, pixels, opts, dygraph, vals) { }; -/** @type {Ticker} */ +/** @type {Dygraph.Ticker} */ Dygraph.dateTicker = function(a, b, pixels, opts, dygraph, vals) { var chosen = Dygraph.pickDateTickGranularity(a, b, pixels, opts); @@ -298,25 +301,6 @@ LONG_TICK_PLACEMENTS[CENTENNIAL] = { }; /** - * This is a list of human-friendly values at which to show tick marks on a log - * scale. It is k * 10^n, where k=1..9 and n=-39..+39, so: - * ..., 1, 2, 3, 4, 5, ..., 9, 10, 20, 30, ..., 90, 100, 200, 300, ... - * NOTE: this assumes that Dygraph.LOG_SCALE = 10. - * @type {Array.} - */ -PREFERRED_LOG_TICK_VALUES = function() { - var vals = []; - for (var power = -39; power <= 39; power++) { - var range = Math.pow(10, power); - for (var mult = 1; mult <= 9; mult++) { - var val = range * mult; - vals.push(val); - } - } - return vals; -}(); - -/** * Determine the correct granularity of ticks on a date axis. * * @param {number} a Left edge of the chart (ms) @@ -364,7 +348,7 @@ Dygraph.numDateTicks = function(start_time, end_time, granularity) { * @param {number} granularity (one of the granularities enumerated above) * @param {function(string):*} opts Function mapping from option name -> value. * @param {Dygraph=} dg - * @return {!TickList} + * @return {!Dygraph.TickList} */ Dygraph.getDateAxis = function(start_time, end_time, granularity, opts, dg) { var formatter = /** @type{AxisLabelFormatter} */( diff --git a/dygraph-utils.js b/dygraph-utils.js index e7cb898..df4fcad 100644 --- a/dygraph-utils.js +++ b/dygraph-utils.js @@ -194,7 +194,7 @@ Dygraph.prototype.addAndTrackEvent = function(elem, type, fn) { * of the world. * @param {!Element} elem The element to add the event to. * @param {string} type The type of the event, e.g. 'click' or 'mousemove'. - * @param {function(Event):(boolean|undefined)} fn The function to call + * @param {function(?Event):(boolean|undefined)} fn The function to call * on the event. The function takes one parameter: the event object. * @private */ @@ -1182,7 +1182,7 @@ Dygraph.toRGB_ = function(color_str) { div.style.backgroundColor = color_str; div.style.visibility = 'hidden'; document.body.appendChild(div); - var rgb_str = window.getComputedStyle(div).backgroundColor; + var rgb_str = window.getComputedStyle(div, null).backgroundColor; document.body.removeChild(div); var bits = /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/.exec(rgb_str); return {