From: dsc Date: Thu, 29 Mar 2012 19:11:13 +0000 (-0700) Subject: Patches Dygraphs with structural markup for the legend so it can be styled to be... X-Git-Url: http://git.lttlst.com:3516/?a=commitdiff_plain;h=8644f425d29644ee68756dae7f29326b6e4ab4da;p=kraken-ui.git Patches Dygraphs with structural markup for the legend so it can be styled to be readable. See https://github.com/dsc/dygraphs/commit/8f19f30b77988ce085976e9a0cc17b50acbcd102 --- diff --git a/lib/graph/graph-edit-view.co b/lib/graph/graph-edit-view.co index 734bc03..7957699 100644 --- a/lib/graph/graph-edit-view.co +++ b/lib/graph/graph-edit-view.co @@ -27,6 +27,7 @@ GraphEditView = exports.GraphEditView = BaseView.extend do # {{{ ]> __bind__ : <[ render renderAll resizeViewport + numberFormatter numberFormatterHTML onReady onSync onModelChange onScaffoldChange onFirstClickRenderOptionsTab ]> @@ -190,14 +191,14 @@ GraphEditView = exports.GraphEditView = BaseView.extend do # {{{ options = @chartOptions() #import size options import do labelsDiv : @$el.find '.graph-label' .0 - valueFormatter : @numberFormatter + valueFormatter : @numberFormatterHTML axes: x: axisLabelFormatter : @axisDateFormatter valueFormatter : @dateFormatter y: axisLabelFormatter : @axisFormatter @numberFormatter - valueFormatter : @numberFormatter + valueFormatter : @numberFormatterHTML # console.log "#this.render!", dataset _.dump options, 'options' @@ -253,16 +254,28 @@ GraphEditView = exports.GraphEditView = BaseView.extend do # {{{ dateFormatter: (n, opts, g) -> moment(n).format 'DD MMM YYYY' - numberFormatter: (n, opts, g) -> - digits = opts('digitsAfterDecimal') ? 2 + _numberFormatter: (n, digits=2) -> for [suffix, d] of [['B', 1000000000], ['M', 1000000], ['K', 1000], ['', NaN]] if n >= d n = n / d break - s = n.toFixed(digits) + suffix + s = n.toFixed(digits) parts = s.split '.' - parts[0] = _.rchop parts[0], 3 .join ',' - parts.join '.' + whole = _.rchop parts[0], 3 .join ',' + fraction = '.' + parts.slice(1).join '.' + { n, digits, whole, fraction, suffix } + + numberFormatter: (n, opts, g) -> + digits = opts('digitsAfterDecimal') ? 2 + { whole, fraction, suffix } = @_numberFormatter n, digits + "#whole#fraction#suffix" + + numberFormatterHTML: (n, opts, g) -> + digits = opts('digitsAfterDecimal') ? 2 + { whole, fraction, suffix } = @_numberFormatter n, digits + """ + #whole#fraction#suffix + """ ### }}} ### Event Handlers {{{ diff --git a/static/vendor/dygraph-1.2dev.js b/static/vendor/dygraph-1.2dev.js index 547e519..4b61bdb 100644 --- a/static/vendor/dygraph-1.2dev.js +++ b/static/vendor/dygraph-1.2dev.js @@ -215,6 +215,7 @@ DygraphLayout.prototype._evaluateLineCharts = function() { this.setPointsLengths = []; this.setPointsOffsets = []; + var connectSeparated = this.attr_('connectSeparatedPoints'); for (var setIdx = 0; setIdx < this.datasets.length; ++setIdx) { var dataset = this.datasets[setIdx]; var setName = this.setNames[setIdx]; @@ -241,6 +242,9 @@ DygraphLayout.prototype._evaluateLineCharts = function() { yval: yValue, name: setName }; + if (connectSeparated && item[1] === null) { + point.yval = null; + } this.points.push(point); setPointsLength += 1; } @@ -567,6 +571,7 @@ DygraphCanvasRenderer.prototype.render = function() { ctx.closePath(); ctx.stroke(); } + ctx.restore(); } if (this.attr_('drawXGrid')) { @@ -583,6 +588,7 @@ DygraphCanvasRenderer.prototype.render = function() { ctx.closePath(); ctx.stroke(); } + ctx.restore(); } // Do the ordinary rendering, as before @@ -965,7 +971,8 @@ DygraphCanvasRenderer.prototype._renderAnnotations = function() { var points = this.layout.annotated_points; for (var i = 0; i < points.length; i++) { var p = points[i]; - if (p.canvasx < this.area.x || p.canvasx > this.area.x + this.area.w) { + if (p.canvasx < this.area.x || p.canvasx > this.area.x + this.area.w || + p.canvasy < this.area.y || p.canvasy > this.area.y + this.area.h) { continue; } @@ -1039,6 +1046,128 @@ DygraphCanvasRenderer.prototype._renderAnnotations = function() { } }; +DygraphCanvasRenderer.makeNextPointStep_ = function(connect, points, end) { + if (connect) { + return function(j) { + while (++j < end) { + if (!(points[j].yval === null)) break; + } + return j; + } + } else { + return function(j) { return j + 1 }; + } +}; + +DygraphCanvasRenderer.prototype._drawStyledLine = function( + ctx, i, setName, color, strokeWidth, strokePattern, drawPoints, + drawPointCallback, pointSize) { + var isNullOrNaN = function(x) { + return (x === null || isNaN(x)); + }; + + var stepPlot = this.attr_("stepPlot"); + var firstIndexInSet = this.layout.setPointsOffsets[i]; + var setLength = this.layout.setPointsLengths[i]; + var afterLastIndexInSet = firstIndexInSet + setLength; + var points = this.layout.points; + var prevX = null; + var prevY = null; + var pointsOnLine = []; // Array of [canvasx, canvasy] pairs. + if (!Dygraph.isArrayLike(strokePattern)) { + strokePattern = null; + } + + var point; + var next = DygraphCanvasRenderer.makeNextPointStep_( + this.attr_('connectSeparatedPoints'), points, afterLastIndexInSet); + ctx.save(); + for (var j = firstIndexInSet; j < afterLastIndexInSet; j = next(j)) { + point = points[j]; + if (isNullOrNaN(point.canvasy)) { + if (stepPlot && prevX !== null) { + // Draw a horizontal line to the start of the missing data + ctx.beginPath(); + ctx.strokeStyle = color; + ctx.lineWidth = this.attr_('strokeWidth'); + this._dashedLine(ctx, prevX, prevY, point.canvasx, prevY, strokePattern); + ctx.stroke(); + } + // this will make us move to the next point, not draw a line to it. + prevX = prevY = null; + } else { + // A point is "isolated" if it is non-null but both the previous + // and next points are null. + var isIsolated = (!prevX && (j == points.length - 1 || + isNullOrNaN(points[j+1].canvasy))); + if (prevX === null) { + prevX = point.canvasx; + prevY = point.canvasy; + } else { + // Skip over points that will be drawn in the same pixel. + if (Math.round(prevX) == Math.round(point.canvasx) && + Math.round(prevY) == Math.round(point.canvasy)) { + continue; + } + // TODO(antrob): skip over points that lie on a line that is already + // going to be drawn. There is no need to have more than 2 + // consecutive points that are collinear. + if (strokeWidth) { + ctx.beginPath(); + ctx.strokeStyle = color; + ctx.lineWidth = strokeWidth; + if (stepPlot) { + this._dashedLine(ctx, prevX, prevY, point.canvasx, prevY, strokePattern); + prevX = point.canvasx; + } + this._dashedLine(ctx, prevX, prevY, point.canvasx, point.canvasy, strokePattern); + prevX = point.canvasx; + prevY = point.canvasy; + ctx.stroke(); + } + } + + if (drawPoints || isIsolated) { + pointsOnLine.push([point.canvasx, point.canvasy]); + } + } + } + for (var idx = 0; idx < pointsOnLine.length; idx++) { + var cb = pointsOnLine[idx]; + ctx.save(); + drawPointCallback( + this.dygraph_, setName, ctx, cb[0], cb[1], color, pointSize); + ctx.restore(); + } + ctx.restore(); +}; + +DygraphCanvasRenderer.prototype._drawLine = function(ctx, i) { + var setNames = this.layout.setNames; + var setName = setNames[i]; + + var strokeWidth = this.dygraph_.attr_("strokeWidth", setName); + var borderWidth = this.dygraph_.attr_("strokeBorderWidth", setName); + var drawPointCallback = this.dygraph_.attr_("drawPointCallback", setName) || + Dygraph.Circles.DEFAULT; + if (borderWidth && strokeWidth) { + this._drawStyledLine(ctx, i, setName, + this.dygraph_.attr_("strokeBorderColor", setName), + strokeWidth + 2 * borderWidth, + this.dygraph_.attr_("strokePattern", setName), + this.dygraph_.attr_("drawPoints", setName), + drawPointCallback, + this.dygraph_.attr_("pointSize", setName)); + } + + this._drawStyledLine(ctx, i, setName, + this.colors[setName], + strokeWidth, + this.dygraph_.attr_("strokePattern", setName), + this.dygraph_.attr_("drawPoints", setName), + drawPointCallback, + this.dygraph_.attr_("pointSize", setName)); +}; /** * Actually draw the lines chart, including error bars. @@ -1046,12 +1175,8 @@ DygraphCanvasRenderer.prototype._renderAnnotations = function() { * @private */ DygraphCanvasRenderer.prototype._renderLineChart = function() { - var isNullOrNaN = function(x) { - return (x === null || isNaN(x)); - }; - // TODO(danvk): use this.attr_ for many of these. - var context = this.elementContext; + var ctx = this.elementContext; var fillAlpha = this.attr_('fillAlpha'); var errorBars = this.attr_("errorBars") || this.attr_("customBars"); var fillGraph = this.attr_("fillGraph"); @@ -1079,8 +1204,8 @@ DygraphCanvasRenderer.prototype._renderLineChart = function() { } // create paths - var ctx = context; if (errorBars) { + ctx.save(); if (fillGraph) { this.dygraph_.warn("Can't use fillGraph option with error bars"); } @@ -1090,8 +1215,15 @@ DygraphCanvasRenderer.prototype._renderLineChart = function() { axis = this.dygraph_.axisPropertiesForSeries(setName); color = this.colors[setName]; + var firstIndexInSet = this.layout.setPointsOffsets[i]; + var setLength = this.layout.setPointsLengths[i]; + var afterLastIndexInSet = firstIndexInSet + setLength; + + var next = DygraphCanvasRenderer.makeNextPointStep_( + this.attr_('connectSeparatedPoints'), points, + afterLastIndexInSet); + // setup graphics context - ctx.save(); prevX = NaN; prevY = NaN; prevYs = [-1, -1]; @@ -1102,9 +1234,9 @@ DygraphCanvasRenderer.prototype._renderLineChart = function() { fillAlpha + ')'; ctx.fillStyle = err_color; ctx.beginPath(); - for (j = 0; j < pointsLength; j++) { + for (j = firstIndexInSet; j < afterLastIndexInSet; j = next(j)) { point = points[j]; - if (point.name == setName) { + if (point.name == setName) { // TODO(klausw): this is always true if (!Dygraph.isOK(point.y)) { prevX = NaN; continue; @@ -1140,7 +1272,9 @@ DygraphCanvasRenderer.prototype._renderLineChart = function() { } ctx.fill(); } + ctx.restore(); } else if (fillGraph) { + ctx.save(); var baseline = []; // for stacked graphs: baseline for filling // process sets in reverse order (needed for stacked graphs) @@ -1152,9 +1286,15 @@ DygraphCanvasRenderer.prototype._renderLineChart = function() { if (axisY < 0.0) axisY = 0.0; else if (axisY > 1.0) axisY = 1.0; axisY = this.area.h * axisY + this.area.y; + var firstIndexInSet = this.layout.setPointsOffsets[i]; + var setLength = this.layout.setPointsLengths[i]; + var afterLastIndexInSet = firstIndexInSet + setLength; + + var next = DygraphCanvasRenderer.makeNextPointStep_( + this.attr_('connectSeparatedPoints'), points, + afterLastIndexInSet); // setup graphics context - ctx.save(); prevX = NaN; prevYs = [-1, -1]; yscale = axis.yscale; @@ -1164,9 +1304,9 @@ DygraphCanvasRenderer.prototype._renderLineChart = function() { fillAlpha + ')'; ctx.fillStyle = err_color; ctx.beginPath(); - for (j = 0; j < pointsLength; j++) { + for (j = firstIndexInSet; j < afterLastIndexInSet; j = next(j)) { point = points[j]; - if (point.name == setName) { + if (point.name == setName) { // TODO(klausw): this is always true if (!Dygraph.isOK(point.y)) { prevX = NaN; continue; @@ -1196,87 +1336,13 @@ DygraphCanvasRenderer.prototype._renderLineChart = function() { } ctx.fill(); } + ctx.restore(); } // Drawing the lines. - var firstIndexInSet = 0; - var afterLastIndexInSet = 0; - var setLength = 0; for (i = 0; i < setCount; i += 1) { - firstIndexInSet = this.layout.setPointsOffsets[i]; - setLength = this.layout.setPointsLengths[i]; - afterLastIndexInSet = firstIndexInSet + setLength; - setName = setNames[i]; - color = this.colors[setName]; - var strokeWidth = this.dygraph_.attr_("strokeWidth", setName); - - // setup graphics context - context.save(); - var pointSize = this.dygraph_.attr_("pointSize", setName); - prevX = null; - prevY = null; - var drawPoints = this.dygraph_.attr_("drawPoints", setName); - var strokePattern = this.dygraph_.attr_("strokePattern", setName); - if (!Dygraph.isArrayLike(strokePattern)) { - strokePattern = null; - } - for (j = firstIndexInSet; j < afterLastIndexInSet; j++) { - point = points[j]; - if (isNullOrNaN(point.canvasy)) { - if (stepPlot && prevX !== null) { - // Draw a horizontal line to the start of the missing data - ctx.beginPath(); - ctx.strokeStyle = color; - ctx.lineWidth = this.attr_('strokeWidth'); - this._dashedLine(ctx, prevX, prevY, point.canvasx, prevY, strokePattern); - ctx.stroke(); - } - // this will make us move to the next point, not draw a line to it. - prevX = prevY = null; - } else { - // A point is "isolated" if it is non-null but both the previous - // and next points are null. - var isIsolated = (!prevX && (j == points.length - 1 || - isNullOrNaN(points[j+1].canvasy))); - if (prevX === null) { - prevX = point.canvasx; - prevY = point.canvasy; - } else { - // Skip over points that will be drawn in the same pixel. - if (Math.round(prevX) == Math.round(point.canvasx) && - Math.round(prevY) == Math.round(point.canvasy)) { - continue; - } - // TODO(antrob): skip over points that lie on a line that is already - // going to be drawn. There is no need to have more than 2 - // consecutive points that are collinear. - if (strokeWidth) { - ctx.beginPath(); - ctx.strokeStyle = color; - ctx.lineWidth = strokeWidth; - if (stepPlot) { - this._dashedLine(ctx, prevX, prevY, point.canvasx, prevY, strokePattern); - prevX = point.canvasx; - } - this._dashedLine(ctx, prevX, prevY, point.canvasx, point.canvasy, strokePattern); - prevX = point.canvasx; - prevY = point.canvasy; - ctx.stroke(); - } - } - - if (drawPoints || isIsolated) { - ctx.beginPath(); - ctx.fillStyle = color; - ctx.arc(point.canvasx, point.canvasy, pointSize, - 0, 2 * Math.PI, false); - ctx.fill(); - } - } - } + this._drawLine(ctx, i); } - - context.restore(); }; /** @@ -1447,7 +1513,7 @@ var Dygraph = function(div, data, opts) { }; Dygraph.NAME = "Dygraph"; -Dygraph.VERSION = "1.2dev"; +Dygraph.VERSION = "1.2"; Dygraph.__repr__ = function() { return "[" + this.NAME + " " + this.VERSION + "]"; }; @@ -1557,6 +1623,8 @@ Dygraph.dateAxisFormatter = function(date, granularity) { // Default attribute values. Dygraph.DEFAULT_ATTRS = { highlightCircleSize: 3, + highlightSeriesOpts: null, + highlightSeriesBackgroundAlpha: 0.5, labelsDivWidth: 250, labelsDivStyles: { @@ -1573,6 +1641,8 @@ Dygraph.DEFAULT_ATTRS = { sigFigs: null, strokeWidth: 1.0, + strokeBorderWidth: 0, + strokeBorderColor: "white", axisTickSize: 3, axisLabelFontSize: 14, @@ -1769,6 +1839,7 @@ Dygraph.prototype.__init__ = function(div, file, attrs) { this.boundaryIds_ = []; this.setIndexByName_ = {}; + this.datasetIndex_ = []; // Create the containing DIV and other interactive elements this.createInterface_(); @@ -1813,18 +1884,31 @@ Dygraph.prototype.toString = function() { * @return { ... } The value of the option. */ Dygraph.prototype.attr_ = function(name, seriesName) { - if (this.user_attrs_ !== null && seriesName && - typeof(this.user_attrs_[seriesName]) != 'undefined' && - this.user_attrs_[seriesName] !== null && - typeof(this.user_attrs_[seriesName][name]) != 'undefined') { - return this.user_attrs_[seriesName][name]; - } else if (this.user_attrs_ !== null && typeof(this.user_attrs_[name]) != 'undefined') { - return this.user_attrs_[name]; - } else if (this.attrs_ !== null && typeof(this.attrs_[name]) != 'undefined') { - return this.attrs_[name]; - } else { - return null; + + var sources = []; + sources.push(this.attrs_); + if (this.user_attrs_) { + sources.push(this.user_attrs_); + if (seriesName) { + if (this.user_attrs_.hasOwnProperty(seriesName)) { + sources.push(this.user_attrs_[seriesName]); + } + if (seriesName === this.highlightSet_ && + this.user_attrs_.hasOwnProperty('highlightSeriesOpts')) { + sources.push(this.user_attrs_['highlightSeriesOpts']); + } + } } + + var ret = null; + for (var i = sources.length - 1; i >= 0; --i) { + var source = sources[i]; + if (source.hasOwnProperty(name)) { + ret = source[name]; + break; + } + } + return ret; }; /** @@ -2194,12 +2278,12 @@ Dygraph.prototype.createInterface_ = function() { var dygraph = this; this.mouseMoveHandler = function(e) { - dygraph.mouseMove_(e); + dygraph.mouseMove_(e); }; Dygraph.addEvent(this.mouseEventElement_, 'mousemove', this.mouseMoveHandler); this.mouseOutHandler = function(e) { - dygraph.mouseOut_(e); + dygraph.mouseOut_(e); }; Dygraph.addEvent(this.mouseEventElement_, 'mouseout', this.mouseOutHandler); @@ -2231,6 +2315,7 @@ Dygraph.prototype.destroy = function() { // remove mouse event handlers Dygraph.removeEvent(this.mouseEventElement_, 'mouseout', this.mouseOutHandler); Dygraph.removeEvent(this.mouseEventElement_, 'mousemove', this.mouseMoveHandler); + Dygraph.removeEvent(this.mouseEventElement_, 'mousemove', this.mouseUpHandler_); removeRecursive(this.maindiv_); var nullOut = function(obj) { @@ -2357,6 +2442,7 @@ Dygraph.prototype.createStatusMessage_ = function() { "top": "0px", "left": (this.width_ - divWidth - 2) + "px", "background": "white", + "lineHeight": "normal", "textAlign": "left", "overflow": "hidden"}; Dygraph.update(messagestyle, this.attr_('labelsDivStyles')); @@ -2364,7 +2450,11 @@ Dygraph.prototype.createStatusMessage_ = function() { div.className = "dygraph-legend"; for (var name in messagestyle) { if (messagestyle.hasOwnProperty(name)) { - div.style[name] = messagestyle[name]; + try { + div.style[name] = messagestyle[name]; + } catch (e) { + this.warn("You are using unsupported css properties for your browser in labelsDivStyles"); + } } } this.graphDiv.appendChild(div); @@ -2459,6 +2549,7 @@ Dygraph.prototype.createDragInterface_ = function() { prevEndX: null, // pixel coordinates prevEndY: null, // pixel coordinates prevDragDirection: null, + cancelNextDblclick: false, // see comment in dygraph-interaction-model.js // The value on the left side of the graph when a pan operation starts. initialLeftmostDate: null, @@ -2495,6 +2586,7 @@ Dygraph.prototype.createDragInterface_ = function() { context.py = Dygraph.findPosY(g.canvas_); context.dragStartX = g.dragGetX_(event, context); context.dragStartY = g.dragGetY_(event, context); + context.cancelNextDblclick = false; } }; @@ -2518,7 +2610,7 @@ Dygraph.prototype.createDragInterface_ = function() { // If the user releases the mouse button during a drag, but not over the // canvas, then it doesn't count as a zooming action. - Dygraph.addEvent(document, 'mouseup', function(event) { + this.mouseUpHandler_ = function(event) { if (context.isZooming || context.isPanning) { context.isZooming = false; context.dragStartX = null; @@ -2534,7 +2626,9 @@ Dygraph.prototype.createDragInterface_ = function() { delete self.axes_[i].dragValueRange; } } - }); + }; + + Dygraph.addEvent(document, 'mouseup', this.mouseUpHandler_); }; /** @@ -2822,74 +2916,197 @@ Dygraph.prototype.doAnimatedZoom = function(oldXRange, newXRange, oldYRanges, ne }; /** - * When the mouse moves in the canvas, display information about a nearby data - * point and draw dots over those points in the data series. This function - * takes care of cleanup of previously-drawn dots. - * @param {Object} event The mousemove event from the browser. - * @private + * Get the current graph's area object. + * + * Returns: {x, y, w, h} */ -Dygraph.prototype.mouseMove_ = function(event) { - // This prevents JS errors when mousing over the canvas before data loads. - var points = this.layout_.points; - if (points === undefined) return; +Dygraph.prototype.getArea = function() { + return this.plotter_.area; +}; +/** + * Convert a mouse event to DOM coordinates relative to the graph origin. + * + * Returns a two-element array: [X, Y]. + */ +Dygraph.prototype.eventToDomCoords = function(event) { var canvasx = Dygraph.pageX(event) - Dygraph.findPosX(this.mouseEventElement_); + var canvasy = Dygraph.pageY(event) - Dygraph.findPosY(this.mouseEventElement_); + return [canvasx, canvasy]; +}; - var lastx = -1; - var i; - - // Loop through all the points and find the date nearest to our current - // location. - var minDist = 1e+100; +/** + * Given a canvas X coordinate, find the closest row. + * @param {Number} domX graph-relative DOM X coordinate + * Returns: row number, integer + * @private + */ +Dygraph.prototype.findClosestRow = function(domX) { + var minDistX = Infinity; var idx = -1; - for (i = 0; i < points.length; i++) { + var points = this.layout_.points; + var l = points.length; + for (var i = 0; i < l; i++) { var point = points[i]; - if (point === null) continue; - var dist = Math.abs(point.canvasx - canvasx); - if (dist > minDist) continue; - minDist = dist; - idx = i; + if (!Dygraph.isValidPoint(point, true)) continue; + var dist = Math.abs(point.canvasx - domX); + if (dist < minDistX) { + minDistX = dist; + idx = i; + } } - if (idx >= 0) lastx = points[idx].xval; + return this.idxToRow_(idx); +}; - // Extract the points we've selected - this.selPoints_ = []; - var l = points.length; - if (!this.attr_("stackedGraph")) { - for (i = 0; i < l; i++) { - if (points[i].xval == lastx) { - this.selPoints_.push(points[i]); +/** + * Given canvas X,Y coordinates, find the closest point. + * + * This finds the individual data point across all visible series + * that's closest to the supplied DOM coordinates using the standard + * Euclidean X,Y distance. + * + * @param {Number} domX graph-relative DOM X coordinate + * @param {Number} domY graph-relative DOM Y coordinate + * Returns: {row, seriesName, point} + * @private + */ +Dygraph.prototype.findClosestPoint = function(domX, domY) { + var minDist = Infinity; + var idx = -1; + var points = this.layout_.points; + var dist, dx, dy, point, closestPoint, closestSeries; + for (var setIdx = 0; setIdx < this.layout_.datasets.length; ++setIdx) { + var first = this.layout_.setPointsOffsets[setIdx]; + var len = this.layout_.setPointsLengths[setIdx]; + for (var i = 0; i < len; ++i) { + var point = points[first + i]; + if (!Dygraph.isValidPoint(point)) continue; + dx = point.canvasx - domX; + dy = point.canvasy - domY; + dist = dx * dx + dy * dy; + if (dist < minDist) { + minDist = dist; + closestPoint = point; + closestSeries = setIdx; + idx = i; } } - } else { - // Need to 'unstack' points starting from the bottom - var cumulative_sum = 0; - for (i = l - 1; i >= 0; i--) { - if (points[i].xval == lastx) { - var p = {}; // Clone the point since we modify it - for (var k in points[i]) { - p[k] = points[i][k]; + } + var name = this.layout_.setNames[closestSeries]; + return { + row: idx + this.getLeftBoundary_(), + seriesName: name, + point: closestPoint + }; +}; + +/** + * Given canvas X,Y coordinates, find the touched area in a stacked graph. + * + * This first finds the X data point closest to the supplied DOM X coordinate, + * then finds the series which puts the Y coordinate on top of its filled area, + * using linear interpolation between adjacent point pairs. + * + * @param {Number} domX graph-relative DOM X coordinate + * @param {Number} domY graph-relative DOM Y coordinate + * Returns: {row, seriesName, point} + * @private + */ +Dygraph.prototype.findStackedPoint = function(domX, domY) { + var row = this.findClosestRow(domX); + var boundary = this.getLeftBoundary_(); + var rowIdx = row - boundary; + var points = this.layout_.points; + var closestPoint, closestSeries; + for (var setIdx = 0; setIdx < this.layout_.datasets.length; ++setIdx) { + var first = this.layout_.setPointsOffsets[setIdx]; + var len = this.layout_.setPointsLengths[setIdx]; + if (rowIdx >= len) continue; + var p1 = points[first + rowIdx]; + if (!Dygraph.isValidPoint(p1)) continue; + var py = p1.canvasy; + if (domX > p1.canvasx && rowIdx + 1 < len) { + // interpolate series Y value using next point + var p2 = points[first + rowIdx + 1]; + if (Dygraph.isValidPoint(p2)) { + var dx = p2.canvasx - p1.canvasx; + if (dx > 0) { + var r = (domX - p1.canvasx) / dx; + py += r * (p2.canvasy - p1.canvasy); + } + } + } else if (domX < p1.canvasx && rowIdx > 0) { + // interpolate series Y value using previous point + var p0 = points[first + rowIdx - 1]; + if (Dygraph.isValidPoint(p0)) { + var dx = p1.canvasx - p0.canvasx; + if (dx > 0) { + var r = (p1.canvasx - domX) / dx; + py += r * (p0.canvasy - p1.canvasy); } - p.yval -= cumulative_sum; - cumulative_sum += p.yval; - this.selPoints_.push(p); } } - this.selPoints_.reverse(); + // Stop if the point (domX, py) is above this series' upper edge + if (setIdx == 0 || py < domY) { + closestPoint = p1; + closestSeries = setIdx; + } } + var name = this.layout_.setNames[closestSeries]; + return { + row: row, + seriesName: name, + point: closestPoint + }; +}; - if (this.attr_("highlightCallback")) { - var px = this.lastx_; - if (px !== null && lastx != px) { - // only fire if the selected point has changed. - this.attr_("highlightCallback")(event, lastx, this.selPoints_, this.idxToRow_(idx)); +/** + * When the mouse moves in the canvas, display information about a nearby data + * point and draw dots over those points in the data series. This function + * takes care of cleanup of previously-drawn dots. + * @param {Object} event The mousemove event from the browser. + * @private + */ +Dygraph.prototype.mouseMove_ = function(event) { + // This prevents JS errors when mousing over the canvas before data loads. + var points = this.layout_.points; + if (points === undefined) return; + + var canvasCoords = this.eventToDomCoords(event); + var canvasx = canvasCoords[0]; + var canvasy = canvasCoords[1]; + + var highlightSeriesOpts = this.attr_("highlightSeriesOpts"); + var selectionChanged = false; + if (highlightSeriesOpts) { + var closest; + if (this.attr_("stackedGraph")) { + closest = this.findStackedPoint(canvasx, canvasy); + } else { + closest = this.findClosestPoint(canvasx, canvasy); } + selectionChanged = this.setSelection(closest.row, closest.seriesName); + } else { + var idx = this.findClosestRow(canvasx); + selectionChanged = this.setSelection(idx); } - // Save last x position for callbacks. - this.lastx_ = lastx; + var callback = this.attr_("highlightCallback"); + if (callback && selectionChanged) { + callback(event, this.lastx_, this.selPoints_, this.lastRow_, this.highlightSet_); + } +}; - this.updateSelection_(); +/** + * Fetch left offset from first defined boundaryIds record (see bug #236). + */ +Dygraph.prototype.getLeftBoundary_ = function() { + for (var i = 0; i < this.boundaryIds_.length; i++) { + if (this.boundaryIds_[i] !== undefined) { + return this.boundaryIds_[i][0]; + } + } + return 0; }; /** @@ -2901,19 +3118,11 @@ Dygraph.prototype.mouseMove_ = function(event) { Dygraph.prototype.idxToRow_ = function(idx) { if (idx < 0) return -1; - // make sure that you get the boundaryIds record which is also defined (see bug #236) - var boundaryIdx = -1; - for (var i = 0; i < this.boundaryIds_.length; i++) { - if (this.boundaryIds_[i] !== undefined) { - boundaryIdx = i; - break; - } - } - if (boundaryIdx < 0) return -1; + var boundary = this.getLeftBoundary_(); for (var setIdx = 0; setIdx < this.layout_.datasets.length; ++setIdx) { var set = this.layout_.datasets[setIdx]; if (idx < set.length) { - return this.boundaryIds_[boundaryIdx][0] + idx; + return boundary + idx; } idx -= set.length; } @@ -3020,7 +3229,7 @@ Dygraph.prototype.generateLegendHTML_ = function(x, sel_points, oneEmWidth) { if (html !== '') html += (sepLines ? '
' : ' '); strokePattern = this.attr_("strokePattern", labels[i]); dash = this.generateLegendDashHTML_(strokePattern, c, oneEmWidth); - html += "" + dash + + html += "" + dash + " " + labels[i] + ""; } return html; @@ -3048,9 +3257,10 @@ Dygraph.prototype.generateLegendHTML_ = function(x, sel_points, oneEmWidth) { c = this.plotter_.colors[pt.name]; var yval = fmtFunc(pt.yval, yOptView, pt.name, this); + var cls = (pt.name == this.highlightSet_) ? " class='highlight'" : ""; // TODO(danvk): use a template string here and make it an attribute. - html += " " + pt.name + - ":" + yval; + html += "" + " " + pt.name + + ":" + yval + ""; } return html; }; @@ -3065,6 +3275,8 @@ Dygraph.prototype.generateLegendHTML_ = function(x, sel_points, oneEmWidth) { */ Dygraph.prototype.setLegendHTML_ = function(x, sel_points) { var labelsDiv = this.attr_("labelsDiv"); + if (!labelsDiv) return; + var sizeSpan = document.createElement('span'); // Calculates the width of 1em in pixels for the legend. sizeSpan.setAttribute('style', 'margin: 0; padding: 0 0 0 1em; border: 0;'); @@ -3082,16 +3294,68 @@ Dygraph.prototype.setLegendHTML_ = function(x, sel_points) { } }; +Dygraph.prototype.animateSelection_ = function(direction) { + var totalSteps = 10; + var millis = 30; + if (this.fadeLevel === undefined) this.fadeLevel = 0; + if (this.animateId === undefined) this.animateId = 0; + var start = this.fadeLevel; + var steps = direction < 0 ? start : totalSteps - start; + if (steps <= 0) { + if (this.fadeLevel) { + this.updateSelection_(1.0); + } + return; + } + + var thisId = ++this.animateId; + var that = this; + Dygraph.repeatAndCleanup( + function(n) { + // ignore simultaneous animations + if (that.animateId != thisId) return; + + that.fadeLevel += direction; + if (that.fadeLevel === 0) { + that.clearSelection(); + } else { + that.updateSelection_(that.fadeLevel / totalSteps); + } + }, + steps, millis, function() {}); +}; + /** * Draw dots over the selectied points in the data series. This function * takes care of cleanup of previously-drawn dots. * @private */ -Dygraph.prototype.updateSelection_ = function() { +Dygraph.prototype.updateSelection_ = function(opt_animFraction) { // Clear the previously drawn vertical, if there is one var i; var ctx = this.canvas_ctx_; - if (this.previousVerticalX_ >= 0) { + if (this.attr_('highlightSeriesOpts')) { + ctx.clearRect(0, 0, this.width_, this.height_); + var alpha = 1.0 - this.attr_('highlightSeriesBackgroundAlpha'); + if (alpha) { + // Activating background fade includes an animation effect for a gradual + // fade. TODO(klausw): make this independently configurable if it causes + // issues? Use a shared preference to control animations? + var animateBackgroundFade = true; + if (animateBackgroundFade) { + if (opt_animFraction === undefined) { + // start a new animation + this.animateSelection_(1); + return; + } + alpha *= opt_animFraction; + } + ctx.fillStyle = 'rgba(255,255,255,' + alpha + ')'; + ctx.fillRect(0, 0, this.width_, this.height_); + } + var setIdx = this.datasetIndexFromSetName_(this.highlightSet_); + this.plotter_._drawLine(ctx, setIdx); + } else if (this.previousVerticalX_ >= 0) { // Determine the maximum highlight circle size. var maxCircleSize = 0; var labels = this.attr_('labels'); @@ -3122,10 +3386,16 @@ Dygraph.prototype.updateSelection_ = function() { if (!Dygraph.isOK(pt.canvasy)) continue; var circleSize = this.attr_('highlightCircleSize', pt.name); - ctx.beginPath(); - ctx.fillStyle = this.plotter_.colors[pt.name]; - ctx.arc(canvasx, pt.canvasy, circleSize, 0, 2 * Math.PI, false); - ctx.fill(); + var callback = this.attr_("drawHighlightPointCallback", pt.name); + var color = this.plotter_.colors[pt.name]; + if (!callback) { + callback = Dygraph.Circles.DEFAULT; + } + ctx.lineWidth = this.attr_('strokeWidth', pt.name); + ctx.strokeStyle = color; + ctx.fillStyle = color; + callback(this.g, pt.name, ctx, canvasx, pt.canvasy, + color, circleSize); } ctx.restore(); @@ -3139,17 +3409,22 @@ Dygraph.prototype.updateSelection_ = function() { * using getSelection(). * @param { Integer } row number that should be highlighted (i.e. appear with * hover dots on the chart). Set to false to clear any selection. + * @param { seriesName } optional series name to highlight that series with the + * the highlightSeriesOpts setting. */ -Dygraph.prototype.setSelection = function(row) { +Dygraph.prototype.setSelection = function(row, opt_seriesName) { // Extract the points we've selected this.selPoints_ = []; var pos = 0; if (row !== false) { - row = row - this.boundaryIds_[0][0]; + row -= this.getLeftBoundary_(); } + var changed = false; if (row !== false && row >= 0) { + if (row != this.lastRow_) changed = true; + this.lastRow_ = row; for (var setIdx = 0; setIdx < this.layout_.datasets.length; ++setIdx) { var set = this.layout_.datasets[setIdx]; if (row < set.length) { @@ -3159,19 +3434,30 @@ Dygraph.prototype.setSelection = function(row) { point = this.layout_.unstackPointAtIndex(pos+row); } - this.selPoints_.push(point); + if (!(point.yval === null)) this.selPoints_.push(point); } pos += set.length; } + } else { + if (this.lastRow_ >= 0) changed = true; + this.lastRow_ = -1; } if (this.selPoints_.length) { this.lastx_ = this.selPoints_[0].xval; - this.updateSelection_(); } else { - this.clearSelection(); + this.lastx_ = -1; } + if (opt_seriesName !== undefined) { + if (this.highlightSet_ !== opt_seriesName) changed = true; + this.highlightSet_ = opt_seriesName; + } + + if (changed) { + this.updateSelection_(undefined); + } + return changed; }; /** @@ -3195,10 +3481,17 @@ Dygraph.prototype.mouseOut_ = function(event) { */ Dygraph.prototype.clearSelection = function() { // Get rid of the overlay data + if (this.fadeLevel) { + this.animateSelection_(-1); + return; + } this.canvas_ctx_.clearRect(0, 0, this.width_, this.height_); + this.fadeLevel = 0; this.setLegendHTML_(); this.selPoints_ = []; this.lastx_ = -1; + this.lastRow_ = -1; + this.highlightSet_ = null; }; /** @@ -3213,12 +3506,16 @@ Dygraph.prototype.getSelection = function() { for (var row=0; row= 0; --k) { + // Use the first nonempty dataset to get X values. + if (!datasets[k]) continue; + for (j = 0; j < datasets[k].length; j++) { + var x = datasets[k][j][0]; + if (isNaN(cumulative_y[x])) { + // Set all Y values to NaN at that X value. + for (i = datasets.length - 1; i >= 0; i--) { + if (!datasets[i]) continue; + datasets[i][j][1] = NaN; + } + } + } + break; + } + } + return [ datasets, extremes, boundaryIds ]; }; @@ -3492,10 +3813,12 @@ Dygraph.prototype.drawGraph_ = function(clearSelection) { if (labels.length > 0) { this.setIndexByName_[labels[0]] = 0; } + var dataIdx = 0; for (var i = 1; i < datasets.length; i++) { this.setIndexByName_[labels[i]] = i; if (!this.visibility()[i - 1]) continue; this.layout_.addDataset(labels[i], datasets[i]); + this.datasetIndex_[i] = dataIdx++; } this.computeYAxisRanges_(extremes); @@ -3818,24 +4141,19 @@ Dygraph.prototype.computeYAxisRanges_ = function(extremes) { * * @private */ -Dygraph.prototype.extractSeries_ = function(rawData, i, logScale, connectSeparatedPoints) { +Dygraph.prototype.extractSeries_ = function(rawData, i, logScale) { var series = []; for (var j = 0; j < rawData.length; j++) { var x = rawData[j][0]; var point = rawData[j][i]; if (logScale) { // On the log scale, points less than zero do not exist. - // This will create a gap in the chart. Note that this ignores - // connectSeparatedPoints. + // This will create a gap in the chart. if (point <= 0) { point = null; } - series.push([x, point]); - } else { - if (point !== null || !connectSeparatedPoints) { - series.push([x, point]); - } } + series.push([x, point]); } return series; }; @@ -4010,7 +4328,7 @@ Dygraph.prototype.detectTypeFromString_ = function(str) { // TODO(danvk): use Dygraph.numberValueFormatter here? /** @private (shut up, jsdoc!) */ this.attrs_.axes.x.valueFormatter = function(x) { return x; }; - this.attrs_.axes.x.ticker = Dygraph.numericTicks; + this.attrs_.axes.x.ticker = Dygraph.numericLinearTicks; this.attrs_.axes.x.axisLabelFormatter = this.attrs_.axes.x.valueFormatter; } }; @@ -4249,7 +4567,7 @@ Dygraph.prototype.parseArray_ = function(data) { /** @private (shut up, jsdoc!) */ this.attrs_.axes.x.valueFormatter = function(x) { return x; }; this.attrs_.axes.x.axisLabelFormatter = Dygraph.numberAxisLabelFormatter; - this.attrs_.axes.x.ticker = Dygraph.numericTicks; + this.attrs_.axes.x.ticker = Dygraph.numericLinearTicks; return data; } }; @@ -4289,7 +4607,7 @@ Dygraph.prototype.parseDataTable_ = function(data) { } else if (indepType == 'number') { this.attrs_.xValueParser = function(x) { return parseFloat(x); }; this.attrs_.axes.x.valueFormatter = function(x) { return x; }; - this.attrs_.axes.x.ticker = Dygraph.numericTicks; + this.attrs_.axes.x.ticker = Dygraph.numericLinearTicks; this.attrs_.axes.x.axisLabelFormatter = this.attrs_.axes.x.valueFormatter; } else { this.error("only 'date', 'datetime' and 'number' types are supported for " + @@ -4681,6 +4999,15 @@ Dygraph.prototype.indexFromSetName = function(name) { }; /** + * Get the internal dataset index given its name. These are numbered starting from 0, + * and only count visible sets. + * @private + */ +Dygraph.prototype.datasetIndexFromSetName_ = function(name) { + return this.datasetIndex_[this.indexFromSetName(name)]; +}; + +/** * @private * Adds a default style for the annotation CSS classes to the document. This is * only executed when annotations are actually used. It is designed to only be @@ -5057,6 +5384,21 @@ Dygraph.isOK = function(x) { }; /** + * @private + * @param { Object } p The point to consider, valid points are {x, y} objects + * @param { Boolean } allowNaNY Treat point with y=NaN as valid + * @return { Boolean } Whether the point has numeric x and y. + */ +Dygraph.isValidPoint = function(p, allowNaNY) { + if (!p) return false; // null or undefined object + if (p.yval === null) return false; // missing point + if (p.x === null || p.x === undefined) return false; + if (p.y === null || p.y === undefined) return false; + if (isNaN(p.x) || (!allowNaNY && isNaN(p.y))) return false; + return true; +}; + +/** * Number formatting function which mimicks the behavior of %g in printf, i.e. * either exponential or fixed format (without trailing 0s) is used depending on * the length of the generated string. The advantage of this format is that @@ -5204,9 +5546,17 @@ Dygraph.dateParser = function(dateStr) { var dateStrSlashed; var d; - // Let the system try the format first. - d = Dygraph.dateStrToMillis(dateStr); - if (d && !isNaN(d)) return d; + // Let the system try the format first, with one caveat: + // YYYY-MM-DD[ HH:MM:SS] is interpreted as UTC by a variety of browsers. + // dygraphs displays dates in local time, so this will result in surprising + // inconsistencies. But if you specify "T" or "Z" (i.e. YYYY-MM-DDTHH:MM:SS), + // then you probably know what you're doing, so we'll let you go ahead. + // Issue: http://code.google.com/p/dygraphs/issues/detail?id=255 + if (dateStr.search("-") == -1 || + dateStr.search("T") != -1 || dateStr.search("Z") != -1) { + d = Dygraph.dateStrToMillis(dateStr); + if (d && !isNaN(d)) return d; + } if (dateStr.search("-") != -1) { // e.g. '2009-7-12' or '2009-07-12' dateStrSlashed = dateStr.replace("-", "/", "g"); @@ -5425,7 +5775,9 @@ Dygraph.isPixelChangingOptionList = function(labels, attrs) { 'clickCallback': true, 'digitsAfterDecimal': true, 'drawCallback': true, + 'drawHighlightPointCallback': true, 'drawPoints': true, + 'drawPointCallback': true, 'drawXGrid': true, 'drawYGrid': true, 'fillAlpha': true, @@ -5530,6 +5882,111 @@ Dygraph.compareArrays = function(array1, array2) { } return true; }; + +/** + * ctx: the canvas context + * sides: the number of sides in the shape. + * radius: the radius of the image. + * cx: center x coordate + * cy: center y coordinate + * rotationRadians: the shift of the initial angle, in radians. + * delta: the angle shift for each line. If missing, creates a regular + * polygon. + */ +Dygraph.regularShape_ = function( + ctx, sides, radius, cx, cy, rotationRadians, delta) { + rotationRadians = rotationRadians ? rotationRadians : 0; + delta = delta ? delta : Math.PI * 2 / sides; + + ctx.beginPath(); + var first = true; + var initialAngle = rotationRadians; + var angle = initialAngle; + + var computeCoordinates = function() { + var x = cx + (Math.sin(angle) * radius); + var y = cy + (-Math.cos(angle) * radius); + return [x, y]; + }; + + var initialCoordinates = computeCoordinates(); + var x = initialCoordinates[0]; + var y = initialCoordinates[1]; + ctx.moveTo(x, y); + + for (var idx = 0; idx < sides; idx++) { + angle = (idx == sides - 1) ? initialAngle : (angle + delta); + var coords = computeCoordinates(); + ctx.lineTo(coords[0], coords[1]); + } + ctx.fill(); + ctx.stroke(); +} + +Dygraph.shapeFunction_ = function(sides, rotationRadians, delta) { + return function(g, name, ctx, cx, cy, color, radius) { + ctx.strokeStyle = color; + ctx.fillStyle = "white"; + Dygraph.regularShape_(ctx, sides, radius, cx, cy, rotationRadians, delta); + }; +}; + +Dygraph.DrawPolygon_ = function(sides, rotationRadians, ctx, cx, cy, color, radius, delta) { + new Dygraph.RegularShape_(sides, rotationRadians, delta).draw(ctx, cx, cy, radius); +} + +Dygraph.Circles = { + DEFAULT : function(g, name, ctx, canvasx, canvasy, color, radius) { + ctx.beginPath(); + ctx.fillStyle = color; + ctx.arc(canvasx, canvasy, radius, 0, 2 * Math.PI, false); + ctx.fill(); + }, + TRIANGLE : Dygraph.shapeFunction_(3), + SQUARE : Dygraph.shapeFunction_(4, Math.PI / 4), + DIAMOND : Dygraph.shapeFunction_(4), + PENTAGON : Dygraph.shapeFunction_(5), + HEXAGON : Dygraph.shapeFunction_(6), + CIRCLE : function(g, name, ctx, cx, cy, color, radius) { + ctx.beginPath(); + ctx.strokeStyle = color; + ctx.fillStyle = "white"; + ctx.arc(cx, cy, radius, 0, 2 * Math.PI, false); + ctx.fill(); + ctx.stroke(); + }, + STAR : Dygraph.shapeFunction_(5, 0, 4 * Math.PI / 5), + PLUS : function(g, name, ctx, cx, cy, color, radius) { + ctx.strokeStyle = color; + + ctx.beginPath(); + ctx.moveTo(cx + radius, cy); + ctx.lineTo(cx - radius, cy); + ctx.closePath(); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(cx, cy + radius); + ctx.lineTo(cx, cy - radius); + ctx.closePath(); + ctx.stroke(); + }, + EX : function(g, name, ctx, cx, cy, color, radius) { + ctx.strokeStyle = color; + + ctx.beginPath(); + ctx.moveTo(cx + radius, cy + radius); + ctx.lineTo(cx - radius, cy - radius); + ctx.closePath(); + ctx.stroke(); + + ctx.beginPath(); + ctx.moveTo(cx + radius, cy - radius); + ctx.lineTo(cx - radius, cy + radius); + ctx.closePath(); + ctx.stroke(); + } +}; /** * @license * Copyright 2011 Dan Vanderkam (danvdk@gmail.com) @@ -5680,20 +6137,26 @@ Dygraph.Interaction.startPan = function(event, g, context) { // Record the range of each y-axis at the start of the drag. // If any axis has a valueRange or valueWindow, then we want a 2D pan. + // We can't store data directly in g.axes_, because it does not belong to us + // and could change out from under us during a pan (say if there's a data + // update). context.is2DPan = false; + context.axes = []; for (i = 0; i < g.axes_.length; i++) { axis = g.axes_[i]; + var axis_data = {}; var yRange = g.yAxisRange(i); // TODO(konigsberg): These values should be in |context|. // In log scale, initialTopValue, dragValueRange and unitsPerPixel are log scale. if (axis.logscale) { - axis.initialTopValue = Dygraph.log10(yRange[1]); - axis.dragValueRange = Dygraph.log10(yRange[1]) - Dygraph.log10(yRange[0]); + axis_data.initialTopValue = Dygraph.log10(yRange[1]); + axis_data.dragValueRange = Dygraph.log10(yRange[1]) - Dygraph.log10(yRange[0]); } else { - axis.initialTopValue = yRange[1]; - axis.dragValueRange = yRange[1] - yRange[0]; + axis_data.initialTopValue = yRange[1]; + axis_data.dragValueRange = yRange[1] - yRange[0]; } - axis.unitsPerPixel = axis.dragValueRange / (g.plotter_.area.h - 1); + axis_data.unitsPerPixel = axis_data.dragValueRange / (g.plotter_.area.h - 1); + context.axes.push(axis_data); // While calculating axes, set 2dpan. if (axis.valueWindow || axis.valueRange) context.is2DPan = true; @@ -5738,23 +6201,24 @@ Dygraph.Interaction.movePan = function(event, g, context) { // Adjust each axis appropriately. for (var i = 0; i < g.axes_.length; i++) { var axis = g.axes_[i]; + var axis_data = context.axes[i]; var pixelsDragged = context.dragEndY - context.dragStartY; - var unitsDragged = pixelsDragged * axis.unitsPerPixel; + var unitsDragged = pixelsDragged * axis_data.unitsPerPixel; var boundedValue = context.boundedValues ? context.boundedValues[i] : null; // In log scale, maxValue and minValue are the logs of those values. - var maxValue = axis.initialTopValue + unitsDragged; + var maxValue = axis_data.initialTopValue + unitsDragged; if (boundedValue) { maxValue = Math.min(maxValue, boundedValue[1]); } - var minValue = maxValue - axis.dragValueRange; + var minValue = maxValue - axis_data.dragValueRange; if (boundedValue) { if (minValue < boundedValue[0]) { // Adjust maxValue, and recompute minValue. maxValue = maxValue - (minValue - boundedValue[0]); - minValue = maxValue - axis.dragValueRange; + minValue = maxValue - axis_data.dragValueRange; } } if (axis.logscale) { @@ -5777,7 +6241,7 @@ Dygraph.Interaction.movePan = function(event, g, context) { * Custom interaction model builders can use it to provide the default * panning behavior. * - * @param { Event } event the event object which led to the startZoom call. + * @param { Event } event the event object which led to the endPan call. * @param { Dygraph} g The dygraph on which to act. * @param { Object} context The dragging context object (with * dragStartX/dragStartY/etc. properties). This function modifies the context. @@ -5794,8 +6258,6 @@ Dygraph.Interaction.endPan = function(event, g, context) { Dygraph.Interaction.treatMouseOpAsClick(g, event, context); } - // TODO(konigsberg): Clear the context data from the axis. - // (replace with "context = {}" ?) // TODO(konigsberg): mouseup should just delete the // context object, and mousedown should create a new one. context.isPanning = false; @@ -5805,6 +6267,7 @@ Dygraph.Interaction.endPan = function(event, g, context) { context.valueRange = null; context.boundedDates = null; context.boundedValues = null; + context.axes = null; }; /** @@ -5931,9 +6394,11 @@ Dygraph.Interaction.endZoom = function(event, g, context) { if (regionWidth >= 10 && context.dragDirection == Dygraph.HORIZONTAL) { g.doZoomX_(Math.min(context.dragStartX, context.dragEndX), Math.max(context.dragStartX, context.dragEndX)); + context.cancelNextDblclick = true; } else if (regionHeight >= 10 && context.dragDirection == Dygraph.VERTICAL) { g.doZoomY_(Math.min(context.dragStartY, context.dragEndY), Math.max(context.dragStartY, context.dragEndY)); + context.cancelNextDblclick = true; } else { g.clearZoomRect_(); } @@ -5942,6 +6407,154 @@ Dygraph.Interaction.endZoom = function(event, g, context) { }; /** + * @private + */ +Dygraph.Interaction.startTouch = function(event, g, context) { + event.preventDefault(); // touch browsers are all nice. + var touches = []; + for (var i = 0; i < event.touches.length; i++) { + var t = event.touches[i]; + // we dispense with 'dragGetX_' because all touchBrowsers support pageX + touches.push({ + pageX: t.pageX, + pageY: t.pageY, + dataX: g.toDataXCoord(t.pageX), + dataY: g.toDataYCoord(t.pageY) + // identifier: t.identifier + }); + } + context.initialTouches = touches; + + if (touches.length == 1) { + // This is just a swipe. + context.initialPinchCenter = touches[0]; + context.touchDirections = { x: true, y: true }; + } else if (touches.length == 2) { + // It's become a pinch! + + // only screen coordinates can be averaged (data coords could be log scale). + context.initialPinchCenter = { + pageX: 0.5 * (touches[0].pageX + touches[1].pageX), + pageY: 0.5 * (touches[0].pageY + touches[1].pageY), + + // TODO(danvk): remove + dataX: 0.5 * (touches[0].dataX + touches[1].dataX), + dataY: 0.5 * (touches[0].dataY + touches[1].dataY) + }; + + // Make pinches in a 45-degree swath around either axis 1-dimensional zooms. + var initialAngle = 180 / Math.PI * Math.atan2( + context.initialPinchCenter.pageY - touches[0].pageY, + touches[0].pageX - context.initialPinchCenter.pageX); + + // use symmetry to get it into the first quadrant. + initialAngle = Math.abs(initialAngle); + if (initialAngle > 90) initialAngle = 90 - initialAngle; + + context.touchDirections = { + x: (initialAngle < (90 - 45/2)), + y: (initialAngle > 45/2) + }; + } + + // save the full x & y ranges. + context.initialRange = { + x: g.xAxisRange(), + y: g.yAxisRange() + }; +}; + +/** + * @private + */ +Dygraph.Interaction.moveTouch = function(event, g, context) { + var i, touches = []; + for (i = 0; i < event.touches.length; i++) { + var t = event.touches[i]; + touches.push({ + pageX: t.pageX, + pageY: t.pageY + }); + } + var initialTouches = context.initialTouches; + + var c_now; + + // old and new centers. + var c_init = context.initialPinchCenter; + if (touches.length == 1) { + c_now = touches[0]; + } else { + c_now = { + pageX: 0.5 * (touches[0].pageX + touches[1].pageX), + pageY: 0.5 * (touches[0].pageY + touches[1].pageY) + }; + } + + // this is the "swipe" component + // we toss it out for now, but could use it in the future. + var swipe = { + pageX: c_now.pageX - c_init.pageX, + pageY: c_now.pageY - c_init.pageY + }; + var dataWidth = context.initialRange.x[1] - context.initialRange.x[0]; + var dataHeight = context.initialRange.y[0] - context.initialRange.y[1]; + swipe.dataX = (swipe.pageX / g.plotter_.area.w) * dataWidth; + swipe.dataY = (swipe.pageY / g.plotter_.area.h) * dataHeight; + var xScale, yScale; + + // The residual bits are usually split into scale & rotate bits, but we split + // them into x-scale and y-scale bits. + if (touches.length == 1) { + xScale = 1.0; + yScale = 1.0; + } else if (touches.length == 2) { + var initHalfWidth = (initialTouches[1].pageX - c_init.pageX); + xScale = (touches[1].pageX - c_now.pageX) / initHalfWidth; + + var initHalfHeight = (initialTouches[1].pageY - c_init.pageY); + yScale = (touches[1].pageY - c_now.pageY) / initHalfHeight; + } + + // Clip scaling to [1/8, 8] to prevent too much blowup. + xScale = Math.min(8, Math.max(0.125, xScale)); + yScale = Math.min(8, Math.max(0.125, yScale)); + + if (context.touchDirections.x) { + g.dateWindow_ = [ + c_init.dataX - swipe.dataX + (context.initialRange.x[0] - c_init.dataX) / xScale, + c_init.dataX - swipe.dataX + (context.initialRange.x[1] - c_init.dataX) / xScale + ]; + } + + if (context.touchDirections.y) { + for (i = 0; i < 1 /*g.axes_.length*/; i++) { + var axis = g.axes_[i]; + if (axis.logscale) { + // TODO(danvk): implement + } else { + axis.valueWindow = [ + c_init.dataY - swipe.dataY + (context.initialRange.y[0] - c_init.dataY) / yScale, + c_init.dataY - swipe.dataY + (context.initialRange.y[1] - c_init.dataY) / yScale + ]; + } + } + } + + g.drawGraph_(false); +}; + +/** + * @private + */ +Dygraph.Interaction.endTouch = function(event, g, context) { + if (event.touches.length != 0) { + // this is effectively a "reset" + Dygraph.Interaction.startTouch(event, g, context); + } +}; + +/** * Default interation model for dygraphs. You can refer to specific elements of * this when constructing your own interaction model, e.g.: * g.updateOptions( { @@ -5953,6 +6566,9 @@ Dygraph.Interaction.endZoom = function(event, g, context) { Dygraph.Interaction.defaultModel = { // Track the beginning of drag events mousedown: function(event, g, context) { + // Right-click should not initiate a zoom. + if (event.button && event.button == 2) return; + context.initializeMouseDown(event, g, context); if (event.altKey || event.shiftKey) { @@ -5979,6 +6595,16 @@ Dygraph.Interaction.defaultModel = { } }, + touchstart: function(event, g, context) { + Dygraph.Interaction.startTouch(event, g, context); + }, + touchmove: function(event, g, context) { + Dygraph.Interaction.moveTouch(event, g, context); + }, + touchend: function(event, g, context) { + Dygraph.Interaction.endTouch(event, g, context); + }, + // Temporarily cancel the dragging event when the mouse leaves the graph mouseout: function(event, g, context) { if (context.isZooming) { @@ -5989,6 +6615,10 @@ Dygraph.Interaction.defaultModel = { // Disable zooming out if panning. dblclick: function(event, g, context) { + if (context.cancelNextDblclick) { + context.cancelNextDblclick = false; + return; + } if (event.altKey || event.shiftKey) { return; } @@ -6760,6 +7390,14 @@ DygraphRangeSelector.prototype.getZoomHandleStatus_ = function() { /*global Dygraph:false */ "use strict"; +Dygraph.numericLinearTicks = function(a, b, pixels, opts, dygraph, vals) { + var nonLogscaleOpts = function(opt) { + if (opt === 'logscale') return false; + return opts(opt); + }; + return Dygraph.numericTicks(a, b, pixels, nonLogscaleOpts, dygraph, vals); +}; + Dygraph.numericTicks = function(a, b, pixels, opts, dygraph, vals) { var pixels_per_tick = opts('pixelsPerLabel'); var ticks = []; @@ -6860,12 +7498,12 @@ Dygraph.numericTicks = function(a, b, pixels, opts, dygraph, vals) { var k_labels = []; if (opts("labelsKMB")) { k = 1000; - k_labels = [ "K", "M", "B", "T" ]; + k_labels = [ "K", "M", "B", "T", "Q" ]; } if (opts("labelsKMG2")) { if (k) Dygraph.warn("Setting both labelsKMB and labelsKMG2. Pick one!"); k = 1024; - k_labels = [ "k", "M", "G", "T" ]; + k_labels = [ "k", "M", "G", "T", "P", "E" ]; } var formatter = opts('axisLabelFormatter'); @@ -6880,8 +7518,8 @@ Dygraph.numericTicks = function(a, b, pixels, opts, dygraph, vals) { if (k_labels.length > 0) { // TODO(danvk): should this be integrated into the axisLabelFormatter? // Round up to an appropriate unit. - var n = k*k*k*k; - for (j = 3; j >= 0; j--, n /= k) { + var n = Math.pow(k, k_labels.length); + for (j = k_labels.length - 1; j >= 0; j--, n /= k) { if (absTickV >= n) { label = Dygraph.round_(tickV / n, opts('digitsAfterDecimal')) + k_labels[j]; diff --git a/static/vendor/dygraph-1.2dev.min.js b/static/vendor/dygraph-1.2dev.min.js index b9e5ecc..4ef6394 100644 --- a/static/vendor/dygraph-1.2dev.min.js +++ b/static/vendor/dygraph-1.2dev.min.js @@ -1 +1,11 @@ -"use strict";var DygraphLayout=function(a){this.dygraph_=a;this.datasets=[];this.setNames=[];this.annotations=[];this.yAxes_=null;this.xTicks_=null;this.yTicks_=null};DygraphLayout.prototype.attr_=function(a){return this.dygraph_.attr_(a)};DygraphLayout.prototype.addDataset=function(a,b){this.datasets.push(b);this.setNames.push(a)};DygraphLayout.prototype.getPlotArea=function(){return this.computePlotArea_()};DygraphLayout.prototype.computePlotArea_=function(){var a={x:0,y:0};if(this.attr_("drawYAxis")){a.x=this.attr_("yAxisLabelWidth")+2*this.attr_("axisTickSize")}a.w=this.dygraph_.width_-a.x-this.attr_("rightGap");a.h=this.dygraph_.height_;if(this.attr_("drawXAxis")){if(this.attr_("xAxisHeight")){a.h-=this.attr_("xAxisHeight")}else{a.h-=this.attr_("axisLabelFontSize")+2*this.attr_("axisTickSize")}}if(this.dygraph_.numAxes()==2){a.w-=(this.attr_("yAxisLabelWidth")+2*this.attr_("axisTickSize"))}else{if(this.dygraph_.numAxes()>2){this.dygraph_.error("Only two y-axes are supported at this time. (Trying to use "+this.dygraph_.numAxes()+")")}}if(this.attr_("title")){a.h-=this.attr_("titleHeight");a.y+=this.attr_("titleHeight")}if(this.attr_("xlabel")){a.h-=this.attr_("xLabelHeight")}if(this.attr_("ylabel")){}if(this.attr_("y2label")){}if(this.attr_("showRangeSelector")){a.h-=this.attr_("rangeSelectorHeight")+4}return a};DygraphLayout.prototype.setAnnotations=function(d){this.annotations=[];var e=this.attr_("xValueParser")||function(a){return a};for(var c=0;c1){var b=d[0][0];if(!this.minxval||bthis.maxxval){this.maxxval=a}}}}this.xrange=this.maxxval-this.minxval;this.xscale=(this.xrange!==0?1/this.xrange:1);for(var c=0;c=0)&&(f<=1)){this.xticks.push([f,b])}}this.yticks=[];for(d=0;d=0)&&(f<=1)){this.yticks.push([d,f,b])}}}};DygraphLayout.prototype.evaluateWithError=function(){this.evaluate();if(!(this.attr_("errorBars")||this.attr_("customBars"))){return}var h=0;for(var a=0;a=0;e--){if(f.childNodes[e].className==g){f.removeChild(f.childNodes[e])}}var c=document.bgColor;var d=this.dygraph_.graphDiv;while(d!=document){var a=d.currentStyle.backgroundColor;if(a&&a!="transparent"){c=a;break}d=d.parentNode}function b(j){if(j.w===0||j.h===0){return}var i=document.createElement("div");i.className=g;i.style.backgroundColor=c;i.style.position="absolute";i.style.left=j.x+"px";i.style.top=j.y+"px";i.style.width=j.w+"px";i.style.height=j.h+"px";f.appendChild(i)}var h=this.area;b({x:0,y:0,w:h.x,h:this.height});b({x:h.x,y:0,w:this.width-h.x,h:h.y});b({x:h.x+h.w,y:0,w:this.width-h.x-h.w,h:this.height});b({x:h.x,y:h.y+h.h,w:this.width-h.x,h:this.height-h.h-h.y})};DygraphCanvasRenderer.prototype._renderAxis=function(){if(!this.attr_("drawXAxis")&&!this.attr_("drawYAxis")){return}function q(i){return Math.round(i)+0.5}function p(i){return Math.round(i)-0.5}var d=this.elementContext;var l,n,m,s,r;var a={position:"absolute",fontSize:this.attr_("axisLabelFontSize")+"px",zIndex:10,color:this.attr_("axisLabelColor"),width:this.attr_("axisLabelWidth")+"px",lineHeight:"normal",overflow:"hidden"};var g=function(i,v,w){var x=document.createElement("div");for(var u in a){if(a.hasOwnProperty(u)){x.style[u]=a[u]}}var t=document.createElement("div");t.className="dygraph-axis-label dygraph-axis-label-"+v+(w?" dygraph-axis-label-"+w:"");t.innerHTML=i;x.appendChild(t);return x};d.save();d.strokeStyle=this.attr_("axisLineColor");d.lineWidth=this.attr_("axisLineWidth");if(this.attr_("drawYAxis")){if(this.layout.yticks&&this.layout.yticks.length>0){var b=this.dygraph_.numAxes();for(r=0;rthis.height){l.style.bottom="0px"}else{l.style.top=o+"px"}if(s[0]===0){l.style.left=(this.area.x-this.attr_("yAxisLabelWidth")-this.attr_("axisTickSize"))+"px";l.style.textAlign="right"}else{if(s[0]==1){l.style.left=(this.area.x+this.area.w+this.attr_("axisTickSize"))+"px";l.style.textAlign="left"}}l.style.width=this.attr_("yAxisLabelWidth")+"px";this.container.appendChild(l);this.ylabels.push(l)}var h=this.ylabels[0];var e=this.attr_("axisLabelFontSize");var k=parseInt(h.style.top,10)+e;if(k>this.height-e){h.style.top=(parseInt(h.style.top,10)-e/2)+"px"}}d.beginPath();d.moveTo(q(this.area.x),p(this.area.y));d.lineTo(q(this.area.x),p(this.area.y+this.area.h));d.closePath();d.stroke();if(this.dygraph_.numAxes()==2){d.beginPath();d.moveTo(p(this.area.x+this.area.w),p(this.area.y));d.lineTo(p(this.area.x+this.area.w),p(this.area.y+this.area.h));d.closePath();d.stroke()}}if(this.attr_("drawXAxis")){if(this.layout.xticks){for(r=0;rthis.width){f=this.width-this.attr_("xAxisLabelWidth");l.style.textAlign="right"}if(f<0){f=0;l.style.textAlign="left"}l.style.left=f+"px";l.style.width=this.attr_("xAxisLabelWidth")+"px";this.container.appendChild(l);this.xlabels.push(l)}}d.beginPath();d.moveTo(q(this.area.x),p(this.area.y+this.area.h));d.lineTo(q(this.area.x+this.area.w),p(this.area.y+this.area.h));d.closePath();d.stroke()}d.restore()};DygraphCanvasRenderer.prototype._renderChartLabels=function(){var d,a;if(this.attr_("title")){d=document.createElement("div");d.style.position="absolute";d.style.top="0px";d.style.left=this.area.x+"px";d.style.width=this.area.w+"px";d.style.height=this.attr_("titleHeight")+"px";d.style.textAlign="center";d.style.fontSize=(this.attr_("titleHeight")-8)+"px";d.style.fontWeight="bold";a=document.createElement("div");a.className="dygraph-label dygraph-title";a.innerHTML=this.attr_("title");d.appendChild(a);this.container.appendChild(d);this.chartLabels.title=d}if(this.attr_("xlabel")){d=document.createElement("div");d.style.position="absolute";d.style.bottom=0;d.style.left=this.area.x+"px";d.style.width=this.area.w+"px";d.style.height=this.attr_("xLabelHeight")+"px";d.style.textAlign="center";d.style.fontSize=(this.attr_("xLabelHeight")-2)+"px";a=document.createElement("div");a.className="dygraph-label dygraph-xlabel";a.innerHTML=this.attr_("xlabel");d.appendChild(a);this.container.appendChild(d);this.chartLabels.xlabel=d}var c=this;function b(h,g,f){var i={left:0,top:c.area.y,width:c.attr_("yLabelWidth"),height:c.area.h};d=document.createElement("div");d.style.position="absolute";if(h==1){d.style.left=i.left}else{d.style.right=i.left}d.style.top=i.top+"px";d.style.width=i.width+"px";d.style.height=i.height+"px";d.style.fontSize=(c.attr_("yLabelWidth")-2)+"px";var e=document.createElement("div");e.style.position="absolute";e.style.width=i.height+"px";e.style.height=i.width+"px";e.style.top=(i.height/2-i.width/2)+"px";e.style.left=(i.width/2-i.height/2)+"px";e.style.textAlign="center";var j="rotate("+(h==1?"-":"")+"90deg)";e.style.transform=j;e.style.WebkitTransform=j;e.style.MozTransform=j;e.style.OTransform=j;e.style.msTransform=j;if(typeof(document.documentMode)!=="undefined"&&document.documentMode<9){e.style.filter="progid:DXImageTransform.Microsoft.BasicImage(rotation="+(h==1?"3":"1")+")";e.style.left="0px";e.style.top="0px"}a=document.createElement("div");a.className=g;a.innerHTML=f;e.appendChild(a);d.appendChild(e);return d}var d;if(this.attr_("ylabel")){d=b(1,"dygraph-label dygraph-ylabel",this.attr_("ylabel"));this.container.appendChild(d);this.chartLabels.ylabel=d}if(this.attr_("y2label")&&this.dygraph_.numAxes()==2){d=b(2,"dygraph-label dygraph-y2label",this.attr_("y2label"));this.container.appendChild(d);this.chartLabels.y2label=d}};DygraphCanvasRenderer.prototype._renderAnnotations=function(){var h={position:"absolute",fontSize:this.attr_("axisLabelFontSize")+"px",zIndex:10,overflow:"hidden"};var j=function(i,q,r,a){return function(s){var p=r.annotation;if(p.hasOwnProperty(i)){p[i](p,r,a.dygraph_,s)}else{if(a.dygraph_.attr_(q)){a.dygraph_.attr_(q)(p,r,a.dygraph_,s)}}}};var m=this.layout.annotated_points;for(var g=0;gthis.area.x+this.area.w){continue}var k=e.annotation;var l=6;if(k.hasOwnProperty("tickHeight")){l=k.tickHeight}var c=document.createElement("div");for(var b in h){if(h.hasOwnProperty(b)){c.style[b]=h[b]}}if(!k.hasOwnProperty("icon")){c.className="dygraphDefaultAnnotation"}if(k.hasOwnProperty("cssClass")){c.className+=" "+k.cssClass}var d=k.hasOwnProperty("width")?k.width:16;var n=k.hasOwnProperty("height")?k.height:16;if(k.hasOwnProperty("icon")){var f=document.createElement("img");f.src=k.icon;f.width=d;f.height=n;c.appendChild(f)}else{if(e.annotation.hasOwnProperty("shortText")){c.appendChild(document.createTextNode(e.annotation.shortText))}}c.style.left=(e.canvasx-d/2)+"px";if(k.attachAtBottom){c.style.top=(this.area.h-n-l)+"px"}else{c.style.top=(e.canvasy-n-l)+"px"}c.style.width=d+"px";c.style.height=n+"px";c.title=e.annotation.text;c.style.color=this.colors[e.name];c.style.borderColor=this.colors[e.name];k.div=c;Dygraph.addEvent(c,"click",j("clickHandler","annotationClickHandler",e,this));Dygraph.addEvent(c,"mouseover",j("mouseOverHandler","annotationMouseOverHandler",e,this));Dygraph.addEvent(c,"mouseout",j("mouseOutHandler","annotationMouseOutHandler",e,this));Dygraph.addEvent(c,"dblclick",j("dblClickHandler","annotationDblClickHandler",e,this));this.container.appendChild(c);this.annotations.push(c);var o=this.elementContext;o.strokeStyle=this.colors[e.name];o.beginPath();if(!k.attachAtBottom){o.moveTo(e.canvasx,e.canvasy);o.lineTo(e.canvasx,e.canvasy-2-l)}else{o.moveTo(e.canvasx,this.area.h);o.lineTo(e.canvasx,this.area.h-2-l)}o.closePath();o.stroke()}};DygraphCanvasRenderer.prototype._renderLineChart=function(){var F=function(i){return(i===null||isNaN(i))};var L=this.elementContext;var l=this.attr_("fillAlpha");var B=this.attr_("errorBars")||this.attr_("customBars");var k=this.attr_("fillGraph");var v=this.attr_("stackedGraph");var u=this.attr_("stepPlot");var z=this.layout.points;var y=z.length;var t,J,H,b,a,f,s,E,m,C,h,d,q;var D=this.layout.setNames;var w=D.length;this.colors={};for(J=0;J=0;J--){E=D[J];s=this.colors[E];q=this.dygraph_.axisPropertiesForSeries(E);var e=1+q.minyval*q.yscale;if(e<0){e=0}else{if(e>1){e=1}}e=this.area.h*e+this.area.y;p.save();b=NaN;f=[-1,-1];d=q.yscale;h=new RGBColor(s);C="rgba("+h.r+","+h.g+","+h.b+","+l+")";p.fillStyle=C;p.beginPath();for(H=0;Hi){d=f[c];if(this._dashedLineToHistory[1]){i+=this._dashedLineToHistory[1]}else{i+=d}if(i>e){this._dashedLineToHistory=[c,i-e];i=e}else{this._dashedLineToHistory=[(c+1)%f.length,0]}if(c%2===0){j.lineTo(i,0)}else{j.moveTo(i,0)}c=(c+1)%f.length}j.restore()};"use strict";var Dygraph=function(c,b,a){if(arguments.length>0){if(arguments.length==4){this.warn("Using deprecated four-argument dygraph constructor");this.__old_init__(c,b,arguments[2],arguments[3])}else{this.__init__(c,b,a)}}};Dygraph.NAME="Dygraph";Dygraph.VERSION="1.2dev";Dygraph.__repr__=function(){return"["+this.NAME+" "+this.VERSION+"]"};Dygraph.toString=function(){return this.__repr__()};Dygraph.DEFAULT_ROLL_PERIOD=1;Dygraph.DEFAULT_WIDTH=480;Dygraph.DEFAULT_HEIGHT=320;Dygraph.ANIMATION_STEPS=10;Dygraph.ANIMATION_DURATION=200;Dygraph.numberValueFormatter=function(a,e,h,d){var b=e("sigFigs");if(b!==null){return Dygraph.floatFormat(a,b)}var f=e("digitsAfterDecimal");var c=e("maxNumberWidth");if(a!==0&&(Math.abs(a)>=Math.pow(10,c)||Math.abs(a)=Dygraph.DECADAL){return b.strftime("%Y")}else{if(c>=Dygraph.MONTHLY){return b.strftime("%b %y")}else{var a=b.getHours()*3600+b.getMinutes()*60+b.getSeconds()+b.getMilliseconds();if(a===0||c>=Dygraph.DAILY){return new Date(b.getTime()+3600*1000).strftime("%d%b")}else{return Dygraph.hmsString_(b.getTime())}}}};Dygraph.DEFAULT_ATTRS={highlightCircleSize:3,labelsDivWidth:250,labelsDivStyles:{},labelsSeparateLines:false,labelsShowZeroValues:true,labelsKMB:false,labelsKMG2:false,showLabelsOnHighlight:true,digitsAfterDecimal:2,maxNumberWidth:6,sigFigs:null,strokeWidth:1,axisTickSize:3,axisLabelFontSize:14,xAxisLabelWidth:50,yAxisLabelWidth:50,rightGap:5,showRoller:false,xValueParser:Dygraph.dateParser,delimiter:",",sigma:2,errorBars:false,fractions:false,wilsonInterval:true,customBars:false,fillGraph:false,fillAlpha:0.15,connectSeparatedPoints:false,stackedGraph:false,hideOverlayOnMouseOut:true,legend:"onmouseover",stepPlot:false,avoidMinZero:false,titleHeight:28,xLabelHeight:18,yLabelWidth:18,drawXAxis:true,drawYAxis:true,axisLineColor:"black",axisLineWidth:0.3,gridLineWidth:0.3,axisLabelColor:"black",axisLabelFont:"Arial",axisLabelWidth:50,drawYGrid:true,drawXGrid:true,gridLineColor:"rgb(128,128,128)",interactionModel:null,animatedZooms:false,showRangeSelector:false,rangeSelectorHeight:40,rangeSelectorPlotStrokeColor:"#808FAB",rangeSelectorPlotFillColor:"#A7B1C4",axes:{x:{pixelsPerLabel:60,axisLabelFormatter:Dygraph.dateAxisFormatter,valueFormatter:Dygraph.dateString_,ticker:null},y:{pixelsPerLabel:30,valueFormatter:Dygraph.numberValueFormatter,axisLabelFormatter:Dygraph.numberAxisLabelFormatter,ticker:null},y2:{pixelsPerLabel:30,valueFormatter:Dygraph.numberValueFormatter,axisLabelFormatter:Dygraph.numberAxisLabelFormatter,ticker:null}}};Dygraph.HORIZONTAL=1;Dygraph.VERTICAL=2;Dygraph.addedAnnotationCSS=false;Dygraph.prototype.__old_init__=function(f,d,e,b){if(e!==null){var a=["Date"];for(var c=0;c=this.axes_.length){return null}var b=this.axes_[a];return[b.computedValueRange[0],b.computedValueRange[1]]};Dygraph.prototype.yAxisRanges=function(){var a=[];for(var b=0;b0){return[this.rawData_[0][0],this.rawData_[this.numRows()-1][0]]}else{return[0,1]}};Dygraph.prototype.getValue=function(b,a){if(b<0||b>this.rawData_.length){return null}if(a<0||a>this.rawData_[b].length){return null}return this.rawData_[b][a]};Dygraph.prototype.createInterface_=function(){var a=this.maindiv_;this.graphDiv=document.createElement("div");this.graphDiv.style.width=this.width_+"px";this.graphDiv.style.height=this.height_+"px";a.appendChild(this.graphDiv);this.canvas_=Dygraph.createCanvas();this.canvas_.style.position="absolute";this.canvas_.width=this.width_;this.canvas_.height=this.height_;this.canvas_.style.width=this.width_+"px";this.canvas_.style.height=this.height_+"px";this.canvas_ctx_=Dygraph.getContext(this.canvas_);this.hidden_=this.createPlotKitCanvas_(this.canvas_);this.hidden_ctx_=Dygraph.getContext(this.hidden_);if(this.attr_("showRangeSelector")){this.rangeSelector_=new DygraphRangeSelector(this)}this.graphDiv.appendChild(this.hidden_);this.graphDiv.appendChild(this.canvas_);this.mouseEventElement_=this.createMouseEventElement_();this.layout_=new DygraphLayout(this);if(this.rangeSelector_){this.rangeSelector_.addToGraph(this.graphDiv,this.layout_)}var b=this;this.mouseMoveHandler=function(c){b.mouseMove_(c)};Dygraph.addEvent(this.mouseEventElement_,"mousemove",this.mouseMoveHandler);this.mouseOutHandler=function(c){b.mouseOut_(c)};Dygraph.addEvent(this.mouseEventElement_,"mouseout",this.mouseOutHandler);this.createStatusMessage_();this.createDragInterface_();this.resizeHandler=function(c){b.resize()};Dygraph.addEvent(window,"resize",this.resizeHandler)};Dygraph.prototype.destroy=function(){var a=function(c){while(c.hasChildNodes()){a(c.firstChild);c.removeChild(c.firstChild)}};Dygraph.removeEvent(this.mouseEventElement_,"mouseout",this.mouseOutHandler);Dygraph.removeEvent(this.mouseEventElement_,"mousemove",this.mouseMoveHandler);a(this.maindiv_);var b=function(c){for(var d in c){if(typeof(c[d])==="object"){c[d]=null}}};Dygraph.removeEvent(window,"resize",this.resizeHandler);this.resizeHandler=null;b(this.layout_);b(this.plotter_);b(this)};Dygraph.prototype.createPlotKitCanvas_=function(a){var b=Dygraph.createCanvas();b.style.position="absolute";b.style.top=a.style.top;b.style.left=a.style.left;b.width=this.width_;b.height=this.height_;b.style.width=this.width_+"px";b.style.height=this.height_+"px";return b};Dygraph.prototype.createMouseEventElement_=function(){if(this.isUsingExcanvas_){var a=document.createElement("div");a.style.position="absolute";a.style.backgroundColor="white";a.style.filter="alpha(opacity=0)";a.style.width=this.width_+"px";a.style.height=this.height_+"px";this.graphDiv.appendChild(a);return a}else{return this.canvas_}};Dygraph.prototype.setColors_=function(){var e=this.attr_("labels").length-1;this.colors_=[];var a=this.attr_("colors");var d;if(!a){var c=this.attr_("colorSaturation")||1;var b=this.attr_("colorValue")||0.5;var j=Math.ceil(e/2);for(d=1;d<=e;d++){if(!this.visibility()[d-1]){continue}var g=d%2?Math.ceil(d/2):(j+d/2);var f=(1*g/(1+e));this.colors_.push(Dygraph.hsvToRGB(f,c,b))}}else{for(d=0;dn){continue}n=h;o=f}if(o>=0){j=r[o].xval}this.selPoints_=[];var d=r.length;if(!this.attr_("stackedGraph")){for(f=0;f=0;f--){if(r[f].xval==j){var c={};for(var e in r[f]){c[e]=r[f][e]}c.yval-=g;g+=c.yval;this.selPoints_.push(c)}}this.selPoints_.reverse()}if(this.attr_("highlightCallback")){var m=this.lastx_;if(m!==null&&j!=m){this.attr_("highlightCallback")(b,j,this.selPoints_,this.idxToRow_(o))}}this.lastx_=j;this.updateSelection_()};Dygraph.prototype.idxToRow_=function(a){if(a<0){return -1}var c=-1;for(var b=0;b'}else{for(f=0;f<=o.length;f++){c+=o[f%o.length]}g=Math.floor(n/(c-o[0]));if(g>1){for(f=0;f'}}}return h};Dygraph.prototype.generateLegendHTML_=function(k,f,b){var l,u,o,s,m,g;if(typeof(k)==="undefined"){if(this.attr_("legend")!="always"){return""}u=this.attr_("labelsSeparateLines");var r=this.attr_("labels");l="";for(o=1;o":" ")}g=this.attr_("strokePattern",r[o]);m=this.generateLegendDashHTML_(g,s,b);l+=""+m+" "+r[o]+""}return l}var t=this.optionsViewForAxis_("x");var h=t("valueFormatter");l=h(k,t,this.attr_("labels")[0],this)+":";var p=[];var d=this.numAxes();for(o=0;o"}var j=p[this.seriesToAxisMap_[n.name]];var q=j("valueFormatter");s=this.plotter_.colors[n.name];var a=q(n.yval,j,n.name,this);l+=" "+n.name+":"+a}return l};Dygraph.prototype.setLegendHTML_=function(b,e){var c=this.attr_("labelsDiv");var f=document.createElement("span");f.setAttribute("style","margin: 0; padding: 0 0 0 1em; border: 0;");c.appendChild(f);var a=f.offsetWidth;var d=this.generateLegendHTML_(b,e,a);if(c!==null){c.innerHTML=d}else{if(typeof(this.shown_legend_error_)=="undefined"){this.error("labelsDiv is set to something nonexistent; legend will not be shown.");this.shown_legend_error_=true}}};Dygraph.prototype.updateSelection_=function(){var d;var h=this.canvas_ctx_;if(this.previousVerticalX_>=0){var e=0;var f=this.attr_("labels");for(d=1;de){e=b}}var g=this.previousVerticalX_;h.clearRect(g-e-1,0,2*e+2,this.height_)}if(this.isUsingExcanvas_&&this.currentZoomRectArgs_){Dygraph.prototype.drawZoomRect_.apply(this,this.currentZoomRectArgs_)}if(this.selPoints_.length>0){if(this.attr_("showLabelsOnHighlight")){this.setLegendHTML_(this.lastx_,this.selPoints_)}var c=this.selPoints_[0].canvasx;h.save();for(d=0;d=0){for(var b=0;bg){a=g}if(ef){f=e}if(h===null||af){f=g}if(h===null||g=1;u--){if(!this.visibility()[u-1]){continue}var h=[];for(t=0;t=A&&d===null){d=r}if(h[r][0]<=f){z=r}}if(d===null){d=0}if(d>0){d--}if(z===null){z=h.length-1}if(zn[1]){n[1]=b[g]}if(b[g]0){this.setIndexByName_[g[0]]=0}for(var f=1;fc){c=a}}return 1+c};Dygraph.prototype.axisPropertiesForSeries=function(a){return this.axes_[this.seriesToAxisMap_[a]]};Dygraph.prototype.computeYAxisRanges_=function(a){var g=[],h;for(h in this.seriesToAxisMap_){if(!this.seriesToAxisMap_.hasOwnProperty(h)){continue}var p=this.seriesToAxisMap_[h];while(g.length<=p){g.push([])}g[p].push(h)}for(var u=0;u0){x=0}if(x==Infinity){x=0}if(w==-Infinity){w=1}var t=w-x;if(t===0){t=w}var d,z;if(b.logscale){d=w+0.1*t;z=x}else{d=w+0.1*t;z=x-0.1*t;if(!this.attr_("avoidMinZero")){if(z<0&&x>=0){z=0}if(d>0&&w<=0){d=0}}if(this.attr_("includeZero")){if(w<0){d=0}if(x>0){z=0}}}b.extremeRange=[z,d]}if(b.valueWindow){b.computedValueRange=[b.valueWindow[0],b.valueWindow[1]]}else{if(b.valueRange){b.computedValueRange=[b.valueRange[0],b.valueRange[1]]}else{b.computedValueRange=b.extremeRange}}var n=this.optionsViewForAxis_("y"+(u?"2":""));var y=n("ticker");if(u===0||b.independentTicks){b.ticks=y(b.computedValueRange[0],b.computedValueRange[1],this.height_,n,this)}else{var l=this.axes_[0];var e=l.ticks;var f=l.computedValueRange[1]-l.computedValueRange[0];var A=b.computedValueRange[1]-b.computedValueRange[0];var c=[];for(var r=0;r=0){k-=l[w-d][1][0];h-=l[w-d][1][1]}var A=l[w][0];var u=h?k/h:0;if(this.attr_("errorBars")){if(this.attr_("wilsonInterval")){if(h){var r=u<0?0:u,t=h;var z=s*Math.sqrt(r*(1-r)/t+s*s/(4*t*t));var a=1+s*s/h;E=(r+s*s/(2*h)-z)/a;o=(r+s*s/(2*h)+z)/a;b[w]=[A,[r*e,(r-E)*e,(o-r)*e]]}else{b[w]=[A,[0,0,0]]}}else{x=h?s*Math.sqrt(u*(1-u)/h):1;b[w]=[A,[e*u,e*x,e*x]]}}else{b[w]=[A,e*u]}}}else{if(this.attr_("customBars")){E=0;var B=0;o=0;var g=0;for(w=0;w=0){var q=l[w-d];if(q[1][1]!==null&&!isNaN(q[1][1])){E-=q[1][0];B-=q[1][1];o-=q[1][2];g-=1}}if(g){b[w]=[l[w][0],[1*B/g,1*(B-E)/g,1*(o-B)/g]]}else{b[w]=[l[w][0],[null,null,null]]}}}else{if(!this.attr_("errorBars")){if(d==1){return l}for(w=0;w0&&(b[c-1]!="e"&&b[c-1]!="E"))||b.indexOf("/")>=0||isNaN(parseFloat(b))){a=true}else{if(b.length==8&&b>"19700101"&&b<"20371231"){a=true}}if(a){this.attrs_.xValueParser=Dygraph.dateParser;this.attrs_.axes.x.valueFormatter=Dygraph.dateString_;this.attrs_.axes.x.ticker=Dygraph.dateTicker;this.attrs_.axes.x.axisLabelFormatter=Dygraph.dateAxisFormatter}else{this.attrs_.xValueParser=function(d){return parseFloat(d)};this.attrs_.axes.x.valueFormatter=function(d){return d};this.attrs_.axes.x.ticker=Dygraph.numericTicks;this.attrs_.axes.x.axisLabelFormatter=this.attrs_.axes.x.valueFormatter}};Dygraph.prototype.parseFloat_=function(a,c,b){var e=parseFloat(a);if(!isNaN(e)){return e}if(/^ *$/.test(a)){return null}if(/^ *nan *$/i.test(a)){return NaN}var d="Unable to parse '"+a+"' as a number";if(b!==null&&c!==null){d+=" on line "+(1+c)+" ('"+b+"') of CSV."}this.error(d);return null};Dygraph.prototype.parseCSV_=function(s){var r=[];var a=s.split("\n");var g,k;var p=this.attr_("delimiter");if(a[0].indexOf(p)==-1&&a[0].indexOf("\t")>=0){p="\t"}var b=0;if(!("labels" in this.user_attrs_)){b=1;this.attrs_.labels=a[0].split(p)}var o=0;var m;var q=false;var c=this.attr_("labels").length;var f=false;for(var l=b;l0&&h[0]0){j=String.fromCharCode(65+(i-1)%26)+j.toLowerCase();i=Math.floor((i-1)/26)}return j};var h=w.getNumberOfColumns();var g=w.getNumberOfRows();var f=w.getColumnType(0);if(f=="date"||f=="datetime"){this.attrs_.xValueParser=Dygraph.dateParser;this.attrs_.axes.x.valueFormatter=Dygraph.dateString_;this.attrs_.axes.x.ticker=Dygraph.dateTicker;this.attrs_.axes.x.axisLabelFormatter=Dygraph.dateAxisFormatter}else{if(f=="number"){this.attrs_.xValueParser=function(i){return parseFloat(i)};this.attrs_.axes.x.valueFormatter=function(i){return i};this.attrs_.axes.x.ticker=Dygraph.numericTicks;this.attrs_.axes.x.axisLabelFormatter=this.attrs_.axes.x.valueFormatter}else{this.error("only 'date', 'datetime' and 'number' types are supported for column 1 of DataTable input (Got '"+f+"')");return null}}var m=[];var t={};var s=false;var q,o;for(q=1;q0&&e[0]0){this.setAnnotations(a,true)}};Dygraph.prototype.start_=function(){var c=this.file_;if(typeof c=="function"){c=c()}if(Dygraph.isArrayLike(c)){this.rawData_=this.parseArray_(c);this.predraw_()}else{if(typeof c=="object"&&typeof c.getColumnRange=="function"){this.parseDataTable_(c);this.predraw_()}else{if(typeof c=="string"){if(c.indexOf("\n")>=0){this.loadedEvent_(c)}else{var b=new XMLHttpRequest();var a=this;b.onreadystatechange=function(){if(b.readyState==4){if(b.status===200||b.status===0){a.loadedEvent_(b.responseText)}}};b.open("GET",c,true);b.send(null)}}else{this.error("Unknown data format: "+(typeof c))}}}};Dygraph.prototype.updateOptions=function(e,b){if(typeof(b)=="undefined"){b=false}var d=e.file;var c=Dygraph.mapLegacyOptions_(e);if("rollPeriod" in c){this.rollPeriod_=c.rollPeriod}if("dateWindow" in c){this.dateWindow_=c.dateWindow;if(!("isZoomedIgnoreProgrammaticZoom" in c)){this.zoomed_x_=(c.dateWindow!==null)}}if("valueRange" in c&&!("isZoomedIgnoreProgrammaticZoom" in c)){this.zoomed_y_=(c.valueRange!==null)}var a=Dygraph.isPixelChangingOptionList(this.attr_("labels"),c);Dygraph.updateDeep(this.user_attrs_,c);if(d){this.file_=d;if(!b){this.start_()}}else{if(!b){if(a){this.predraw_()}else{this.renderGraph_(false,false)}}}};Dygraph.mapLegacyOptions_=function(c){var a={};for(var b in c){if(b=="file"){continue}if(c.hasOwnProperty(b)){a[b]=c[b]}}var e=function(g,f,h){if(!a.axes){a.axes={}}if(!a.axes[g]){a.axes[g]={}}a.axes[g][f]=h};var d=function(f,g,h){if(typeof(c[f])!="undefined"){e(g,h,c[f]);delete a[f]}};d("xValueFormatter","x","valueFormatter");d("pixelsPerXLabel","x","pixelsPerLabel");d("xAxisLabelFormatter","x","axisLabelFormatter");d("xTicker","x","ticker");d("yValueFormatter","y","valueFormatter");d("pixelsPerYLabel","y","pixelsPerLabel");d("yAxisLabelFormatter","y","axisLabelFormatter");d("yTicker","y","ticker");return a};Dygraph.prototype.resize=function(d,b){if(this.resize_lock){return}this.resize_lock=true;if((d===null)!=(b===null)){this.warn("Dygraph.resize() should be called with zero parameters or two non-NULL parameters. Pretending it was zero.");d=b=null}var a=this.width_;var c=this.height_;if(d){this.maindiv_.style.width=d+"px";this.maindiv_.style.height=b+"px";this.width_=d;this.height_=b}else{this.width_=this.maindiv_.clientWidth;this.height_=this.maindiv_.clientHeight}if(a!=this.width_||c!=this.height_){this.maindiv_.innerHTML="";this.roller_=null;this.attrs_.labelsDiv=null;this.createInterface_();if(this.annotations_.length){this.layout_.setAnnotations(this.annotations_)}this.predraw_()}this.resize_lock=false};Dygraph.prototype.adjustRoll=function(a){this.rollPeriod_=a;this.predraw_()};Dygraph.prototype.visibility=function(){if(!this.attr_("visibility")){this.attrs_.visibility=[]}while(this.attr_("visibility").length=a.length){this.warn("invalid series number in setVisibility: "+b)}else{a[b]=c;this.predraw_()}};Dygraph.prototype.size=function(){return{width:this.width_,height:this.height_}};Dygraph.prototype.setAnnotations=function(b,a){Dygraph.addAnnotationRule();this.annotations_=b;this.layout_.setAnnotations(this.annotations_);if(!a){this.predraw_()}};Dygraph.prototype.annotations=function(){return this.annotations_};Dygraph.prototype.getLabels=function(a){return this.attr_("labels").slice()};Dygraph.prototype.indexFromSetName=function(a){return this.setIndexByName_[a]};Dygraph.addAnnotationRule=function(){if(Dygraph.addedAnnotationCSS){return}var f="border: 1px solid black; background-color: white; text-align: center;";var e=document.createElement("style");e.type="text/css";document.getElementsByTagName("head")[0].appendChild(e);for(var b=0;bb){return -1}if(i===null||i===undefined){i=0}var h=function(j){return j>=0&&ja){if(i>0){f=g-1;if(h(f)&&d[f]a){return g}}return Dygraph.binarySearch(a,d,i,g+1,b)}};Dygraph.dateParser=function(a){var b;var c;c=Dygraph.dateStrToMillis(a);if(c&&!isNaN(c)){return c}if(a.search("-")!=-1){b=a.replace("-","/","g");while(b.search("-")!=-1){b=b.replace("-","/")}c=Dygraph.dateStrToMillis(b)}else{if(a.length==8){b=a.substr(0,4)+"/"+a.substr(4,2)+"/"+a.substr(6,2);c=Dygraph.dateStrToMillis(b)}else{c=Dygraph.dateStrToMillis(a)}}if(!c||isNaN(c)){Dygraph.error("Couldn't parse "+a+" as a date")}return c};Dygraph.dateStrToMillis=function(a){return new Date(a).getTime()};Dygraph.update=function(b,c){if(typeof(c)!="undefined"&&c!==null){for(var a in c){if(c.hasOwnProperty(a)){b[a]=c[a]}}}return b};Dygraph.updateDeep=function(b,d){function c(e){return(typeof Node==="object"?e instanceof Node:typeof e==="object"&&typeof e.nodeType==="number"&&typeof e.nodeName==="string")}if(typeof(d)!="undefined"&&d!==null){for(var a in d){if(d.hasOwnProperty(a)){if(d[a]===null){b[a]=null}else{if(Dygraph.isArrayLike(d[a])){b[a]=d[a].slice()}else{if(c(d[a])){b[a]=d[a]}else{if(typeof(d[a])=="object"){if(typeof(b[a])!="object"){b[a]={}}Dygraph.updateDeep(b[a],d[a])}else{b[a]=d[a]}}}}}}}return b};Dygraph.isArrayLike=function(b){var a=typeof(b);if((a!="object"&&!(a=="function"&&typeof(b.item)=="function"))||b===null||typeof(b.length)!="number"||b.nodeType===3){return false}return true};Dygraph.isDateLike=function(a){if(typeof(a)!="object"||a===null||typeof(a.getTime)!="function"){return false}return true};Dygraph.clone=function(c){var b=[];for(var a=0;a=g){return}var h=d+(1+e)*f;setTimeout(function(){e++;b(e);if(e>=g-1){c()}else{a()}},h-new Date().getTime())})()};Dygraph.isPixelChangingOptionList=function(h,e){var d={annotationClickHandler:true,annotationDblClickHandler:true,annotationMouseOutHandler:true,annotationMouseOverHandler:true,axisLabelColor:true,axisLineColor:true,axisLineWidth:true,clickCallback:true,digitsAfterDecimal:true,drawCallback:true,drawPoints:true,drawXGrid:true,drawYGrid:true,fillAlpha:true,gridLineColor:true,gridLineWidth:true,hideOverlayOnMouseOut:true,highlightCallback:true,highlightCircleSize:true,interactionModel:true,isZoomedIgnoreProgrammaticZoom:true,labelsDiv:true,labelsDivStyles:true,labelsDivWidth:true,labelsKMB:true,labelsKMG2:true,labelsSeparateLines:true,labelsShowZeroValues:true,legend:true,maxNumberWidth:true,panEdgeFraction:true,pixelsPerYLabel:true,pointClickCallback:true,pointSize:true,rangeSelectorPlotFillColor:true,rangeSelectorPlotStrokeColor:true,showLabelsOnHighlight:true,showRoller:true,sigFigs:true,strokeWidth:true,underlayCallback:true,unhighlightCallback:true,xAxisLabelFormatter:true,xTicker:true,xValueFormatter:true,yAxisLabelFormatter:true,yValueFormatter:true,zoomCallback:true};var a=false;var b={};if(h){for(var f=1;fc.boundedDates[1]){h=h-(a-c.boundedDates[1]);a=h+c.dateRange}}k.dateWindow_=[h,a];if(c.is2DPan){for(var j=0;j=10&&a.dragDirection==Dygraph.HORIZONTAL){b.doZoomX_(Math.min(a.dragStartX,a.dragEndX),Math.max(a.dragStartX,a.dragEndX))}else{if(d>=10&&a.dragDirection==Dygraph.VERTICAL){b.doZoomY_(Math.min(a.dragStartY,a.dragEndY),Math.max(a.dragStartY,a.dragEndY))}else{b.clearZoomRect_()}}a.dragStartX=null;a.dragStartY=null};Dygraph.Interaction.defaultModel={mousedown:function(c,b,a){a.initializeMouseDown(c,b,a);if(c.altKey||c.shiftKey){Dygraph.startPan(c,b,a)}else{Dygraph.startZoom(c,b,a)}},mousemove:function(c,b,a){if(a.isZooming){Dygraph.moveZoom(c,b,a)}else{if(a.isPanning){Dygraph.movePan(c,b,a)}}},mouseup:function(c,b,a){if(a.isZooming){Dygraph.endZoom(c,b,a)}else{if(a.isPanning){Dygraph.endPan(c,b,a)}}},mouseout:function(c,b,a){if(a.isZooming){a.dragEndX=null;a.dragEndY=null}},dblclick:function(c,b,a){if(c.altKey||c.shiftKey){return}b.doUnzoom_()}};Dygraph.DEFAULT_ATTRS.interactionModel=Dygraph.Interaction.defaultModel;Dygraph.defaultInteractionModel=Dygraph.Interaction.defaultModel;Dygraph.endZoom=Dygraph.Interaction.endZoom;Dygraph.moveZoom=Dygraph.Interaction.moveZoom;Dygraph.startZoom=Dygraph.Interaction.startZoom;Dygraph.endPan=Dygraph.Interaction.endPan;Dygraph.movePan=Dygraph.Interaction.movePan;Dygraph.startPan=Dygraph.Interaction.startPan;Dygraph.Interaction.nonInteractiveModel_={mousedown:function(c,b,a){a.initializeMouseDown(c,b,a)},mouseup:function(c,b,a){a.dragEndX=b.dragGetX_(c,a);a.dragEndY=b.dragGetY_(c,a);var e=Math.abs(a.dragEndX-a.dragStartX);var d=Math.abs(a.dragEndY-a.dragStartY);if(e<2&&d<2&&b.lastx_!==undefined&&b.lastx_!=-1){Dygraph.Interaction.treatMouseOpAsClick(b,c,a)}}};Dygraph.Interaction.dragIsPanInteractionModel={mousedown:function(c,b,a){a.initializeMouseDown(c,b,a);Dygraph.startPan(c,b,a)},mousemove:function(c,b,a){if(a.isPanning){Dygraph.movePan(c,b,a)}},mouseup:function(c,b,a){if(a.isPanning){Dygraph.endPan(c,b,a)}}};"use strict";var DygraphRangeSelector=function(a){this.isIE_=/MSIE/.test(navigator.userAgent)&&!window.opera;this.isUsingExcanvas_=a.isUsingExcanvas_;this.dygraph_=a;this.createCanvases_();if(this.isUsingExcanvas_){this.createIEPanOverlay_()}this.createZoomHandles_();this.initInteraction_()};DygraphRangeSelector.prototype.addToGraph=function(a,b){this.layout_=b;this.resize_();a.appendChild(this.bgcanvas_);a.appendChild(this.fgcanvas_);a.appendChild(this.leftZoomHandle_);a.appendChild(this.rightZoomHandle_)};DygraphRangeSelector.prototype.renderStaticLayer=function(){this.resize_();this.drawStaticLayer_()};DygraphRangeSelector.prototype.renderInteractiveLayer=function(){if(this.isChangingRange_){return}this.placeZoomHandles_();this.drawInteractiveLayer_()};DygraphRangeSelector.prototype.resize_=function(){function c(d,e){d.style.top=e.y+"px";d.style.left=e.x+"px";d.width=e.w;d.height=e.h;d.style.width=d.width+"px";d.style.height=d.height+"px"}var b=this.layout_.getPlotArea();var a=this.attr_("axisLabelFontSize")+2*this.attr_("axisTickSize");this.canvasRect_={x:b.x,y:b.y+b.h+a+4,w:b.w,h:this.attr_("rangeSelectorHeight")};c(this.bgcanvas_,this.canvasRect_);c(this.fgcanvas_,this.canvasRect_)};DygraphRangeSelector.prototype.attr_=function(a){return this.dygraph_.attr_(a)};DygraphRangeSelector.prototype.createCanvases_=function(){this.bgcanvas_=Dygraph.createCanvas();this.bgcanvas_.className="dygraph-rangesel-bgcanvas";this.bgcanvas_.style.position="absolute";this.bgcanvas_.style.zIndex=9;this.bgcanvas_ctx_=Dygraph.getContext(this.bgcanvas_);this.fgcanvas_=Dygraph.createCanvas();this.fgcanvas_.className="dygraph-rangesel-fgcanvas";this.fgcanvas_.style.position="absolute";this.fgcanvas_.style.zIndex=9;this.fgcanvas_.style.cursor="default";this.fgcanvas_ctx_=Dygraph.getContext(this.fgcanvas_)};DygraphRangeSelector.prototype.createIEPanOverlay_=function(){this.iePanOverlay_=document.createElement("div");this.iePanOverlay_.style.position="absolute";this.iePanOverlay_.style.backgroundColor="white";this.iePanOverlay_.style.filter="alpha(opacity=0)";this.iePanOverlay_.style.display="none";this.iePanOverlay_.style.cursor="move";this.fgcanvas_.appendChild(this.iePanOverlay_)};DygraphRangeSelector.prototype.createZoomHandles_=function(){var a=new Image();a.className="dygraph-rangesel-zoomhandle";a.style.position="absolute";a.style.zIndex=10;a.style.visibility="hidden";a.style.cursor="col-resize";if(/MSIE 7/.test(navigator.userAgent)){a.width=7;a.height=14;a.style.backgroundColor="white";a.style.border="1px solid #333333"}else{a.width=9;a.height=16;a.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAQCAYAAADESFVDAAAAAXNSR0IArs4c6QAAAAZiS0dEANAAzwDP4Z7KegAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB9sHGw0cMqdt1UwAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAaElEQVQoz+3SsRFAQBCF4Z9WJM8KCDVwownl6YXsTmCUsyKGkZzcl7zkz3YLkypgAnreFmDEpHkIwVOMfpdi9CEEN2nGpFdwD03yEqDtOgCaun7sqSTDH32I1pQA2Pb9sZecAxc5r3IAb21d6878xsAAAAAASUVORK5CYII="}this.leftZoomHandle_=a;this.rightZoomHandle_=a.cloneNode(false)};DygraphRangeSelector.prototype.initInteraction_=function(){var i=this;var f=this.isIE_?document:window;var k=0;var p=null;var n=false;var c=false;var j,d,m,g,q,e,r,o,l,b,h;j=function(w){var v=i.dygraph_.xAxisExtremes();var t=(v[1]-v[0])/i.canvasRect_.w;var u=v[0]+(w.leftHandlePos-i.canvasRect_.x)*t;var s=v[0]+(w.rightHandlePos-i.canvasRect_.x)*t;return[u,s]};d=function(s){Dygraph.cancelEvent(s);n=true;k=s.screenX;p=s.target?s.target:s.srcElement;Dygraph.addEvent(f,"mousemove",m);Dygraph.addEvent(f,"mouseup",g);i.fgcanvas_.style.cursor="col-resize"};m=function(w){if(!n){return}var t=w.screenX-k;if(Math.abs(t)<4){return}k=w.screenX;var v=i.getZoomHandleStatus_();var s;if(p==i.leftZoomHandle_){s=v.leftHandlePos+t;s=Math.min(s,v.rightHandlePos-p.width-3);s=Math.max(s,i.canvasRect_.x)}else{s=v.rightHandlePos+t;s=Math.min(s,i.canvasRect_.x+i.canvasRect_.w);s=Math.max(s,v.leftHandlePos+p.width+3)}var u=p.width/2;p.style.left=(s-u)+"px";i.drawInteractiveLayer_();if(!i.isUsingExcanvas_){q()}};g=function(s){if(!n){return}n=false;Dygraph.removeEvent(f,"mousemove",m);Dygraph.removeEvent(f,"mouseup",g);i.fgcanvas_.style.cursor="default";if(i.isUsingExcanvas_){q()}};q=function(){try{var t=i.getZoomHandleStatus_();i.isChangingRange_=true;if(!t.isZoomed){i.dygraph_.doUnzoom_()}else{var s=j(t);i.dygraph_.doZoomXDates_(s[0],s[1])}}finally{i.isChangingRange_=false}};e=function(u){if(i.isUsingExcanvas_){return u.srcElement==i.iePanOverlay_}else{var s;if(u.offsetX!=undefined){s=i.canvasRect_.x+u.offsetX}else{s=u.clientX}var t=i.getZoomHandleStatus_();return(s>t.leftHandlePos&&s=i.canvasRect_.x+i.canvasRect_.w){s=i.canvasRect_.x+i.canvasRect_.w;y=s-x}else{y+=t;s+=t}}var u=i.leftZoomHandle_.width/2;i.leftZoomHandle_.style.left=(y-u)+"px";i.rightZoomHandle_.style.left=(s-u)+"px";i.drawInteractiveLayer_();if(!i.isUsingExcanvas_){b()}};l=function(s){if(!c){return}c=false;Dygraph.removeEvent(f,"mousemove",o);Dygraph.removeEvent(f,"mouseup",l);if(i.isUsingExcanvas_){b()}};b=function(){try{i.isChangingRange_=true;i.dygraph_.dateWindow_=j(i.getZoomHandleStatus_());i.dygraph_.drawGraph_(false)}finally{i.isChangingRange_=false}};h=function(s){if(n||c){return}var t=e(s)?"move":"default";if(t!=i.fgcanvas_.style.cursor){i.fgcanvas_.style.cursor=t}};this.dygraph_.attrs_.interactionModel=Dygraph.Interaction.dragIsPanInteractionModel;this.dygraph_.attrs_.panEdgeFraction=0.0001;var a=window.opera?"mousedown":"dragstart";Dygraph.addEvent(this.leftZoomHandle_,a,d);Dygraph.addEvent(this.rightZoomHandle_,a,d);if(this.isUsingExcanvas_){Dygraph.addEvent(this.iePanOverlay_,"mousedown",r)}else{Dygraph.addEvent(this.fgcanvas_,"mousedown",r);Dygraph.addEvent(this.fgcanvas_,"mousemove",h)}};DygraphRangeSelector.prototype.drawStaticLayer_=function(){var a=this.bgcanvas_ctx_;a.clearRect(0,0,this.canvasRect_.w,this.canvasRect_.h);try{this.drawMiniPlot_()}catch(b){Dygraph.warn(b)}var c=0.5;this.bgcanvas_ctx_.lineWidth=1;a.strokeStyle="gray";a.beginPath();a.moveTo(c,c);a.lineTo(c,this.canvasRect_.h-c);a.lineTo(this.canvasRect_.w-c,this.canvasRect_.h-c);a.lineTo(this.canvasRect_.w-c,c);a.stroke()};DygraphRangeSelector.prototype.drawMiniPlot_=function(){var p=this.attr_("rangeSelectorPlotFillColor");var l=this.attr_("rangeSelectorPlotStrokeColor");if(!p&&!l){return}var m=this.computeCombinedSeriesAndLimits_();var e=m.yMax-m.yMin;var r=this.bgcanvas_ctx_;var f=0.5;var j=this.dygraph_.xAxisExtremes();var b=Math.max(j[1]-j[0],1e-30);var q=(this.canvasRect_.w-f)/b;var o=(this.canvasRect_.h-f)/e;var d=this.canvasRect_.w-f;var h=this.canvasRect_.h-f;r.beginPath();r.moveTo(f,h);for(var g=0;g1&&u[s][1]!=null){l=typeof u[s][1]!="number";if(l){c=[];g=[];for(q=0;q0)){a=Math.min(a,f);b=Math.max(b,f)}}var n=0.25;if(t){b=Dygraph.log10(b);b+=b*n;a=Dygraph.log10(a);for(s=0;sthis.canvasRect_.x||a+1=A/4){for(var t=K;t>=o;t--){var p=Dygraph.PREFERRED_LOG_TICK_VALUES[t];var m=Math.log(p/I)/Math.log(H/I)*w;var G={v:p};if(u===null){u={tickValue:p,pixel_coord:m}}else{if(Math.abs(m-u.pixel_coord)>=C){u={tickValue:p,pixel_coord:m}}else{G.label=""}}J.push(G)}J.reverse()}}if(J.length===0){var h=r("labelsKMG2");var q;if(h){q=[1,2,4,8]}else{q=[1,2,5]}var L,z,c;for(F=-10;F<50;F++){var g;if(h){g=Math.pow(16,F)}else{g=Math.pow(10,F)}var f=0;for(D=0;DC){break}}if(f>C){break}}if(z>c){L*=-1}for(F=0;F0){var x=B*B*B*B;for(D=3;D>=0;D--,x/=B){if(e>=x){l=Dygraph.round_(v/x,r("digitsAfterDecimal"))+y[D];break}}}J[F].label=l}return J};Dygraph.dateTicker=function(e,c,i,g,f,h){var d=Dygraph.pickDateTickGranularity(e,c,i,g);if(d>=0){return Dygraph.getDateAxis(e,c,d,g,f)}else{return[]}};Dygraph.SECONDLY=0;Dygraph.TWO_SECONDLY=1;Dygraph.FIVE_SECONDLY=2;Dygraph.TEN_SECONDLY=3;Dygraph.THIRTY_SECONDLY=4;Dygraph.MINUTELY=5;Dygraph.TWO_MINUTELY=6;Dygraph.FIVE_MINUTELY=7;Dygraph.TEN_MINUTELY=8;Dygraph.THIRTY_MINUTELY=9;Dygraph.HOURLY=10;Dygraph.TWO_HOURLY=11;Dygraph.SIX_HOURLY=12;Dygraph.DAILY=13;Dygraph.WEEKLY=14;Dygraph.MONTHLY=15;Dygraph.QUARTERLY=16;Dygraph.BIANNUAL=17;Dygraph.ANNUAL=18;Dygraph.DECADAL=19;Dygraph.CENTENNIAL=20;Dygraph.NUM_GRANULARITIES=21;Dygraph.SHORT_SPACINGS=[];Dygraph.SHORT_SPACINGS[Dygraph.SECONDLY]=1000*1;Dygraph.SHORT_SPACINGS[Dygraph.TWO_SECONDLY]=1000*2;Dygraph.SHORT_SPACINGS[Dygraph.FIVE_SECONDLY]=1000*5;Dygraph.SHORT_SPACINGS[Dygraph.TEN_SECONDLY]=1000*10;Dygraph.SHORT_SPACINGS[Dygraph.THIRTY_SECONDLY]=1000*30;Dygraph.SHORT_SPACINGS[Dygraph.MINUTELY]=1000*60;Dygraph.SHORT_SPACINGS[Dygraph.TWO_MINUTELY]=1000*60*2;Dygraph.SHORT_SPACINGS[Dygraph.FIVE_MINUTELY]=1000*60*5;Dygraph.SHORT_SPACINGS[Dygraph.TEN_MINUTELY]=1000*60*10;Dygraph.SHORT_SPACINGS[Dygraph.THIRTY_MINUTELY]=1000*60*30;Dygraph.SHORT_SPACINGS[Dygraph.HOURLY]=1000*3600;Dygraph.SHORT_SPACINGS[Dygraph.TWO_HOURLY]=1000*3600*2;Dygraph.SHORT_SPACINGS[Dygraph.SIX_HOURLY]=1000*3600*6;Dygraph.SHORT_SPACINGS[Dygraph.DAILY]=1000*86400;Dygraph.SHORT_SPACINGS[Dygraph.WEEKLY]=1000*604800;Dygraph.PREFERRED_LOG_TICK_VALUES=function(){var c=[];for(var b=-39;b<=39;b++){var a=Math.pow(10,b);for(var d=1;d<=9;d++){var e=a*d;c.push(e)}}return c}();Dygraph.pickDateTickGranularity=function(d,c,j,h){var g=h("pixelsPerLabel");for(var f=0;f=g){return f}}return -1};Dygraph.numDateTicks=function(e,b,g){if(gh){continue}z.push({v:k,label:u(new Date(k),a,l,w)})}}}return z};Dygraph.DEFAULT_ATTRS.axes.x.ticker=Dygraph.dateTicker;Dygraph.DEFAULT_ATTRS.axes.y.ticker=Dygraph.numericTicks;Dygraph.DEFAULT_ATTRS.axes.y2.ticker=Dygraph.numericTicks;"use strict";function RGBColor(f){this.ok=false;if(f.charAt(0)=="#"){f=f.substr(1,6)}f=f.replace(/ /g,"");f=f.toLowerCase();var b={aliceblue:"f0f8ff",antiquewhite:"faebd7",aqua:"00ffff",aquamarine:"7fffd4",azure:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"000000",blanchedalmond:"ffebcd",blue:"0000ff",blueviolet:"8a2be2",brown:"a52a2a",burlywood:"deb887",cadetblue:"5f9ea0",chartreuse:"7fff00",chocolate:"d2691e",coral:"ff7f50",cornflowerblue:"6495ed",cornsilk:"fff8dc",crimson:"dc143c",cyan:"00ffff",darkblue:"00008b",darkcyan:"008b8b",darkgoldenrod:"b8860b",darkgray:"a9a9a9",darkgreen:"006400",darkkhaki:"bdb76b",darkmagenta:"8b008b",darkolivegreen:"556b2f",darkorange:"ff8c00",darkorchid:"9932cc",darkred:"8b0000",darksalmon:"e9967a",darkseagreen:"8fbc8f",darkslateblue:"483d8b",darkslategray:"2f4f4f",darkturquoise:"00ced1",darkviolet:"9400d3",deeppink:"ff1493",deepskyblue:"00bfff",dimgray:"696969",dodgerblue:"1e90ff",feldspar:"d19275",firebrick:"b22222",floralwhite:"fffaf0",forestgreen:"228b22",fuchsia:"ff00ff",gainsboro:"dcdcdc",ghostwhite:"f8f8ff",gold:"ffd700",goldenrod:"daa520",gray:"808080",green:"008000",greenyellow:"adff2f",honeydew:"f0fff0",hotpink:"ff69b4",indianred:"cd5c5c",indigo:"4b0082",ivory:"fffff0",khaki:"f0e68c",lavender:"e6e6fa",lavenderblush:"fff0f5",lawngreen:"7cfc00",lemonchiffon:"fffacd",lightblue:"add8e6",lightcoral:"f08080",lightcyan:"e0ffff",lightgoldenrodyellow:"fafad2",lightgrey:"d3d3d3",lightgreen:"90ee90",lightpink:"ffb6c1",lightsalmon:"ffa07a",lightseagreen:"20b2aa",lightskyblue:"87cefa",lightslateblue:"8470ff",lightslategray:"778899",lightsteelblue:"b0c4de",lightyellow:"ffffe0",lime:"00ff00",limegreen:"32cd32",linen:"faf0e6",magenta:"ff00ff",maroon:"800000",mediumaquamarine:"66cdaa",mediumblue:"0000cd",mediumorchid:"ba55d3",mediumpurple:"9370d8",mediumseagreen:"3cb371",mediumslateblue:"7b68ee",mediumspringgreen:"00fa9a",mediumturquoise:"48d1cc",mediumvioletred:"c71585",midnightblue:"191970",mintcream:"f5fffa",mistyrose:"ffe4e1",moccasin:"ffe4b5",navajowhite:"ffdead",navy:"000080",oldlace:"fdf5e6",olive:"808000",olivedrab:"6b8e23",orange:"ffa500",orangered:"ff4500",orchid:"da70d6",palegoldenrod:"eee8aa",palegreen:"98fb98",paleturquoise:"afeeee",palevioletred:"d87093",papayawhip:"ffefd5",peachpuff:"ffdab9",peru:"cd853f",pink:"ffc0cb",plum:"dda0dd",powderblue:"b0e0e6",purple:"800080",red:"ff0000",rosybrown:"bc8f8f",royalblue:"4169e1",saddlebrown:"8b4513",salmon:"fa8072",sandybrown:"f4a460",seagreen:"2e8b57",seashell:"fff5ee",sienna:"a0522d",silver:"c0c0c0",skyblue:"87ceeb",slateblue:"6a5acd",slategray:"708090",snow:"fffafa",springgreen:"00ff7f",steelblue:"4682b4",tan:"d2b48c",teal:"008080",thistle:"d8bfd8",tomato:"ff6347",turquoise:"40e0d0",violet:"ee82ee",violetred:"d02090",wheat:"f5deb3",white:"ffffff",whitesmoke:"f5f5f5",yellow:"ffff00",yellowgreen:"9acd32"};for(var g in b){if(f==g){f=b[g]}}var e=[{re:/^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,example:["rgb(123, 234, 45)","rgb(255,234,245)"],process:function(i){return[parseInt(i[1]),parseInt(i[2]),parseInt(i[3])]}},{re:/^(\w{2})(\w{2})(\w{2})$/,example:["#00ff00","336699"],process:function(i){return[parseInt(i[1],16),parseInt(i[2],16),parseInt(i[3],16)]}},{re:/^(\w{1})(\w{1})(\w{1})$/,example:["#fb0","f0f"],process:function(i){return[parseInt(i[1]+i[1],16),parseInt(i[2]+i[2],16),parseInt(i[3]+i[3],16)]}}];for(var c=0;c255)?255:this.r);this.g=(this.g<0||isNaN(this.g))?0:((this.g>255)?255:this.g);this.b=(this.b<0||isNaN(this.b))?0:((this.b>255)?255:this.b);this.toRGB=function(){return"rgb("+this.r+", "+this.g+", "+this.b+")"};this.toHex=function(){var l=this.r.toString(16);var k=this.g.toString(16);var i=this.b.toString(16);if(l.length==1){l="0"+l}if(k.length==1){k="0"+k}if(i.length==1){i="0"+i}return"#"+l+k+i}}Date.ext={};Date.ext.util={};Date.ext.util.xPad=function(a,c,b){if(typeof(b)=="undefined"){b=10}for(;parseInt(a,10)1;b/=10){a=c.toString()+a}return a.toString()};Date.prototype.locale="en-GB";if(document.getElementsByTagName("html")&&document.getElementsByTagName("html")[0].lang){Date.prototype.locale=document.getElementsByTagName("html")[0].lang}Date.ext.locales={};Date.ext.locales.en={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],x:"%d/%m/%y",X:"%T"};Date.ext.locales["en-US"]=Date.ext.locales.en;Date.ext.locales["en-US"].c="%a %d %b %Y %r %Z";Date.ext.locales["en-US"].x="%D";Date.ext.locales["en-US"].X="%r";Date.ext.locales["en-GB"]=Date.ext.locales.en;Date.ext.locales["en-AU"]=Date.ext.locales["en-GB"];Date.ext.formats={a:function(a){return Date.ext.locales[a.locale].a[a.getDay()]},A:function(a){return Date.ext.locales[a.locale].A[a.getDay()]},b:function(a){return Date.ext.locales[a.locale].b[a.getMonth()]},B:function(a){return Date.ext.locales[a.locale].B[a.getMonth()]},c:"toLocaleString",C:function(a){return Date.ext.util.xPad(parseInt(a.getFullYear()/100,10),0)},d:["getDate","0"],e:["getDate"," "],g:function(a){return Date.ext.util.xPad(parseInt(Date.ext.util.G(a)/100,10),0)},G:function(c){var e=c.getFullYear();var b=parseInt(Date.ext.formats.V(c),10);var a=parseInt(Date.ext.formats.W(c),10);if(a>b){e++}else{if(a===0&&b>=52){e--}}return e},H:["getHours","0"],I:function(b){var a=b.getHours()%12;return Date.ext.util.xPad(a===0?12:a,0)},j:function(c){var a=c-new Date(""+c.getFullYear()+"/1/1 GMT");a+=c.getTimezoneOffset()*60000;var b=parseInt(a/60000/60/24,10)+1;return Date.ext.util.xPad(b,0,100)},m:function(a){return Date.ext.util.xPad(a.getMonth()+1,0)},M:["getMinutes","0"],p:function(a){return Date.ext.locales[a.locale].p[a.getHours()>=12?1:0]},P:function(a){return Date.ext.locales[a.locale].P[a.getHours()>=12?1:0]},S:["getSeconds","0"],u:function(a){var b=a.getDay();return b===0?7:b},U:function(e){var a=parseInt(Date.ext.formats.j(e),10);var c=6-e.getDay();var b=parseInt((a+c)/7,10);return Date.ext.util.xPad(b,0)},V:function(e){var c=parseInt(Date.ext.formats.W(e),10);var a=(new Date(""+e.getFullYear()+"/1/1")).getDay();var b=c+(a>4||a<=1?0:1);if(b==53&&(new Date(""+e.getFullYear()+"/12/31")).getDay()<4){b=1}else{if(b===0){b=Date.ext.formats.V(new Date(""+(e.getFullYear()-1)+"/12/31"))}}return Date.ext.util.xPad(b,0)},w:"getDay",W:function(e){var a=parseInt(Date.ext.formats.j(e),10);var c=7-Date.ext.formats.u(e);var b=parseInt((a+c)/7,10);return Date.ext.util.xPad(b,0,10)},y:function(a){return Date.ext.util.xPad(a.getFullYear()%100,0)},Y:"getFullYear",z:function(c){var b=c.getTimezoneOffset();var a=Date.ext.util.xPad(parseInt(Math.abs(b/60),10),0);var e=Date.ext.util.xPad(b%60,0);return(b>0?"-":"+")+a+e},Z:function(a){return a.toString().replace(/^.*\(([^)]+)\)$/,"$1")},"%":function(a){return"%"}};Date.ext.aggregates={c:"locale",D:"%m/%d/%y",h:"%b",n:"\n",r:"%I:%M:%S %p",R:"%H:%M",t:"\t",T:"%H:%M:%S",x:"locale",X:"locale"};Date.ext.aggregates.z=Date.ext.formats.z(new Date());Date.ext.aggregates.Z=Date.ext.formats.Z(new Date());Date.ext.unsupported={};Date.prototype.strftime=function(a){if(!(this.locale in Date.ext.locales)){if(this.locale.replace(/-[a-zA-Z]+$/,"") in Date.ext.locales){this.locale=this.locale.replace(/-[a-zA-Z]+$/,"")}else{this.locale="en-GB"}}var c=this;while(a.match(/%[cDhnrRtTxXzZ]/)){a=a.replace(/%([cDhnrRtTxXzZ])/g,function(e,d){var g=Date.ext.aggregates[d];return(g=="locale"?Date.ext.locales[c.locale][d]:g)})}var b=a.replace(/%([aAbBCdegGHIjmMpPSuUVwWyY%])/g,function(e,d){var g=Date.ext.formats[d];if(typeof(g)=="string"){return c[g]()}else{if(typeof(g)=="function"){return g.call(c,c)}else{if(typeof(g)=="object"&&typeof(g[0])=="string"){return Date.ext.util.xPad(c[g[0]](),g[1])}else{return d}}}});c=null;return b}; \ No newline at end of file +/** + * @license + * Copyright 2011 Dan Vanderkam (danvdk@gmail.com) + * MIT-licensed (http://opensource.org/licenses/MIT) + *//** + * @fileoverview Based on PlotKitLayout, but modified to meet the needs of + * dygraphs. + *//*jshint globalstrict: true *//*global Dygraph:false */function RGBColor(a){this.ok=!1,a.charAt(0)=="#"&&(a=a.substr(1,6)),a=a.replace(/ /g,""),a=a.toLowerCase();var b={aliceblue:"f0f8ff",antiquewhite:"faebd7",aqua:"00ffff",aquamarine:"7fffd4",azure:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"000000",blanchedalmond:"ffebcd",blue:"0000ff",blueviolet:"8a2be2",brown:"a52a2a",burlywood:"deb887",cadetblue:"5f9ea0",chartreuse:"7fff00",chocolate:"d2691e",coral:"ff7f50",cornflowerblue:"6495ed",cornsilk:"fff8dc",crimson:"dc143c",cyan:"00ffff",darkblue:"00008b",darkcyan:"008b8b",darkgoldenrod:"b8860b",darkgray:"a9a9a9",darkgreen:"006400",darkkhaki:"bdb76b",darkmagenta:"8b008b",darkolivegreen:"556b2f",darkorange:"ff8c00",darkorchid:"9932cc",darkred:"8b0000",darksalmon:"e9967a",darkseagreen:"8fbc8f",darkslateblue:"483d8b",darkslategray:"2f4f4f",darkturquoise:"00ced1",darkviolet:"9400d3",deeppink:"ff1493",deepskyblue:"00bfff",dimgray:"696969",dodgerblue:"1e90ff",feldspar:"d19275",firebrick:"b22222",floralwhite:"fffaf0",forestgreen:"228b22",fuchsia:"ff00ff",gainsboro:"dcdcdc",ghostwhite:"f8f8ff",gold:"ffd700",goldenrod:"daa520",gray:"808080",green:"008000",greenyellow:"adff2f",honeydew:"f0fff0",hotpink:"ff69b4",indianred:"cd5c5c",indigo:"4b0082",ivory:"fffff0",khaki:"f0e68c",lavender:"e6e6fa",lavenderblush:"fff0f5",lawngreen:"7cfc00",lemonchiffon:"fffacd",lightblue:"add8e6",lightcoral:"f08080",lightcyan:"e0ffff",lightgoldenrodyellow:"fafad2",lightgrey:"d3d3d3",lightgreen:"90ee90",lightpink:"ffb6c1",lightsalmon:"ffa07a",lightseagreen:"20b2aa",lightskyblue:"87cefa",lightslateblue:"8470ff",lightslategray:"778899",lightsteelblue:"b0c4de",lightyellow:"ffffe0",lime:"00ff00",limegreen:"32cd32",linen:"faf0e6",magenta:"ff00ff",maroon:"800000",mediumaquamarine:"66cdaa",mediumblue:"0000cd",mediumorchid:"ba55d3",mediumpurple:"9370d8",mediumseagreen:"3cb371",mediumslateblue:"7b68ee",mediumspringgreen:"00fa9a",mediumturquoise:"48d1cc",mediumvioletred:"c71585",midnightblue:"191970",mintcream:"f5fffa",mistyrose:"ffe4e1",moccasin:"ffe4b5",navajowhite:"ffdead",navy:"000080",oldlace:"fdf5e6",olive:"808000",olivedrab:"6b8e23",orange:"ffa500",orangered:"ff4500",orchid:"da70d6",palegoldenrod:"eee8aa",palegreen:"98fb98",paleturquoise:"afeeee",palevioletred:"d87093",papayawhip:"ffefd5",peachpuff:"ffdab9",peru:"cd853f",pink:"ffc0cb",plum:"dda0dd",powderblue:"b0e0e6",purple:"800080",red:"ff0000",rosybrown:"bc8f8f",royalblue:"4169e1",saddlebrown:"8b4513",salmon:"fa8072",sandybrown:"f4a460",seagreen:"2e8b57",seashell:"fff5ee",sienna:"a0522d",silver:"c0c0c0",skyblue:"87ceeb",slateblue:"6a5acd",slategray:"708090",snow:"fffafa",springgreen:"00ff7f",steelblue:"4682b4",tan:"d2b48c",teal:"008080",thistle:"d8bfd8",tomato:"ff6347",turquoise:"40e0d0",violet:"ee82ee",violetred:"d02090",wheat:"f5deb3",white:"ffffff",whitesmoke:"f5f5f5",yellow:"ffff00",yellowgreen:"9acd32"};for(var c in b)a==c&&(a=b[c]);var d=[{re:/^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,example:["rgb(123, 234, 45)","rgb(255,234,245)"],process:function(a){return[parseInt(a[1]),parseInt(a[2]),parseInt(a[3])]}},{re:/^(\w{2})(\w{2})(\w{2})$/,example:["#00ff00","336699"],process:function(a){return[parseInt(a[1],16),parseInt(a[2],16),parseInt(a[3],16)]}},{re:/^(\w{1})(\w{1})(\w{1})$/,example:["#fb0","f0f"],process:function(a){return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)]}}];for(var e=0;e255?255:this.r,this.g=this.g<0||isNaN(this.g)?0:this.g>255?255:this.g,this.b=this.b<0||isNaN(this.b)?0:this.b>255?255:this.b,this.toRGB=function(){return"rgb("+this.r+", "+this.g+", "+this.b+")"},this.toHex=function(){var a=this.r.toString(16),b=this.g.toString(16),c=this.b.toString(16);return a.length==1&&(a="0"+a),b.length==1&&(b="0"+b),c.length==1&&(c="0"+c),"#"+a+b+c}}"use strict";var DygraphLayout=function(a){this.dygraph_=a,this.datasets=[],this.setNames=[],this.annotations=[],this.yAxes_=null,this.xTicks_=null,this.yTicks_=null};DygraphLayout.prototype.attr_=function(a){return this.dygraph_.attr_(a)},DygraphLayout.prototype.addDataset=function(a,b){this.datasets.push(b),this.setNames.push(a)},DygraphLayout.prototype.getPlotArea=function(){return this.computePlotArea_()},DygraphLayout.prototype.computePlotArea_=function(){var a={x:0,y:0};return this.attr_("drawYAxis")&&(a.x=this.attr_("yAxisLabelWidth")+2*this.attr_("axisTickSize")),a.w=this.dygraph_.width_-a.x-this.attr_("rightGap"),a.h=this.dygraph_.height_,this.attr_("drawXAxis")&&(this.attr_("xAxisHeight")?a.h-=this.attr_("xAxisHeight"):a.h-=this.attr_("axisLabelFontSize")+2*this.attr_("axisTickSize")),this.dygraph_.numAxes()==2?a.w-=this.attr_("yAxisLabelWidth")+2*this.attr_("axisTickSize"):this.dygraph_.numAxes()>2&&this.dygraph_.error("Only two y-axes are supported at this time. (Trying to use "+this.dygraph_.numAxes()+")"),this.attr_("title")&&(a.h-=this.attr_("titleHeight"),a.y+=this.attr_("titleHeight")),this.attr_("xlabel")&&(a.h-=this.attr_("xLabelHeight")),!this.attr_("ylabel"),!this.attr_("y2label"),this.attr_("showRangeSelector")&&(a.h-=this.attr_("rangeSelectorHeight")+4),a},DygraphLayout.prototype.setAnnotations=function(a){this.annotations=[];var b=this.attr_("xValueParser")||function(a){return a};for(var c=0;c1){var c=b[0][0];if(!this.minxval||cthis.maxxval)this.maxxval=d}}this.xrange=this.maxxval-this.minxval,this.xscale=this.xrange!==0?1/this.xrange:1;for(var e=0;e=0&&d<=1&&this.xticks.push([d,c]);this.yticks=[];for(a=0;a=0&&d<=1&&this.yticks.push([a,d,c])}},DygraphLayout.prototype.evaluateWithError=function(){this.evaluate();if(!this.attr_("errorBars")&&!this.attr_("customBars"))return;var a=0;for(var b=0;b=0;c--)b.childNodes[c].className==a&&b.removeChild(b.childNodes[c]);var d=document.bgColor,e=this.dygraph_.graphDiv;while(e!=document){var f=e.currentStyle.backgroundColor;if(f&&f!="transparent"){d=f;break}e=e.parentNode}var h=this.area;g({x:0,y:0,w:h.x,h:this.height}),g({x:h.x,y:0,w:this.width-h.x,h:h.y}),g({x:h.x+h.w,y:0,w:this.width-h.x-h.w,h:this.height}),g({x:h.x,y:h.y+h.h,w:this.width-h.x,h:this.height-h.h-h.y})},DygraphCanvasRenderer.prototype._renderAxis=function(){function a(a){return Math.round(a)+.5}function b(a){return Math.round(a)-.5}if(!this.attr_("drawXAxis")&&!this.attr_("drawYAxis"))return;var c=this.elementContext,d,e,f,g,h,i={position:"absolute",fontSize:this.attr_("axisLabelFontSize")+"px",zIndex:10,color:this.attr_("axisLabelColor"),width:this.attr_("axisLabelWidth")+"px",lineHeight:"normal",overflow:"hidden"},j=function(a,b,c){var d=document.createElement("div");for(var e in i)i.hasOwnProperty(e)&&(d.style[e]=i[e]);var f=document.createElement("div");return f.className="dygraph-axis-label dygraph-axis-label-"+b+(c?" dygraph-axis-label-"+c:""),f.innerHTML=a,d.appendChild(f),d};c.save(),c.strokeStyle=this.attr_("axisLineColor"),c.lineWidth=this.attr_("axisLineWidth");if(this.attr_("drawYAxis")){if(this.layout.yticks&&this.layout.yticks.length>0){var k=this.dygraph_.numAxes();for(h=0;hthis.height?d.style.bottom="0px":d.style.top=n+"px",g[0]===0?(d.style.left=this.area.x-this.attr_("yAxisLabelWidth")-this.attr_("axisTickSize")+"px",d.style.textAlign="right"):g[0]==1&&(d.style.left=this.area.x+this.area.w+this.attr_("axisTickSize")+"px",d.style.textAlign="left"),d.style.width=this.attr_("yAxisLabelWidth")+"px",this.container.appendChild(d),this.ylabels.push(d)}var o=this.ylabels[0],p=this.attr_("axisLabelFontSize"),q=parseInt(o.style.top,10)+p;q>this.height-p&&(o.style.top=parseInt(o.style.top,10)-p/2+"px")}c.beginPath(),c.moveTo(a(this.area.x),b(this.area.y)),c.lineTo(a(this.area.x),b(this.area.y+this.area.h)),c.closePath(),c.stroke(),this.dygraph_.numAxes()==2&&(c.beginPath(),c.moveTo(b(this.area.x+this.area.w),b(this.area.y)),c.lineTo(b(this.area.x+this.area.w),b(this.area.y+this.area.h)),c.closePath(),c.stroke())}if(this.attr_("drawXAxis")){if(this.layout.xticks)for(h=0;hthis.width&&(r=this.width-this.attr_("xAxisLabelWidth"),d.style.textAlign="right"),r<0&&(r=0,d.style.textAlign="left"),d.style.left=r+"px",d.style.width=this.attr_("xAxisLabelWidth")+"px",this.container.appendChild(d),this.xlabels.push(d)}c.beginPath(),c.moveTo(a(this.area.x),b(this.area.y+this.area.h)),c.lineTo(a(this.area.x+this.area.w),b(this.area.y+this.area.h)),c.closePath(),c.stroke()}c.restore()},DygraphCanvasRenderer.prototype._renderChartLabels=function(){function d(d,e,f){var g={left:0,top:c.area.y,width:c.attr_("yLabelWidth"),height:c.area.h};a=document.createElement("div"),a.style.position="absolute",d==1?a.style.left=g.left:a.style.right=g.left,a.style.top=g.top+"px",a.style.width=g.width+"px",a.style.height=g.height+"px",a.style.fontSize=c.attr_("yLabelWidth")-2+"px";var h=document.createElement("div");h.style.position="absolute",h.style.width=g.height+"px",h.style.height=g.width+"px",h.style.top=g.height/2-g.width/2+"px",h.style.left=g.width/2-g.height/2+"px",h.style.textAlign="center";var i="rotate("+(d==1?"-":"")+"90deg)";return h.style.transform=i,h.style.WebkitTransform=i,h.style.MozTransform=i,h.style.OTransform=i,h.style.msTransform=i,typeof document.documentMode!="undefined"&&document.documentMode<9&&(h.style.filter="progid:DXImageTransform.Microsoft.BasicImage(rotation="+(d==1?"3":"1")+")",h.style.left="0px",h.style.top="0px"),b=document.createElement("div"),b.className=e,b.innerHTML=f,h.appendChild(b),a.appendChild(h),a}var a,b;this.attr_("title")&&(a=document.createElement("div"),a.style.position="absolute",a.style.top="0px",a.style.left=this.area.x+"px",a.style.width=this.area.w+"px",a.style.height=this.attr_("titleHeight")+"px",a.style.textAlign="center",a.style.fontSize=this.attr_("titleHeight")-8+"px",a.style.fontWeight="bold",b=document.createElement("div"),b.className="dygraph-label dygraph-title",b.innerHTML=this.attr_("title"),a.appendChild(b),this.container.appendChild(a),this.chartLabels.title=a),this.attr_("xlabel")&&(a=document.createElement("div"),a.style.position="absolute",a.style.bottom=0,a.style.left=this.area.x+"px",a.style.width=this.area.w+"px",a.style.height=this.attr_("xLabelHeight")+"px",a.style.textAlign="center",a.style.fontSize=this.attr_("xLabelHeight")-2+"px",b=document.createElement("div"),b.className="dygraph-label dygraph-xlabel",b.innerHTML=this.attr_("xlabel"),a.appendChild(b),this.container.appendChild(a),this.chartLabels.xlabel=a);var c=this,a;this.attr_("ylabel")&&(a=d(1,"dygraph-label dygraph-ylabel",this.attr_("ylabel")),this.container.appendChild(a),this.chartLabels.ylabel=a),this.attr_("y2label")&&this.dygraph_.numAxes()==2&&(a=d(2,"dygraph-label dygraph-y2label",this.attr_("y2label")),this.container.appendChild(a),this.chartLabels.y2label=a)},DygraphCanvasRenderer.prototype._renderAnnotations=function(){var a={position:"absolute",fontSize:this.attr_("axisLabelFontSize")+"px",zIndex:10,overflow:"hidden"},b=function(a,b,c,d){return function(e){var f=c.annotation;f.hasOwnProperty(a)?f[a](f,c,d.dygraph_,e):d.dygraph_.attr_(b)&&d.dygraph_.attr_(b)(f,c,d.dygraph_,e)}},c=this.layout.annotated_points;for(var d=0;dthis.area.x+this.area.w||e.canvasythis.area.y+this.area.h)continue;var f=e.annotation,g=6;f.hasOwnProperty("tickHeight")&&(g=f.tickHeight);var h=document.createElement("div");for(var i in a)a.hasOwnProperty(i)&&(h.style[i]=a[i]);f.hasOwnProperty("icon")||(h.className="dygraphDefaultAnnotation"),f.hasOwnProperty("cssClass")&&(h.className+=" "+f.cssClass);var j=f.hasOwnProperty("width")?f.width:16,k=f.hasOwnProperty("height")?f.height:16;if(f.hasOwnProperty("icon")){var l=document.createElement("img");l.src=f.icon,l.width=j,l.height=k,h.appendChild(l)}else e.annotation.hasOwnProperty("shortText")&&h.appendChild(document.createTextNode(e.annotation.shortText));h.style.left=e.canvasx-j/2+"px",f.attachAtBottom?h.style.top=this.area.h-k-g+"px":h.style.top=e.canvasy-k-g+"px",h.style.width=j+"px",h.style.height=k+"px",h.title=e.annotation.text,h.style.color=this.colors[e.name],h.style.borderColor=this.colors[e.name],f.div=h,Dygraph.addEvent(h,"click",b("clickHandler","annotationClickHandler",e,this)),Dygraph.addEvent(h,"mouseover",b("mouseOverHandler","annotationMouseOverHandler",e,this)),Dygraph.addEvent(h,"mouseout",b("mouseOutHandler","annotationMouseOutHandler",e,this)),Dygraph.addEvent(h,"dblclick",b("dblClickHandler","annotationDblClickHandler",e,this)),this.container.appendChild(h),this.annotations.push(h);var m=this.elementContext;m.strokeStyle=this.colors[e.name],m.beginPath(),f.attachAtBottom?(m.moveTo(e.canvasx,this.area.h),m.lineTo(e.canvasx,this.area.h-2-g)):(m.moveTo(e.canvasx,e.canvasy),m.lineTo(e.canvasx,e.canvasy-2-g)),m.closePath(),m.stroke()}},DygraphCanvasRenderer.makeNextPointStep_=function(a,b,c){return a?function(a){while(++a=0;j--){p=v[j],o=this.colors[p],u=this.dygraph_.axisPropertiesForSeries(p);var C=1+u.minyval*u.yscale;C<0?C=0:C>1&&(C=1),C=this.area.h*C+this.area.y;var x=this.layout.setPointsOffsets[j],y=this.layout.setPointsLengths[j],z=x+y,A=DygraphCanvasRenderer.makeNextPointStep_(this.attr_("connectSeparatedPoints"),g,z);l=NaN,n=[-1,-1],t=u.yscale,s=new RGBColor(o),r="rgba("+s.r+","+s.g+","+s.b+","+b+")",a.fillStyle=r,a.beginPath();for(k=x;kb)l=f[k],this._dashedLineToHistory[1]?b+=this._dashedLineToHistory[1]:b+=l,b>i?(this._dashedLineToHistory=[k,b-i],b=i):this._dashedLineToHistory=[(k+1)%f.length,0],k%2===0?a.lineTo(b,0):a.moveTo(b,0),k=(k+1)%f.length;a.restore()},"use strict";var Dygraph=function(a,b,c){arguments.length>0&&(arguments.length==4?(this.warn("Using deprecated four-argument dygraph constructor"),this.__old_init__(a,b,arguments[2],arguments[3])):this.__init__(a,b,c))};Dygraph.NAME="Dygraph",Dygraph.VERSION="1.2",Dygraph.__repr__=function(){return"["+this.NAME+" "+this.VERSION+"]"},Dygraph.toString=function(){return this.__repr__()},Dygraph.DEFAULT_ROLL_PERIOD=1,Dygraph.DEFAULT_WIDTH=480,Dygraph.DEFAULT_HEIGHT=320,Dygraph.ANIMATION_STEPS=10,Dygraph.ANIMATION_DURATION=200,Dygraph.numberValueFormatter=function(a,b,c,d){var e=b("sigFigs");if(e!==null)return Dygraph.floatFormat(a,e);var f=b("digitsAfterDecimal"),g=b("maxNumberWidth");return a!==0&&(Math.abs(a)>=Math.pow(10,g)||Math.abs(a)=Dygraph.DECADAL)return a.strftime("%Y");if(b>=Dygraph.MONTHLY)return a.strftime("%b %y");var c=a.getHours()*3600+a.getMinutes()*60+a.getSeconds()+a.getMilliseconds();return c===0||b>=Dygraph.DAILY?(new Date(a.getTime()+36e5)).strftime("%d%b"):Dygraph.hmsString_(a.getTime())},Dygraph.DEFAULT_ATTRS={highlightCircleSize:3,highlightSeriesOpts:null,highlightSeriesBackgroundAlpha:.5,labelsDivWidth:250,labelsDivStyles:{},labelsSeparateLines:!1,labelsShowZeroValues:!0,labelsKMB:!1,labelsKMG2:!1,showLabelsOnHighlight:!0,digitsAfterDecimal:2,maxNumberWidth:6,sigFigs:null,strokeWidth:1,strokeBorderWidth:0,strokeBorderColor:"white",axisTickSize:3,axisLabelFontSize:14,xAxisLabelWidth:50,yAxisLabelWidth:50,rightGap:5,showRoller:!1,xValueParser:Dygraph.dateParser,delimiter:",",sigma:2,errorBars:!1,fractions:!1,wilsonInterval:!0,customBars:!1,fillGraph:!1,fillAlpha:.15,connectSeparatedPoints:!1,stackedGraph:!1,hideOverlayOnMouseOut:!0,legend:"onmouseover",stepPlot:!1,avoidMinZero:!1,titleHeight:28,xLabelHeight:18,yLabelWidth:18,drawXAxis:!0,drawYAxis:!0,axisLineColor:"black",axisLineWidth:.3,gridLineWidth:.3,axisLabelColor:"black",axisLabelFont:"Arial",axisLabelWidth:50,drawYGrid:!0,drawXGrid:!0,gridLineColor:"rgb(128,128,128)",interactionModel:null,animatedZooms:!1,showRangeSelector:!1,rangeSelectorHeight:40,rangeSelectorPlotStrokeColor:"#808FAB",rangeSelectorPlotFillColor:"#A7B1C4",axes:{x:{pixelsPerLabel:60,axisLabelFormatter:Dygraph.dateAxisFormatter,valueFormatter:Dygraph.dateString_,ticker:null},y:{pixelsPerLabel:30,valueFormatter:Dygraph.numberValueFormatter,axisLabelFormatter:Dygraph.numberAxisLabelFormatter,ticker:null},y2:{pixelsPerLabel:30,valueFormatter:Dygraph.numberValueFormatter,axisLabelFormatter:Dygraph.numberAxisLabelFormatter,ticker:null}}},Dygraph.HORIZONTAL=1,Dygraph.VERTICAL=2,Dygraph.addedAnnotationCSS=!1,Dygraph.prototype.__old_init__=function(a,b,c,d){if(c!==null){var e=["Date"];for(var f=0;f=0;--e){var f=c[e];if(f.hasOwnProperty(a)){d=f[a];break}}return d},Dygraph.prototype.optionsViewForAxis_=function(a){var b=this;return function(c){var d=b.user_attrs_.axes;return d&&d[a]&&d[a][c]?d[a][c]:typeof b.user_attrs_[c]!="undefined"?b.user_attrs_[c]:(d=b.attrs_.axes,d&&d[a]&&d[a][c]?d[a][c]:a=="y"&&b.axes_[0].hasOwnProperty(c)?b.axes_[0][c]:a=="y2"&&b.axes_[1].hasOwnProperty(c)?b.axes_[1][c]:b.attr_(c))}},Dygraph.prototype.rollPeriod=function(){return this.rollPeriod_},Dygraph.prototype.xAxisRange=function(){return this.dateWindow_?this.dateWindow_:this.xAxisExtremes()},Dygraph.prototype.xAxisExtremes=function(){var a=this.rawData_[0][0],b=this.rawData_[this.rawData_.length-1][0];return[a,b]},Dygraph.prototype.yAxisRange=function(a){typeof a=="undefined"&&(a=0);if(a<0||a>=this.axes_.length)return null;var b=this.axes_[a];return[b.computedValueRange[0],b.computedValueRange[1]]},Dygraph.prototype.yAxisRanges=function(){var a=[];for(var b=0;b0?[this.rawData_[0][0],this.rawData_[this.numRows()-1][0]]:[0,1]},Dygraph.prototype.getValue=function(a,b){return a<0||a>this.rawData_.length?null:b<0||b>this.rawData_[a].length?null:this.rawData_[a][b]},Dygraph.prototype.createInterface_=function(){var a=this.maindiv_;this.graphDiv=document.createElement("div"),this.graphDiv.style.width=this.width_+"px",this.graphDiv.style.height=this.height_+"px",a.appendChild(this.graphDiv),this.canvas_=Dygraph.createCanvas(),this.canvas_.style.position="absolute",this.canvas_.width=this.width_,this.canvas_.height=this.height_,this.canvas_.style.width=this.width_+"px",this.canvas_.style.height=this.height_+"px",this.canvas_ctx_=Dygraph.getContext(this.canvas_),this.hidden_=this.createPlotKitCanvas_(this.canvas_),this.hidden_ctx_=Dygraph.getContext(this.hidden_),this.attr_("showRangeSelector")&&(this.rangeSelector_=new DygraphRangeSelector(this)),this.graphDiv.appendChild(this.hidden_),this.graphDiv.appendChild(this.canvas_),this.mouseEventElement_=this.createMouseEventElement_(),this.layout_=new DygraphLayout(this),this.rangeSelector_&&this.rangeSelector_.addToGraph(this.graphDiv,this.layout_);var b=this;this.mouseMoveHandler=function(a){b.mouseMove_(a)},Dygraph.addEvent(this.mouseEventElement_,"mousemove",this.mouseMoveHandler),this.mouseOutHandler=function(a){b.mouseOut_(a)},Dygraph.addEvent(this.mouseEventElement_,"mouseout",this.mouseOutHandler),this.createStatusMessage_(),this.createDragInterface_(),this.resizeHandler=function(a){b.resize()},Dygraph.addEvent(window,"resize",this.resizeHandler)},Dygraph.prototype.destroy=function(){var a=function(b){while(b.hasChildNodes())a(b.firstChild),b.removeChild(b.firstChild)};Dygraph.removeEvent(this.mouseEventElement_,"mouseout",this.mouseOutHandler),Dygraph.removeEvent(this.mouseEventElement_,"mousemove",this.mouseMoveHandler),Dygraph.removeEvent(this.mouseEventElement_,"mousemove",this.mouseUpHandler_),a(this.maindiv_);var b=function(a){for(var b in a)typeof a[b]=="object"&&(a[b]=null)};Dygraph.removeEvent(window,"resize",this.resizeHandler),this.resizeHandler=null,b(this.layout_),b(this.plotter_),b(this)},Dygraph.prototype.createPlotKitCanvas_=function(a){var b=Dygraph.createCanvas();return b.style.position="absolute",b.style.top=a.style.top,b.style.left=a.style.left,b.width=this.width_,b.height=this.height_,b.style.width=this.width_+"px",b.style.height=this.height_+"px",b},Dygraph.prototype.createMouseEventElement_=function(){if(this.isUsingExcanvas_){var a=document.createElement("div");return a.style.position="absolute",a.style.backgroundColor="white",a.style.filter="alpha(opacity=0)",a.style.width=this.width_+"px",a.style.height=this.height_+"px",this.graphDiv.appendChild(a),a}return this.canvas_},Dygraph.prototype.setColors_=function(){var a=this.attr_("labels").length-1;this.colors_=[];var b=this.attr_("colors"),c;if(!b){var d=this.attr_("colorSaturation")||1,e=this.attr_("colorValue")||.5,f=Math.ceil(a/2);for(c=1;c<=a;c++){if(!this.visibility()[c-1])continue;var g=c%2?Math.ceil(c/2):f+c/2,h=1*g/(1+a);this.colors_.push(Dygraph.hsvToRGB(h,d,e))}}else for(c=0;c=k)continue;var l=f[j+e];if(!Dygraph.isValidPoint(l))continue;var m=l.canvasy;if(a>l.canvasx&&e+10){var p=(a-l.canvasx)/o;m+=p*(n.canvasy-l.canvasy)}}}else if(a0){var q=f[j+e-1];if(Dygraph.isValidPoint(q)){var o=l.canvasx-q.canvasx;if(o>0){var p=(l.canvasx-a)/o;m+=p*(q.canvasy-l.canvasy)}}}if(i==0||m';else{for(e=0;e<=a.length;e++)i+=a[e%a.length];l=Math.floor(c/(i-a[0]));if(l>1){for(e=0;e'}return d},Dygraph.prototype.generateLegendHTML_=function(a,b,c){var d,e,f,g,h,i;if(typeof a=="undefined"){if(this.attr_("legend")!="always")return"";e=this.attr_("labelsSeparateLines");var j=this.attr_("labels");d="";for(f=1;f":" "),i=this.attr_("strokePattern",j[f]),h=this.generateLegendDashHTML_(i,g,c),d+=""+h+" "+j[f]+""}return d}var k=this.optionsViewForAxis_("x"),l=k("valueFormatter");d=l(a,k,this.attr_("labels")[0],this)+":";var m=[],n=this.numAxes();for(f=0;f");var q=m[this.seriesToAxisMap_[p.name]],r=q("valueFormatter");g=this.plotter_.colors[p.name];var s=r(p.yval,q,p.name,this),t=p.name==this.highlightSet_?" class='highlight'":"";d+=""+" "+p.name+":"+s+""}return d},Dygraph.prototype.setLegendHTML_=function(a,b){var c=this.attr_("labelsDiv");if(!c)return;var d=document.createElement("span");d.setAttribute("style","margin: 0; padding: 0 0 0 1em; border: 0;"),c.appendChild(d);var e=d.offsetWidth,f=this.generateLegendHTML_(a,b,e);c!==null?c.innerHTML=f:typeof this.shown_legend_error_=="undefined"&&(this.error("labelsDiv is set to something nonexistent; legend will not be shown."),this.shown_legend_error_=!0)},Dygraph.prototype.animateSelection_=function(a){var b=10,c=30;this.fadeLevel===undefined&&(this.fadeLevel=0),this.animateId===undefined&&(this.animateId=0);var d=this.fadeLevel,e=a<0?d:b-d;if(e<=0){this.fadeLevel&&this.updateSelection_(1);return}var f=++this.animateId,g=this;Dygraph.repeatAndCleanup(function(c){if(g.animateId!=f)return;g.fadeLevel+=a,g.fadeLevel===0?g.clearSelection():g.updateSelection_(g.fadeLevel/b)},e,c,function(){})},Dygraph.prototype.updateSelection_=function(a){var b,c=this.canvas_ctx_;if(this.attr_("highlightSeriesOpts")){c.clearRect(0,0,this.width_,this.height_);var d=1-this.attr_("highlightSeriesBackgroundAlpha");if(d){var e=!0;if(e){if(a===undefined){this.animateSelection_(1);return}d*=a}c.fillStyle="rgba(255,255,255,"+d+")",c.fillRect(0,0,this.width_,this.height_)}var f=this.datasetIndexFromSetName_(this.highlightSet_);this.plotter_._drawLine(c,f)}else if(this.previousVerticalX_>=0){var g=0,h=this.attr_("labels");for(b=1;bg&&(g=i)}var j=this.previousVerticalX_;c.clearRect(j-g-1,0,2*g+2,this.height_)}this.isUsingExcanvas_&&this.currentZoomRectArgs_&&Dygraph.prototype.drawZoomRect_.apply(this,this.currentZoomRectArgs_);if(this.selPoints_.length>0){this.attr_("showLabelsOnHighlight")&&this.setLegendHTML_(this.lastx_,this.selPoints_);var k=this.selPoints_[0].canvasx;c.save();for(b=0;b=0){a!=this.lastRow_&&(d=!0),this.lastRow_=a;for(var e=0;e=0&&(d=!0),this.lastRow_=-1;return this.selPoints_.length?this.lastx_=this.selPoints_[0].xval:this.lastx_=-1,b!==undefined&&(this.highlightSet_!==b&&(d=!0),this.highlightSet_=b),d&&this.updateSelection_(undefined),d},Dygraph.prototype.mouseOut_=function(a){this.attr_("unhighlightCallback")&&this.attr_("unhighlightCallback")(a),this.attr_("hideOverlayOnMouseOut")&&this.clearSelection()},Dygraph.prototype.clearSelection=function(){if(this.fadeLevel){this.animateSelection_(-1);return}this.canvas_ctx_.clearRect(0,0,this.width_,this.height_),this.fadeLevel=0,this.setLegendHTML_(),this.selPoints_=[],this.lastx_=-1,this.lastRow_=-1,this.highlightSet_=null},Dygraph.prototype.getSelection=function(){if(!this.selPoints_||this.selPoints_.length<1)return-1;for(var a=0;ae&&(g=e),hc)c=h;if(b===null||gc)c=e;if(b===null||e=1;g--){if(!this.visibility()[g-1])continue;var k=[];for(h=0;h=m&&p===null&&(p=i),k[i][0]<=n&&(q=i);p===null&&(p=0),p>0&&p--,q===null&&(q=k.length-1),qr[1]&&(r[1]=d[u]),d[u]=0;--i){if(!e[i])continue;for(h=0;h=0;g--){if(!e[g])continue;e[g][h][1]=NaN}}break}return[e,f,c]},Dygraph.prototype.drawGraph_=function(a){var b=new Date;typeof a=="undefined"&&(a=!0);var c=this.is_initial_draw_;this.is_initial_draw_=!1,this.layout_.removeAllDatasets(),this.setColors_(),this.attrs_.pointSize=.5*this.attr_("highlightCircleSize");var d=this.gatherDatasets_(this.rolledSeries_,this.dateWindow_),e=d[0],f=d[1];this.boundaryIds_=d[2],this.setIndexByName_={};var g=this.attr_("labels");g.length>0&&(this.setIndexByName_[g[0]]=0);var h=0;for(var i=1;ia&&(a=c)}return 1+a},Dygraph.prototype.axisPropertiesForSeries=function(a){return this.axes_[this.seriesToAxisMap_[a]]},Dygraph.prototype.computeYAxisRanges_=function(a){var b=[],c;for(c in this.seriesToAxisMap_){if(!this.seriesToAxisMap_.hasOwnProperty(c))continue;var d=this.seriesToAxisMap_[c];while(b.length<=d)b.push([]);b[d].push(c)}for(var e=0;e0&&(g=0),g==Infinity&&(g=0),h==-Infinity&&(h=1);var l=h-g;l===0&&(l=h);var m,n;f.logscale?(m=h+.1*l,n=g):(m=h+.1*l,n=g-.1*l,this.attr_("avoidMinZero")||(n<0&&g>=0&&(n=0),m>0&&h<=0&&(m=0)),this.attr_("includeZero")&&(h<0&&(m=0),g>0&&(n=0))),f.extremeRange=[n,m]}f.valueWindow?f.computedValueRange=[f.valueWindow[0],f.valueWindow[1]]:f.valueRange?f.computedValueRange=[f.valueRange[0],f.valueRange[1]]:f.computedValueRange=f.extremeRange;var o=this.optionsViewForAxis_("y"+(e?"2":"")),p=o("ticker");if(e===0||f.independentTicks)f.ticks=p(f.computedValueRange[0],f.computedValueRange[1],this.height_,o,this);else{var q=this.axes_[0],r=q.ticks,s=q.computedValueRange[1]-q.computedValueRange[0],t=f.computedValueRange[1]-f.computedValueRange[0],u=[];for(var v=0;v=0&&(m-=a[g-b][1][0],n-=a[g-b][1][1]);var p=a[g][0],q=n?m/n:0;if(this.attr_("errorBars"))if(this.attr_("wilsonInterval"))if(n){var r=q<0?0:q,s=n,t=d*Math.sqrt(r*(1-r)/s+d*d/(4*s*s)),u=1+d*d/n;e=(r+d*d/(2*n)-t)/u,f=(r+d*d/(2*n)+t)/u,c[g]=[p,[r*o,(r-e)*o,(f-r)*o]]}else c[g]=[p,[0,0,0]];else l=n?d*Math.sqrt(q*(1-q)/n):1,c[g]=[p,[o*q,o*l,o*l]];else c[g]=[p,o*q]}}else if(this.attr_("customBars")){e=0;var v=0;f=0;var w=0;for(g=0;g=0){var y=a[g-b];y[1][1]!==null&&!isNaN(y[1][1])&&(e-=y[1][0],v-=y[1][1],f-=y[1][2],w-=1)}w?c[g]=[a[g][0],[1*v/w,1*(v-e)/w,1*(f-v)/w]]:c[g]=[a[g][0],[null,null,null]]}}else if(!this.attr_("errorBars")){if(b==1)return a;for(g=0;g0&&a[c-1]!="e"&&a[c-1]!="E"||a.indexOf("/")>=0||isNaN(parseFloat(a))?b=!0:a.length==8&&a>"19700101"&&a<"20371231"&&(b=!0),b?(this.attrs_.xValueParser=Dygraph.dateParser,this.attrs_.axes.x.valueFormatter=Dygraph.dateString_,this.attrs_.axes.x.ticker=Dygraph.dateTicker,this.attrs_.axes.x.axisLabelFormatter=Dygraph.dateAxisFormatter):(this.attrs_.xValueParser=function(a){return parseFloat(a)},this.attrs_.axes.x.valueFormatter=function(a){return a},this.attrs_.axes.x.ticker=Dygraph.numericLinearTicks,this.attrs_.axes.x.axisLabelFormatter=this.attrs_.axes.x.valueFormatter)},Dygraph.prototype.parseFloat_=function(a,b,c){var d=parseFloat(a);if(!isNaN(d))return d;if(/^ *$/.test(a))return null;if(/^ *nan *$/i.test(a))return NaN;var e="Unable to parse '"+a+"' as a number";return c!==null&&b!==null&&(e+=" on line "+(1+b)+" ('"+c+"') of CSV."),this.error(e),null},Dygraph.prototype.parseCSV_=function(a){var b=[],c=a.split("\n"),d,e,f=this.attr_("delimiter");c[0].indexOf(f)==-1&&c[0].indexOf(" ")>=0&&(f=" ");var g=0;"labels"in this.user_attrs_||(g=1,this.attrs_.labels=c[0].split(f));var h=0,i,j=!1,k=this.attr_("labels").length,l=!1;for(var m=g;m0&&p[0]0)b=String.fromCharCode(65+(a-1)%26)+b.toLowerCase(),a=Math.floor((a-1)/26);return b},c=a.getNumberOfColumns(),d=a.getNumberOfRows(),e=a.getColumnType(0);if(e=="date"||e=="datetime")this.attrs_.xValueParser=Dygraph.dateParser,this.attrs_.axes.x.valueFormatter=Dygraph.dateString_,this.attrs_.axes.x.ticker=Dygraph.dateTicker,this.attrs_.axes.x.axisLabelFormatter=Dygraph.dateAxisFormatter;else{if(e!="number")return this.error("only 'date', 'datetime' and 'number' types are supported for column 1 of DataTable input (Got '"+e+"')"),null;this.attrs_.xValueParser=function(a){return parseFloat(a)},this.attrs_.axes.x.valueFormatter=function(a){return a},this.attrs_.axes.x.ticker=Dygraph.numericLinearTicks,this.attrs_.axes.x.axisLabelFormatter=this.attrs_.axes.x.valueFormatter}var f=[],g={},h=!1,i,j;for(i=1;i0&&q[0]0&&this.setAnnotations(p,!0)},Dygraph.prototype.start_=function(){var a=this.file_;typeof a=="function"&&(a=a());if(Dygraph.isArrayLike(a))this.rawData_=this.parseArray_(a),this.predraw_();else if(typeof a=="object"&&typeof a.getColumnRange=="function")this.parseDataTable_(a),this.predraw_();else if(typeof a=="string")if(a.indexOf("\n")>=0)this.loadedEvent_(a);else{var b=new XMLHttpRequest,c=this;b.onreadystatechange=function(){b.readyState==4&&(b.status===200||b.status===0)&&c.loadedEvent_(b.responseText)},b.open("GET",a,!0),b.send(null)}else this.error("Unknown data format: "+typeof a)},Dygraph.prototype.updateOptions=function(a,b){typeof b=="undefined"&&(b=!1);var c=a.file,d=Dygraph.mapLegacyOptions_(a);"rollPeriod"in d&&(this.rollPeriod_=d.rollPeriod),"dateWindow"in d&&(this.dateWindow_=d.dateWindow,"isZoomedIgnoreProgrammaticZoom"in d||(this.zoomed_x_=d.dateWindow!==null)),"valueRange"in d&&!("isZoomedIgnoreProgrammaticZoom"in d)&&(this.zoomed_y_=d.valueRange!==null);var e=Dygraph.isPixelChangingOptionList(this.attr_("labels"),d);Dygraph.updateDeep(this.user_attrs_,d),c?(this.file_=c,b||this.start_()):b||(e?this.predraw_():this.renderGraph_(!1,!1))},Dygraph.mapLegacyOptions_=function(a){var b={};for(var c in a){if(c=="file")continue;a.hasOwnProperty(c)&&(b[c]=a[c])}var d=function(a,c,d){b.axes||(b.axes={}),b.axes[a]||(b.axes[a]={}),b.axes[a][c]=d},e=function(c,e,f){typeof a[c]!="undefined"&&(d(e,f,a[c]),delete b[c])};return e("xValueFormatter","x","valueFormatter"),e("pixelsPerXLabel","x","pixelsPerLabel"),e("xAxisLabelFormatter","x","axisLabelFormatter"),e("xTicker","x","ticker"),e("yValueFormatter","y","valueFormatter"),e("pixelsPerYLabel","y","pixelsPerLabel"),e("yAxisLabelFormatter","y","axisLabelFormatter"),e("yTicker","y","ticker"),b},Dygraph.prototype.resize=function(a,b){if(this.resize_lock)return;this.resize_lock=!0,a===null!=(b===null)&&(this.warn("Dygraph.resize() should be called with zero parameters or two non-NULL parameters. Pretending it was zero."),a=b=null);var c=this.width_,d=this.height_;a?(this.maindiv_.style.width=a+"px",this.maindiv_.style.height=b+"px",this.width_=a,this.height_=b):(this.width_=this.maindiv_.clientWidth,this.height_=this.maindiv_.clientHeight);if(c!=this.width_||d!=this.height_)this.maindiv_.innerHTML="",this.roller_=null,this.attrs_.labelsDiv=null,this.createInterface_(),this.annotations_.length&&this.layout_.setAnnotations(this.annotations_),this.predraw_();this.resize_lock=!1},Dygraph.prototype.adjustRoll=function(a){this.rollPeriod_=a,this.predraw_()},Dygraph.prototype.visibility=function(){this.attr_("visibility")||(this.attrs_.visibility=[]);while(this.attr_("visibility").length=c.length?this.warn("invalid series number in setVisibility: "+a):(c[a]=b,this.predraw_())},Dygraph.prototype.size=function(){return{width:this.width_,height:this.height_}},Dygraph.prototype.setAnnotations=function(a,b){Dygraph.addAnnotationRule(),this.annotations_=a,this.layout_.setAnnotations(this.annotations_),b||this.predraw_()},Dygraph.prototype.annotations=function(){return this.annotations_},Dygraph.prototype.getLabels=function(a){return this.attr_("labels").slice()},Dygraph.prototype.indexFromSetName=function(a){return this.setIndexByName_[a]},Dygraph.prototype.datasetIndexFromSetName_=function(a){return this.datasetIndex_[this.indexFromSetName(a)]},Dygraph.addAnnotationRule=function(){if(Dygraph.addedAnnotationCSS)return;var a="border: 1px solid black; background-color: white; text-align: center;",b=document.createElement("style");b.type="text/css",document.getElementsByTagName("head")[0].appendChild(b);for(var c=0;ce)return-1;if(c===null||c===undefined)c=0;var f=function(a){return a>=0&&aa){if(c>0){i=g-1;if(f(i)&&b[i]a)return g}return Dygraph.binarySearch(a,b,c,g+1,e)}},Dygraph.dateParser=function(a){var b,c;if(a.search("-")==-1||a.search("T")!=-1||a.search("Z")!=-1){c=Dygraph.dateStrToMillis(a);if(c&&!isNaN(c))return c}if(a.search("-")!=-1){b=a.replace("-","/","g");while(b.search("-")!=-1)b=b.replace("-","/");c=Dygraph.dateStrToMillis(b)}else a.length==8?(b=a.substr(0,4)+"/"+a.substr(4,2)+"/"+a.substr(6,2),c=Dygraph.dateStrToMillis(b)):c=Dygraph.dateStrToMillis(a);return(!c||isNaN(c))&&Dygraph.error("Couldn't parse "+a+" as a date"),c},Dygraph.dateStrToMillis=function(a){return(new Date(a)).getTime()},Dygraph.update=function(a,b){if(typeof b!="undefined"&&b!==null)for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a},Dygraph.updateDeep=function(a,b){function c(a){return typeof Node=="object"?a instanceof Node:typeof a=="object"&&typeof a.nodeType=="number"&&typeof a.nodeName=="string"}if(typeof b!="undefined"&&b!==null)for(var d in b)b.hasOwnProperty(d)&&(b[d]===null?a[d]=null:Dygraph.isArrayLike(b[d])?a[d]=b[d].slice():c(b[d])?a[d]=b[d]:typeof b[d]=="object"?(typeof a[d]!="object"&&(a[d]={}),Dygraph.updateDeep(a[d],b[d])):a[d]=b[d]);return a},Dygraph.isArrayLike=function(a){var b=typeof a;return b!="object"&&(b!="function"||typeof a.item!="function")||a===null||typeof a.length!="number"||a.nodeType===3?!1:!0},Dygraph.isDateLike=function(a){return typeof a!="object"||a===null||typeof a.getTime!="function"?!1:!0},Dygraph.clone=function(a){var b=[];for(var c=0;c=b)return;var h=f+(1+e)*c;setTimeout(function(){e++,a(e),e>=b-1?d():g()},h-(new Date).getTime())})()},Dygraph.isPixelChangingOptionList=function(a,b){var c={annotationClickHandler:!0,annotationDblClickHandler:!0,annotationMouseOutHandler:!0,annotationMouseOverHandler:!0,axisLabelColor:!0,axisLineColor:!0,axisLineWidth:!0,clickCallback:!0,digitsAfterDecimal:!0,drawCallback:!0,drawHighlightPointCallback:!0,drawPoints:!0,drawPointCallback:!0,drawXGrid:!0,drawYGrid:!0,fillAlpha:!0,gridLineColor:!0,gridLineWidth:!0,hideOverlayOnMouseOut:!0,highlightCallback:!0,highlightCircleSize:!0,interactionModel:!0,isZoomedIgnoreProgrammaticZoom:!0,labelsDiv:!0,labelsDivStyles:!0,labelsDivWidth:!0,labelsKMB:!0,labelsKMG2:!0,labelsSeparateLines:!0,labelsShowZeroValues:!0,legend:!0,maxNumberWidth:!0,panEdgeFraction:!0,pixelsPerYLabel:!0,pointClickCallback:!0,pointSize:!0,rangeSelectorPlotFillColor:!0,rangeSelectorPlotStrokeColor:!0,showLabelsOnHighlight:!0,showRoller:!0,sigFigs:!0,strokeWidth:!0,underlayCallback:!0,unhighlightCallback:!0,xAxisLabelFormatter:!0,xTicker:!0,xValueFormatter:!0,yAxisLabelFormatter:!0,yValueFormatter:!0,zoomCallback:!0},d=!1,e={};if(a)for(var f=1;fc.boundedDates[1]&&(d-=e-c.boundedDates[1],e=d+c.dateRange),b.dateWindow_=[d,e];if(c.is2DPan)for(var f=0;f=10&&c.dragDirection==Dygraph.HORIZONTAL?(b.doZoomX_(Math.min(c.dragStartX,c.dragEndX),Math.max(c.dragStartX,c.dragEndX)),c.cancelNextDblclick=!0):e>=10&&c.dragDirection==Dygraph.VERTICAL?(b.doZoomY_(Math.min(c.dragStartY,c.dragEndY),Math.max(c.dragStartY,c.dragEndY)),c.cancelNextDblclick=!0):b.clearZoomRect_(),c.dragStartX=null,c.dragStartY=null},Dygraph.Interaction.startTouch=function(a,b,c){a.preventDefault();var d=[];for(var e=0;e90&&(g=90-g),c.touchDirections={x:g<67.5,y:g>22.5}}c.initialRange={x:b.xAxisRange(),y:b.yAxisRange()}},Dygraph.Interaction.moveTouch=function(a,b,c){var d,e=[];for(d=0;dd.leftHandlePos&&c=a.canvasRect_.x+a.canvasRect_.w?(h=a.canvasRect_.x+a.canvasRect_.w,g=h-i):(g+=d,h+=d);var j=a.leftZoomHandle_.width/2;a.leftZoomHandle_.style.left=g-j+"px",a.rightZoomHandle_.style.left=h-j+"px",a.drawInteractiveLayer_(),a.isUsingExcanvas_||p()},o=function(c){if(!f)return;f=!1,Dygraph.removeEvent(b,"mousemove",n),Dygraph.removeEvent(b,"mouseup",o),a.isUsingExcanvas_&&p()},p=function(){try{a.isChangingRange_=!0,a.dygraph_.dateWindow_=g(a.getZoomHandleStatus_()),a.dygraph_.drawGraph_(!1)}finally{a.isChangingRange_=!1}},q=function(b){if(e||f)return;var c=l(b)?"move":"default";c!=a.fgcanvas_.style.cursor&&(a.fgcanvas_.style.cursor=c)},this.dygraph_.attrs_.interactionModel=Dygraph.Interaction.dragIsPanInteractionModel,this.dygraph_.attrs_.panEdgeFraction=1e-4;var r=window.opera?"mousedown":"dragstart";Dygraph.addEvent(this.leftZoomHandle_,r,h),Dygraph.addEvent(this.rightZoomHandle_,r,h),this.isUsingExcanvas_?Dygraph.addEvent(this.iePanOverlay_,"mousedown",m):(Dygraph.addEvent(this.fgcanvas_,"mousedown",m),Dygraph.addEvent(this.fgcanvas_,"mousemove",q))},DygraphRangeSelector.prototype.drawStaticLayer_=function(){var a=this.bgcanvas_ctx_;a.clearRect(0,0,this.canvasRect_.w,this.canvasRect_.h);try{this.drawMiniPlot_()}catch(b){Dygraph.warn(b)}var c=.5;this.bgcanvas_ctx_.lineWidth=1,a.strokeStyle="gray",a.beginPath(),a.moveTo(c,c),a.lineTo(c,this.canvasRect_.h-c),a.lineTo(this.canvasRect_.w-c,this.canvasRect_.h-c),a.lineTo(this.canvasRect_.w-c,c),a.stroke()},DygraphRangeSelector.prototype.drawMiniPlot_=function(){var a=this.attr_("rangeSelectorPlotFillColor"),b=this.attr_("rangeSelectorPlotStrokeColor");if(!a&&!b)return;var c=this.computeCombinedSeriesAndLimits_(),d=c.yMax-c.yMin,e=this.bgcanvas_ctx_,f=.5,g=this.dygraph_.xAxisExtremes(),h=Math.max(g[1]-g[0],1e-30),i=(this.canvasRect_.w-f)/h,j=(this.canvasRect_.h-f)/d,k=this.canvasRect_.w-f,l=this.canvasRect_.h-f;e.beginPath(),e.moveTo(f,l);for(var m=0;m1&&a[i][1]!=null){h=typeof a[i][1]!="number";if(h){d=[],e=[];for(k=0;k0)&&(n=Math.min(n,f),o=Math.max(o,f));var p=.25;if(b){o=Dygraph.log10(o),o+=o*p,n=Dygraph.log10(n);for(i=0;ithis.canvasRect_.x||c+1=l/4){for(var p=n;p>=m;p--){var q=Dygraph.PREFERRED_LOG_TICK_VALUES[p],r=Math.log(q/a)/Math.log(b/a)*c,s={v:q};o===null?o={tickValue:q,pixel_coord:r}:Math.abs(r-o.pixel_coord)>=g?o={tickValue:q,pixel_coord:r}:s.label="",h.push(s)}h.reverse()}}if(h.length===0){var t=d("labelsKMG2"),u;t?u=[1,2,4,8]:u=[1,2,5];var v,w,x;for(i=-10;i<50;i++){var y;t?y=Math.pow(16,i):y=Math.pow(10, +i);var z=0;for(j=0;jg)break}if(z>g)break}w>x&&(v*=-1);for(i=0;i0){var F=Math.pow(A,B.length);for(j=B.length-1;j>=0;j--,F/=A)if(D>=F){E=Dygraph.round_(k/F,d("digitsAfterDecimal"))+B[j];break}}h[i].label=E}return h},Dygraph.dateTicker=function(a,b,c,d,e,f){var g=Dygraph.pickDateTickGranularity(a,b,c,d);return g>=0?Dygraph.getDateAxis(a,b,g,d,e):[]},Dygraph.SECONDLY=0,Dygraph.TWO_SECONDLY=1,Dygraph.FIVE_SECONDLY=2,Dygraph.TEN_SECONDLY=3,Dygraph.THIRTY_SECONDLY=4,Dygraph.MINUTELY=5,Dygraph.TWO_MINUTELY=6,Dygraph.FIVE_MINUTELY=7,Dygraph.TEN_MINUTELY=8,Dygraph.THIRTY_MINUTELY=9,Dygraph.HOURLY=10,Dygraph.TWO_HOURLY=11,Dygraph.SIX_HOURLY=12,Dygraph.DAILY=13,Dygraph.WEEKLY=14,Dygraph.MONTHLY=15,Dygraph.QUARTERLY=16,Dygraph.BIANNUAL=17,Dygraph.ANNUAL=18,Dygraph.DECADAL=19,Dygraph.CENTENNIAL=20,Dygraph.NUM_GRANULARITIES=21,Dygraph.SHORT_SPACINGS=[],Dygraph.SHORT_SPACINGS[Dygraph.SECONDLY]=1e3,Dygraph.SHORT_SPACINGS[Dygraph.TWO_SECONDLY]=2e3,Dygraph.SHORT_SPACINGS[Dygraph.FIVE_SECONDLY]=5e3,Dygraph.SHORT_SPACINGS[Dygraph.TEN_SECONDLY]=1e4,Dygraph.SHORT_SPACINGS[Dygraph.THIRTY_SECONDLY]=3e4,Dygraph.SHORT_SPACINGS[Dygraph.MINUTELY]=6e4,Dygraph.SHORT_SPACINGS[Dygraph.TWO_MINUTELY]=12e4,Dygraph.SHORT_SPACINGS[Dygraph.FIVE_MINUTELY]=3e5,Dygraph.SHORT_SPACINGS[Dygraph.TEN_MINUTELY]=6e5,Dygraph.SHORT_SPACINGS[Dygraph.THIRTY_MINUTELY]=18e5,Dygraph.SHORT_SPACINGS[Dygraph.HOURLY]=36e5,Dygraph.SHORT_SPACINGS[Dygraph.TWO_HOURLY]=72e5,Dygraph.SHORT_SPACINGS[Dygraph.SIX_HOURLY]=216e5,Dygraph.SHORT_SPACINGS[Dygraph.DAILY]=864e5,Dygraph.SHORT_SPACINGS[Dygraph.WEEKLY]=6048e5,Dygraph.PREFERRED_LOG_TICK_VALUES=function(){var a=[];for(var b=-39;b<=39;b++){var c=Math.pow(10,b);for(var d=1;d<=9;d++){var e=c*d;a.push(e)}}return a}(),Dygraph.pickDateTickGranularity=function(a,b,c,d){var e=d("pixelsPerLabel");for(var f=0;f=e)return f}return-1},Dygraph.numDateTicks=function(a,b,c){if(cb)continue;g.push({v:h,label:f(new Date(h),c,d,e)})}}}return g},Dygraph.DEFAULT_ATTRS.axes.x.ticker=Dygraph.dateTicker,Dygraph.DEFAULT_ATTRS.axes.y.ticker=Dygraph.numericTicks,Dygraph.DEFAULT_ATTRS.axes.y2.ticker=Dygraph.numericTicks,"use strict",Date.ext={},Date.ext.util={},Date.ext.util.xPad=function(a,b,c){typeof c=="undefined"&&(c=10);for(;parseInt(a,10)1;c/=10)a=b.toString()+a;return a.toString()},Date.prototype.locale="en-GB",document.getElementsByTagName("html")&&document.getElementsByTagName("html")[0].lang&&(Date.prototype.locale=document.getElementsByTagName("html")[0].lang),Date.ext.locales={},Date.ext.locales.en={a:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],A:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],b:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],B:["January","February","March","April","May","June","July","August","September","October","November","December"],c:"%a %d %b %Y %T %Z",p:["AM","PM"],P:["am","pm"],x:"%d/%m/%y",X:"%T"},Date.ext.locales["en-US"]=Date.ext.locales.en,Date.ext.locales["en-US"].c="%a %d %b %Y %r %Z",Date.ext.locales["en-US"].x="%D",Date.ext.locales["en-US"].X="%r",Date.ext.locales["en-GB"]=Date.ext.locales.en,Date.ext.locales["en-AU"]=Date.ext.locales["en-GB"],Date.ext.formats={a:function(a){return Date.ext.locales[a.locale].a[a.getDay()]},A:function(a){return Date.ext.locales[a.locale].A[a.getDay()]},b:function(a){return Date.ext.locales[a.locale].b[a.getMonth()]},B:function(a){return Date.ext.locales[a.locale].B[a.getMonth()]},c:"toLocaleString",C:function(a){return Date.ext.util.xPad(parseInt(a.getFullYear()/100,10),0)},d:["getDate","0"],e:["getDate"," "],g:function(a){return Date.ext.util.xPad(parseInt(Date.ext.util.G(a)/100,10),0)},G:function(a){var b=a.getFullYear(),c=parseInt(Date.ext.formats.V(a),10),d=parseInt(Date.ext.formats.W(a),10);return d>c?b++:d===0&&c>=52&&b--,b},H:["getHours","0"],I:function(a){var b=a.getHours()%12;return Date.ext.util.xPad(b===0?12:b,0)},j:function(a){var b=a-new Date(""+a.getFullYear()+"/1/1 GMT");b+=a.getTimezoneOffset()*6e4;var c=parseInt(b/6e4/60/24,10)+1;return Date.ext.util.xPad(c,0,100)},m:function(a){return Date.ext.util.xPad(a.getMonth()+1,0)},M:["getMinutes","0"],p:function(a){return Date.ext.locales[a.locale].p[a.getHours()>=12?1:0]},P:function(a){return Date.ext.locales[a.locale].P[a.getHours()>=12?1:0]},S:["getSeconds","0"],u:function(a){var b=a.getDay();return b===0?7:b},U:function(a){var b=parseInt(Date.ext.formats.j(a),10),c=6-a.getDay(),d=parseInt((b+c)/7,10);return Date.ext.util.xPad(d,0)},V:function(a){var b=parseInt(Date.ext.formats.W(a),10),c=(new Date(""+a.getFullYear()+"/1/1")).getDay(),d=b+(c>4||c<=1?0:1);return d==53&&(new Date(""+a.getFullYear()+"/12/31")).getDay()<4?d=1:d===0&&(d=Date.ext.formats.V(new Date(""+(a.getFullYear()-1)+"/12/31"))),Date.ext.util.xPad(d,0)},w:"getDay",W:function(a){var b=parseInt(Date.ext.formats.j(a),10),c=7-Date.ext.formats.u(a),d=parseInt((b+c)/7,10);return Date.ext.util.xPad(d,0,10)},y:function(a){return Date.ext.util.xPad(a.getFullYear()%100,0)},Y:"getFullYear",z:function(a){var b=a.getTimezoneOffset(),c=Date.ext.util.xPad(parseInt(Math.abs(b/60),10),0),d=Date.ext.util.xPad(b%60,0);return(b>0?"-":"+")+c+d},Z:function(a){return a.toString().replace(/^.*\(([^)]+)\)$/,"$1")},"%":function(a){return"%"}},Date.ext.aggregates={c:"locale",D:"%m/%d/%y",h:"%b",n:"\n",r:"%I:%M:%S %p",R:"%H:%M",t:" ",T:"%H:%M:%S",x:"locale",X:"locale"},Date.ext.aggregates.z=Date.ext.formats.z(new Date),Date.ext.aggregates.Z=Date.ext.formats.Z(new Date),Date.ext.unsupported={},Date.prototype.strftime=function(a){this.locale in Date.ext.locales||(this.locale.replace(/-[a-zA-Z]+$/,"")in Date.ext.locales?this.locale=this.locale.replace(/-[a-zA-Z]+$/,""):this.locale="en-GB");var b=this;while(a.match(/%[cDhnrRtTxXzZ]/))a=a.replace(/%([cDhnrRtTxXzZ])/g,function(a,c){var e=Date.ext.aggregates[c];return e=="locale"?Date.ext.locales[b.locale][c]:e});var c=a.replace(/%([aAbBCdegGHIjmMpPSuUVwWyY%])/g,function(a,c){var e=Date.ext.formats[c];return typeof e=="string"?b[e]():typeof e=="function"?e.call(b,b):typeof e=="object"&&typeof e[0]=="string"?Date.ext.util.xPad(b[e[0]](),e[1]):c});return b=null,c}; \ No newline at end of file diff --git a/www/css/graph.styl b/www/css/graph.styl index fd8812c..5df372f 100644 --- a/www/css/graph.styl +++ b/www/css/graph.styl @@ -20,7 +20,19 @@ section.graph padding 1em border-radius 5px background-color rgba(255,255,255, 0.75) - font 12px/1.3 "helvetica neue", helvetica, arial, sans-serif + font 12px/1.5 "helvetica neue", helvetica, arial, sans-serif + + b + display inline-block + width 140px + .whole + display inline-block + width 30px + text-align right + .fraction + text-align left + .suffix + text-align left .viewport:hover + .graph-label border 1px solid $light