X-Git-Url: https://adrianiainlam.tk/git/?a=blobdiff_plain;f=dygraph.js;h=09a668453608de16a6a82c6f14f29176621b2685;hb=540d00f13a75b1a8e74eeefca61571f79ace7614;hp=92d6de9582c359fc97393f913d978bafb831bbdc;hpb=353a0294d48f0e9338280a45353c1811e5df7012;p=dygraphs.git diff --git a/dygraph.js b/dygraph.js index 92d6de9..09a6684 100644 --- a/dygraph.js +++ b/dygraph.js @@ -144,7 +144,8 @@ DateGraph.prototype.__init__ = function(div, file, labels, attrs) { this.createRollInterface_(); this.createDragInterface_(); - connect(window, 'onload', this, function(e) { this.start_(); }); + // connect(window, 'onload', this, function(e) { this.start_(); }); + this.start_(); }; /** @@ -257,13 +258,18 @@ DateGraph.prototype.createStatusMessage_ = function(){ */ DateGraph.prototype.createRollInterface_ = function() { var padding = this.plotter_.options.padding; + if (typeof this.attrs_.showRoller == 'undefined') { + this.attrs_.showRoller = false; + } + var display = this.attrs_.showRoller ? "block" : "none"; var textAttr = { "type": "text", "size": "2", "value": this.rollPeriod_, "style": { "position": "absolute", "zIndex": 10, "top": (this.height_ - 25 - padding.bottom) + "px", - "left": (padding.left+1) + "px" } + "left": (padding.left+1) + "px", + "display": display } }; var roller = MochiKit.DOM.INPUT(textAttr); var pa = this.graphDiv; @@ -527,24 +533,51 @@ DateGraph.prototype.mouseOut_ = function(event) { }; /** + * Return a string version of the hours, minutes and seconds portion of a date. + * @param {Number} date The JavaScript date (ms since epoch) + * @return {String} A time of the form "HH:MM:SS" + * @private + */ +DateGraph.prototype.hmsString_ = function(date) { + var zeropad = function(x) { + if (x < 10) return "0" + x; else return "" + x; + }; + var d = new Date(date); + if (d.getSeconds()) { + return zeropad(d.getHours()) + ":" + + zeropad(d.getMinutes()) + ":" + + zeropad(d.getSeconds()); + } else if (d.getMinutes()) { + return zeropad(d.getHours()) + ":" + zeropad(d.getMinutes()); + } else { + return zeropad(d.getHours()); + } +} + +/** * Convert a JS date (millis since epoch) to YYYY/MM/DD * @param {Number} date The JavaScript date (ms since epoch) * @return {String} A date of the form "YYYY/MM/DD" * @private */ DateGraph.prototype.dateString_ = function(date) { + var zeropad = function(x) { + if (x < 10) return "0" + x; else return "" + x; + }; var d = new Date(date); // Get the year: var year = "" + d.getFullYear(); // Get a 0 padded month string - var month = "" + (d.getMonth() + 1); //months are 0-offset, sigh - if (month.length < 2) month = "0" + month; + var month = zeropad(d.getMonth() + 1); //months are 0-offset, sigh // Get a 0 padded day string - var day = "" + d.getDate(); - if (day.length < 2) day = "0" + day; + var day = zeropad(d.getDate()); + + var ret = ""; + var frac = d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds(); + if (frac) ret = " " + this.hmsString_(date); - return year + "/" + month + "/" + day; + return year + "/" + month + "/" + day + ret; }; /** @@ -625,10 +658,15 @@ DateGraph.prototype.dateTicker = function(startDate, endDate) { for (var week = startDate - 14; week < endDate + 14; week += 7) { scale.push(week * ONE_DAY); } - } else { // daily + } else if (dateSpan > 1) { // daily for (var day = startDate - 14; day < endDate + 14; day += 1) { scale.push(day * ONE_DAY); } + } else { // hourly + for (var hour = Math.floor(startDate - 1) * 24; + hour < (endDate + 1) * 24; hour += 1) { + scale.push(hour * 60*60*1000); + } } var xTicks = []; @@ -645,11 +683,18 @@ DateGraph.prototype.dateTicker = function(startDate, endDate) { } } else { for (var i = 0; i < scale.length; i++) { - var date = new Date(scale[i]); - var year = date.getFullYear().toString(); - var label = this.months[date.getMonth()] + date.getDate(); - label += "'" + year.substr(year.length - 2, 2); - xTicks.push( {label: label, v: date} ); + // TODO(danvk): this is _gross_. Unify all this with dateString_. + var d = new Date(scale[i]); + var frac = d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds(); + var label; + if (frac == 0) { + var year = d.getFullYear().toString(); + var label = this.months[d.getMonth()] + d.getDate(); + label += "'" + year.substr(year.length - 2, 2); + } else { + label = this.hmsString_(d); + } + xTicks.push( {label: label, v: d} ); } } return xTicks; @@ -847,12 +892,29 @@ DateGraph.prototype.rollingAverage = function(originalData, rollPeriod) { } } } else if (this.customBars_) { - // just ignore the rolling for now. - // TODO(danvk): do something reasonable. + var low = 0; + var mid = 0; + var high = 0; + var count = 0; for (var i = 0; i < originalData.length; i++) { var data = originalData[i][1]; var y = data[1]; rollingData[i] = [originalData[i][0], [y, y - data[0], data[2] - y]]; + + low += data[0]; + mid += y; + high += data[2]; + count += 1; + if (i - rollPeriod >= 0) { + var prev = originalData[i - rollPeriod]; + low -= prev[1][0]; + mid -= prev[1][1]; + high -= prev[1][2]; + count -= 1; + } + rollingData[i] = [originalData[i][0], [ 1.0 * mid / count, + 1.0 * (mid - low) / count, + 1.0 * (high - mid) / count ]]; } } else { // Calculate the rolling average for the first rollPeriod - 1 points where @@ -915,18 +977,21 @@ DateGraph.prototype.rollingAverage = function(originalData, rollPeriod) { */ DateGraph.prototype.dateParser = function(dateStr) { var dateStrSlashed; - if (dateStr.search("-") != -1) { + if (dateStr.length == 10 && dateStr.search("-") != -1) { // e.g. '2009-07-12' dateStrSlashed = dateStr.replace("-", "/", "g"); while (dateStrSlashed.search("-") != -1) { dateStrSlashed = dateStrSlashed.replace("-", "/"); } - } else if (dateStr.search("/") != -1) { - return Date.parse(dateStr); - } else { + return Date.parse(dateStrSlashed); + } else if (dateStr.length == 8) { // e.g. '20090712' dateStrSlashed = dateStr.substr(0,4) + "/" + dateStr.substr(4,2) + "/" + dateStr.substr(6,2); + return Date.parse(dateStrSlashed); + } else { + // Any format that Date.parse will accept, e.g. "2009/07/12" or + // "2009/07/12 12:34:56" + return Date.parse(dateStr); } - return Date.parse(dateStrSlashed); }; /** @@ -994,6 +1059,50 @@ DateGraph.prototype.parseCSV_ = function(data) { }; /** + * Parses a DataTable object from gviz. + * The data is expected to have a first column that is either a date or a + * number. All subsequent columns must be numbers. If there is a clear mismatch + * between this.xValueParser_ and the type of the first column, it will be + * fixed. Returned value is in the same format as return value of parseCSV_. + * @param {Array.} data See above. + * @private + */ +DateGraph.prototype.parseDataTable_ = function(data) { + var cols = data.getNumberOfColumns(); + var rows = data.getNumberOfRows(); + + // Read column labels + var labels = []; + for (var i = 0; i < cols; i++) { + labels.push(data.getColumnLabel(i)); + } + labels.shift(); // a "date" parameter is assumed. + this.labels_ = labels; + // regenerate automatic colors. + this.setColors_(this.attrs_); + this.renderOptions_.colorScheme = this.colors_; + MochiKit.Base.update(this.plotter_.options, this.renderOptions_); + MochiKit.Base.update(this.layoutOptions_, this.attrs_); + + // Assume column 1 is a date type for now. + if (data.getColumnType(0) != 'date') { + alert("only date type is support for column 1 of DataTable input."); + return null; + } + + var ret = []; + for (var i = 0; i < rows; i++) { + var row = []; + row.push(data.getValue(i, 0).getTime()); + for (var j = 1; j < cols; j++) { + row.push(data.getValue(i, j)); + } + ret.push(row); + } + return ret; +} + +/** * Get the CSV data. If it's in a function, call that function. If it's in a * file, do an XMLHttpRequest to get it. * @private @@ -1002,6 +1111,11 @@ DateGraph.prototype.start_ = function() { if (typeof this.file_ == 'function') { // Stubbed out to allow this to run off a filesystem this.loadedEvent_(this.file_()); + } else if (typeof this.file_ == 'object' && + typeof this.file_.getColumnRange == 'function') { + // must be a DataTable from gviz. + this.rawData_ = this.parseDataTable_(this.file_); + this.drawGraph_(this.rawData_); } else { var req = new XMLHttpRequest(); var caller = this; @@ -1070,3 +1184,17 @@ DateGraph.prototype.adjustRoll = function(length) { this.rollPeriod_ = length; this.drawGraph_(this.rawData_); }; + + +/** + * A wrapper around DateGraph that implements the gviz API. + * @param {Object} container The DOM object the visualization should live in. + */ +DateGraph.GVizChart = function(container) { + this.container = container; +} + +DateGraph.GVizChart.prototype.draw = function(data, options) { + this.container.innerHTML = ''; + this.date_graph = new DateGraph(this.container, data, null, options || {}); +}