Skip to content
Snippets Groups Projects
dygraph-combined-dev.js 401 KiB
Newer Older
  • Learn to ignore specific revisions
  • Laura Cappelli's avatar
    Laura Cappelli committed
    10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 10011 10012 10013 10014 10015 10016 10017 10018 10019 10020 10021 10022 10023 10024 10025 10026 10027 10028 10029 10030 10031 10032 10033 10034 10035 10036 10037 10038 10039 10040 10041 10042 10043 10044 10045 10046 10047 10048 10049 10050 10051 10052 10053 10054 10055 10056 10057 10058 10059 10060 10061 10062 10063 10064 10065 10066 10067 10068 10069 10070 10071 10072 10073 10074 10075 10076 10077 10078 10079 10080 10081 10082 10083 10084 10085 10086 10087 10088 10089 10090 10091 10092 10093 10094 10095 10096 10097 10098 10099 10100 10101 10102 10103 10104 10105 10106 10107 10108 10109 10110 10111 10112 10113 10114 10115 10116 10117 10118 10119 10120 10121 10122 10123 10124 10125 10126 10127 10128 10129 10130 10131 10132 10133 10134 10135 10136 10137 10138 10139 10140 10141 10142 10143 10144 10145 10146 10147 10148 10149 10150 10151 10152 10153 10154 10155 10156 10157 10158 10159 10160 10161 10162 10163 10164 10165 10166 10167 10168 10169 10170 10171 10172 10173 10174 10175 10176 10177 10178 10179 10180 10181 10182 10183 10184 10185 10186 10187 10188 10189 10190 10191 10192 10193 10194 10195 10196 10197 10198 10199 10200 10201 10202 10203 10204 10205 10206 10207 10208 10209 10210 10211 10212 10213 10214 10215 10216 10217 10218 10219 10220 10221 10222 10223 10224 10225 10226 10227 10228 10229 10230 10231 10232 10233 10234 10235 10236 10237 10238 10239 10240 10241 10242 10243 10244 10245 10246 10247 10248 10249 10250 10251 10252 10253 10254 10255 10256 10257 10258 10259 10260 10261 10262 10263 10264 10265 10266 10267 10268 10269 10270 10271 10272 10273 10274 10275 10276 10277 10278 10279 10280 10281 10282 10283 10284 10285 10286 10287 10288 10289 10290 10291 10292 10293 10294 10295 10296 10297 10298 10299 10300 10301 10302 10303 10304 10305 10306 10307 10308 10309 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320 10321 10322 10323 10324 10325 10326 10327 10328 10329 10330 10331 10332 10333 10334 10335 10336 10337 10338 10339 10340 10341 10342 10343 10344 10345 10346 10347 10348 10349 10350 10351 10352 10353 10354 10355 10356 10357 10358 10359 10360 10361 10362 10363 10364 10365 10366 10367 10368 10369 10370 10371 10372 10373 10374 10375 10376 10377 10378 10379 10380 10381 10382 10383 10384 10385 10386 10387 10388 10389 10390 10391 10392 10393 10394 10395 10396 10397 10398 10399 10400 10401 10402 10403 10404 10405 10406 10407 10408 10409 10410 10411 10412 10413 10414 10415 10416 10417 10418 10419 10420 10421 10422 10423 10424 10425 10426 10427 10428 10429 10430 10431 10432 10433 10434 10435 10436 10437 10438 10439 10440 10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452 10453 10454 10455 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465 10466 10467 10468 10469 10470 10471 10472 10473 10474 10475 10476 10477 10478 10479 10480 10481 10482 10483 10484 10485 10486 10487 10488 10489 10490 10491 10492 10493 10494 10495 10496 10497 10498 10499 10500 10501 10502 10503 10504 10505 10506 10507 10508 10509 10510 10511 10512 10513 10514 10515 10516 10517 10518 10519 10520 10521 10522 10523 10524 10525 10526 10527 10528 10529 10530 10531 10532 10533 10534 10535 10536 10537 10538 10539 10540 10541 10542 10543 10544 10545 10546 10547 10548 10549 10550 10551 10552 10553 10554 10555 10556 10557 10558 10559 10560 10561 10562 10563 10564 10565 10566 10567 10568 10569 10570 10571 10572 10573 10574 10575 10576 10577 10578 10579 10580 10581 10582 10583 10584 10585 10586 10587 10588 10589 10590 10591 10592 10593 10594 10595 10596 10597 10598 10599 10600 10601 10602 10603 10604 10605 10606 10607 10608 10609 10610 10611 10612 10613 10614 10615 10616 10617 10618 10619 10620 10621 10622 10623 10624 10625 10626 10627 10628 10629 10630 10631 10632 10633 10634 10635 10636 10637 10638 10639 10640 10641 10642 10643 10644 10645 10646 10647 10648 10649 10650 10651 10652 10653 10654 10655 10656 10657 10658 10659 10660 10661 10662 10663 10664 10665 10666 10667 10668 10669 10670 10671 10672 10673 10674 10675 10676 10677 10678 10679 10680 10681 10682 10683 10684 10685 10686 10687 10688 10689 10690 10691 10692 10693 10694 10695 10696 10697 10698 10699 10700 10701 10702 10703 10704 10705 10706 10707 10708 10709 10710 10711 10712 10713 10714 10715 10716 10717 10718 10719 10720 10721 10722 10723 10724 10725 10726 10727 10728 10729 10730 10731 10732 10733 10734 10735 10736 10737 10738 10739 10740 10741 10742 10743 10744 10745 10746 10747 10748 10749 10750 10751 10752 10753 10754 10755 10756 10757 10758 10759 10760 10761 10762 10763 10764 10765 10766 10767 10768 10769 10770 10771 10772 10773 10774 10775 10776 10777 10778 10779 10780 10781 10782 10783 10784 10785 10786 10787 10788 10789 10790 10791 10792 10793 10794 10795 10796 10797 10798 10799 10800 10801 10802 10803 10804 10805 10806 10807 10808 10809 10810 10811 10812 10813 10814 10815 10816 10817 10818 10819 10820 10821 10822 10823 10824 10825 10826 10827 10828 10829 10830 10831 10832 10833 10834 10835 10836 10837 10838 10839 10840 10841 10842 10843 10844 10845 10846 10847 10848 10849 10850 10851 10852 10853 10854 10855 10856 10857 10858 10859 10860 10861 10862 10863 10864 10865 10866 10867 10868 10869 10870 10871 10872 10873 10874 10875 10876 10877 10878 10879 10880 10881 10882 10883 10884 10885 10886 10887 10888 10889 10890 10891 10892 10893 10894 10895 10896 10897 10898 10899 10900 10901 10902 10903 10904 10905 10906 10907 10908 10909 10910 10911 10912 10913 10914 10915 10916 10917 10918 10919 10920 10921 10922 10923 10924 10925 10926 10927 10928 10929 10930 10931 10932 10933 10934 10935 10936 10937 10938 10939 10940 10941 10942 10943 10944 10945 10946 10947 10948 10949 10950 10951 10952 10953 10954 10955 10956 10957 10958 10959 10960 10961 10962 10963 10964 10965 10966 10967 10968 10969 10970 10971 10972 10973 10974 10975 10976 10977 10978 10979 10980 10981 10982 10983 10984 10985 10986 10987 10988 10989 10990 10991 10992 10993 10994 10995 10996 10997 10998 10999 11000
        var cursor = isMouseInPanZone(e) ? 'move' : 'default';
        if (cursor != self.fgcanvas_.style.cursor) {
          self.fgcanvas_.style.cursor = cursor;
        }
      };
    
      onZoomHandleTouchEvent = function(e) {
        if (e.type == 'touchstart' && e.targetTouches.length == 1) {
          if (onZoomStart(e.targetTouches[0])) {
            Dygraph.cancelEvent(e);
          }
        } else if (e.type == 'touchmove' && e.targetTouches.length == 1) {
          if (onZoom(e.targetTouches[0])) {
            Dygraph.cancelEvent(e);
          }
        } else {
          onZoomEnd(e);
        }
      };
    
      onCanvasTouchEvent = function(e) {
        if (e.type == 'touchstart' && e.targetTouches.length == 1) {
          if (onPanStart(e.targetTouches[0])) {
            Dygraph.cancelEvent(e);
          }
        } else if (e.type == 'touchmove' && e.targetTouches.length == 1) {
          if (onPan(e.targetTouches[0])) {
            Dygraph.cancelEvent(e);
          }
        } else {
          onPanEnd(e);
        }
      };
    
      addTouchEvents = function(elem, fn) {
        var types = ['touchstart', 'touchend', 'touchmove', 'touchcancel'];
        for (var i = 0; i < types.length; i++) {
          self.dygraph_.addAndTrackEvent(elem, types[i], fn);
        }
      };
    
      this.setDefaultOption_('interactionModel', Dygraph.Interaction.dragIsPanInteractionModel);
      this.setDefaultOption_('panEdgeFraction', 0.0001);
    
      var dragStartEvent = window.opera ? 'mousedown' : 'dragstart';
      this.dygraph_.addAndTrackEvent(this.leftZoomHandle_, dragStartEvent, onZoomStart);
      this.dygraph_.addAndTrackEvent(this.rightZoomHandle_, dragStartEvent, onZoomStart);
    
      if (this.isUsingExcanvas_) {
        this.dygraph_.addAndTrackEvent(this.iePanOverlay_, 'mousedown', onPanStart);
      } else {
        this.dygraph_.addAndTrackEvent(this.fgcanvas_, 'mousedown', onPanStart);
        this.dygraph_.addAndTrackEvent(this.fgcanvas_, 'mousemove', onCanvasHover);
      }
    
      // Touch events
      if (this.hasTouchInterface_) {
        addTouchEvents(this.leftZoomHandle_, onZoomHandleTouchEvent);
        addTouchEvents(this.rightZoomHandle_, onZoomHandleTouchEvent);
        addTouchEvents(this.fgcanvas_, onCanvasTouchEvent);
      }
    };
    
    /**
     * @private
     * Draws the static layer in the background canvas.
     */
    rangeSelector.prototype.drawStaticLayer_ = function() {
      var ctx = this.bgcanvas_ctx_;
      ctx.clearRect(0, 0, this.canvasRect_.w, this.canvasRect_.h);
      try {
        this.drawMiniPlot_();
      } catch(ex) {
        console.warn(ex);
      }
    
      var margin = 0.5;
      this.bgcanvas_ctx_.lineWidth = 1;
      ctx.strokeStyle = 'gray';
      ctx.beginPath();
      ctx.moveTo(margin, margin);
      ctx.lineTo(margin, this.canvasRect_.h-margin);
      ctx.lineTo(this.canvasRect_.w-margin, this.canvasRect_.h-margin);
      ctx.lineTo(this.canvasRect_.w-margin, margin);
      ctx.stroke();
    };
    
    
    /**
     * @private
     * Draws the mini plot in the background canvas.
     */
    rangeSelector.prototype.drawMiniPlot_ = function() {
      var fillStyle = this.getOption_('rangeSelectorPlotFillColor');
      var strokeStyle = this.getOption_('rangeSelectorPlotStrokeColor');
      if (!fillStyle && !strokeStyle) {
        return;
      }
    
      var stepPlot = this.getOption_('stepPlot');
    
      var combinedSeriesData = this.computeCombinedSeriesAndLimits_();
      var yRange = combinedSeriesData.yMax - combinedSeriesData.yMin;
    
      // Draw the mini plot.
      var ctx = this.bgcanvas_ctx_;
      var margin = 0.5;
    
      var xExtremes = this.dygraph_.xAxisExtremes();
      var xRange = Math.max(xExtremes[1] - xExtremes[0], 1.e-30);
      var xFact = (this.canvasRect_.w - margin)/xRange;
      var yFact = (this.canvasRect_.h - margin)/yRange;
      var canvasWidth = this.canvasRect_.w - margin;
      var canvasHeight = this.canvasRect_.h - margin;
    
      var prevX = null, prevY = null;
    
      ctx.beginPath();
      ctx.moveTo(margin, canvasHeight);
      for (var i = 0; i < combinedSeriesData.data.length; i++) {
        var dataPoint = combinedSeriesData.data[i];
        var x = ((dataPoint[0] !== null) ? ((dataPoint[0] - xExtremes[0])*xFact) : NaN);
        var y = ((dataPoint[1] !== null) ? (canvasHeight - (dataPoint[1] - combinedSeriesData.yMin)*yFact) : NaN);
    
        // Skip points that don't change the x-value. Overly fine-grained points
        // can cause major slowdowns with the ctx.fill() call below.
        if (!stepPlot && prevX !== null && Math.round(x) == Math.round(prevX)) {
          continue;
        }
    
        if (isFinite(x) && isFinite(y)) {
          if(prevX === null) {
            ctx.lineTo(x, canvasHeight);
          }
          else if (stepPlot) {
            ctx.lineTo(x, prevY);
          }
          ctx.lineTo(x, y);
          prevX = x;
          prevY = y;
        }
        else {
          if(prevX !== null) {
            if (stepPlot) {
              ctx.lineTo(x, prevY);
              ctx.lineTo(x, canvasHeight);
            }
            else {
              ctx.lineTo(prevX, canvasHeight);
            }
          }
          prevX = prevY = null;
        }
      }
      ctx.lineTo(canvasWidth, canvasHeight);
      ctx.closePath();
    
      if (fillStyle) {
        var lingrad = this.bgcanvas_ctx_.createLinearGradient(0, 0, 0, canvasHeight);
        lingrad.addColorStop(0, 'white');
        lingrad.addColorStop(1, fillStyle);
        this.bgcanvas_ctx_.fillStyle = lingrad;
        ctx.fill();
      }
    
      if (strokeStyle) {
        this.bgcanvas_ctx_.strokeStyle = strokeStyle;
        this.bgcanvas_ctx_.lineWidth = 1.5;
        ctx.stroke();
      }
    };
    
    /**
     * @private
     * Computes and returns the combined series data along with min/max for the mini plot.
     * The combined series consists of averaged values for all series.
     * When series have error bars, the error bars are ignored.
     * @return {Object} An object containing combined series array, ymin, ymax.
     */
    rangeSelector.prototype.computeCombinedSeriesAndLimits_ = function() {
      var g = this.dygraph_;
      var logscale = this.getOption_('logscale');
      var i;
    
      // Select series to combine. By default, all series are combined.
      var numColumns = g.numColumns();
      var labels = g.getLabels();
      var includeSeries = new Array(numColumns);
      var anySet = false;
      for (i = 1; i < numColumns; i++) {
        var include = this.getOption_('showInRangeSelector', labels[i]);
        includeSeries[i] = include;
        if (include !== null) anySet = true;  // it's set explicitly for this series
      }
      if (!anySet) {
        for (i = 0; i < includeSeries.length; i++) includeSeries[i] = true;
      }
    
      // Create a combined series (average of selected series values).
      // TODO(danvk): short-circuit if there's only one series.
      var rolledSeries = [];
      var dataHandler = g.dataHandler_;
      var options = g.attributes_;
      for (i = 1; i < g.numColumns(); i++) {
        if (!includeSeries[i]) continue;
        var series = dataHandler.extractSeries(g.rawData_, i, options);
        if (g.rollPeriod() > 1) {
          series = dataHandler.rollingAverage(series, g.rollPeriod(), options);
        }
        
        rolledSeries.push(series);
      }
    
      var combinedSeries = [];
      for (i = 0; i < rolledSeries[0].length; i++) {
        var sum = 0;
        var count = 0;
        for (var j = 0; j < rolledSeries.length; j++) {
          var y = rolledSeries[j][i][1];
          if (y === null || isNaN(y)) continue;
          count++;
          sum += y;
        }
        combinedSeries.push([rolledSeries[0][i][0], sum / count]);
      }
    
      // Compute the y range.
      var yMin = Number.MAX_VALUE;
      var yMax = -Number.MAX_VALUE;
      for (i = 0; i < combinedSeries.length; i++) {
        var yVal = combinedSeries[i][1];
        if (yVal !== null && isFinite(yVal) && (!logscale || yVal > 0)) {
          yMin = Math.min(yMin, yVal);
          yMax = Math.max(yMax, yVal);
        }
      }
    
      // Convert Y data to log scale if needed.
      // Also, expand the Y range to compress the mini plot a little.
      var extraPercent = 0.25;
      if (logscale) {
        yMax = Dygraph.log10(yMax);
        yMax += yMax*extraPercent;
        yMin = Dygraph.log10(yMin);
        for (i = 0; i < combinedSeries.length; i++) {
          combinedSeries[i][1] = Dygraph.log10(combinedSeries[i][1]);
        }
      } else {
        var yExtra;
        var yRange = yMax - yMin;
        if (yRange <= Number.MIN_VALUE) {
          yExtra = yMax*extraPercent;
        } else {
          yExtra = yRange*extraPercent;
        }
        yMax += yExtra;
        yMin -= yExtra;
      }
    
      return {data: combinedSeries, yMin: yMin, yMax: yMax};
    };
    
    /**
     * @private
     * Places the zoom handles in the proper position based on the current X data window.
     */
    rangeSelector.prototype.placeZoomHandles_ = function() {
      var xExtremes = this.dygraph_.xAxisExtremes();
      var xWindowLimits = this.dygraph_.xAxisRange();
      var xRange = xExtremes[1] - xExtremes[0];
      var leftPercent = Math.max(0, (xWindowLimits[0] - xExtremes[0])/xRange);
      var rightPercent = Math.max(0, (xExtremes[1] - xWindowLimits[1])/xRange);
      var leftCoord = this.canvasRect_.x + this.canvasRect_.w*leftPercent;
      var rightCoord = this.canvasRect_.x + this.canvasRect_.w*(1 - rightPercent);
      var handleTop = Math.max(this.canvasRect_.y, this.canvasRect_.y + (this.canvasRect_.h - this.leftZoomHandle_.height)/2);
      var halfHandleWidth = this.leftZoomHandle_.width/2;
      this.leftZoomHandle_.style.left = (leftCoord - halfHandleWidth) + 'px';
      this.leftZoomHandle_.style.top = handleTop + 'px';
      this.rightZoomHandle_.style.left = (rightCoord - halfHandleWidth) + 'px';
      this.rightZoomHandle_.style.top = this.leftZoomHandle_.style.top;
    
      this.leftZoomHandle_.style.visibility = 'visible';
      this.rightZoomHandle_.style.visibility = 'visible';
    };
    
    /**
     * @private
     * Draws the interactive layer in the foreground canvas.
     */
    rangeSelector.prototype.drawInteractiveLayer_ = function() {
      var ctx = this.fgcanvas_ctx_;
      ctx.clearRect(0, 0, this.canvasRect_.w, this.canvasRect_.h);
      var margin = 1;
      var width = this.canvasRect_.w - margin;
      var height = this.canvasRect_.h - margin;
      var zoomHandleStatus = this.getZoomHandleStatus_();
    
      ctx.strokeStyle = 'black';
      if (!zoomHandleStatus.isZoomed) {
        ctx.beginPath();
        ctx.moveTo(margin, margin);
        ctx.lineTo(margin, height);
        ctx.lineTo(width, height);
        ctx.lineTo(width, margin);
        ctx.stroke();
        if (this.iePanOverlay_) {
          this.iePanOverlay_.style.display = 'none';
        }
      } else {
        var leftHandleCanvasPos = Math.max(margin, zoomHandleStatus.leftHandlePos - this.canvasRect_.x);
        var rightHandleCanvasPos = Math.min(width, zoomHandleStatus.rightHandlePos - this.canvasRect_.x);
    
        ctx.fillStyle = 'rgba(240, 240, 240, 0.6)';
        ctx.fillRect(0, 0, leftHandleCanvasPos, this.canvasRect_.h);
        ctx.fillRect(rightHandleCanvasPos, 0, this.canvasRect_.w - rightHandleCanvasPos, this.canvasRect_.h);
    
        ctx.beginPath();
        ctx.moveTo(margin, margin);
        ctx.lineTo(leftHandleCanvasPos, margin);
        ctx.lineTo(leftHandleCanvasPos, height);
        ctx.lineTo(rightHandleCanvasPos, height);
        ctx.lineTo(rightHandleCanvasPos, margin);
        ctx.lineTo(width, margin);
        ctx.stroke();
    
        if (this.isUsingExcanvas_) {
          this.iePanOverlay_.style.width = (rightHandleCanvasPos - leftHandleCanvasPos) + 'px';
          this.iePanOverlay_.style.left = leftHandleCanvasPos + 'px';
          this.iePanOverlay_.style.height = height + 'px';
          this.iePanOverlay_.style.display = 'inline';
        }
      }
    };
    
    /**
     * @private
     * Returns the current zoom handle position information.
     * @return {Object} The zoom handle status.
     */
    rangeSelector.prototype.getZoomHandleStatus_ = function() {
      var halfHandleWidth = this.leftZoomHandle_.width/2;
      var leftHandlePos = parseFloat(this.leftZoomHandle_.style.left) + halfHandleWidth;
      var rightHandlePos = parseFloat(this.rightZoomHandle_.style.left) + halfHandleWidth;
      return {
          leftHandlePos: leftHandlePos,
          rightHandlePos: rightHandlePos,
          isZoomed: (leftHandlePos - 1 > this.canvasRect_.x || rightHandlePos + 1 < this.canvasRect_.x+this.canvasRect_.w)
      };
    };
    
    return rangeSelector;
    
    })();
    /*global Dygraph:false */
    
    // This file defines the ordering of the plugins.
    //
    // The ordering is from most-general to most-specific.
    // This means that, in an event cascade, plugins which have registered for that
    // event will be called in reverse order.
    //
    // This is most relevant for plugins which register a layout event, e.g.
    // Axes, Legend and ChartLabels.
    
    Dygraph.PLUGINS.push(
      Dygraph.Plugins.Legend,
      Dygraph.Plugins.Axes,
      Dygraph.Plugins.RangeSelector, // Has to be before ChartLabels so that its callbacks are called after ChartLabels' callbacks.
      Dygraph.Plugins.ChartLabels,
      Dygraph.Plugins.Annotations,
      Dygraph.Plugins.Grid
    );
    /**
     * @license
     * Copyright 2011 Dan Vanderkam (danvdk@gmail.com)
     * MIT-licensed (http://opensource.org/licenses/MIT)
     */
    
    // NOTE: in addition to parsing as JS, this snippet is expected to be valid
    // JSON. This assumption cannot be checked in JS, but it will be checked when
    // documentation is generated by the generate-documentation.py script. For the
    // most part, this just means that you should always use double quotes.
    Dygraph.OPTIONS_REFERENCE =  // <JSON>
    {
      "xValueParser": {
        "default": "parseFloat() or Date.parse()*",
        "labels": ["CSV parsing"],
        "type": "function(str) -> number",
        "description": "A function which parses x-values (i.e. the dependent series). Must return a number, even when the values are dates. In this case, millis since epoch are used. This is used primarily for parsing CSV data. *=Dygraphs is slightly more accepting in the dates which it will parse. See code for details."
      },
      "stackedGraph": {
        "default": "false",
        "labels": ["Data Line display"],
        "type": "boolean",
        "description": "If set, stack series on top of one another rather than drawing them independently. The first series specified in the input data will wind up on top of the chart and the last will be on bottom. NaN values are drawn as white areas without a line on top, see stackedGraphNaNFill for details."
      },
      "stackedGraphNaNFill": {
        "default": "all",
        "labels": ["Data Line display"],
        "type": "string",
        "description": "Controls handling of NaN values inside a stacked graph. NaN values are interpolated/extended for stacking purposes, but the actual point value remains NaN in the legend display. Valid option values are \"all\" (interpolate internally, repeat leftmost and rightmost value as needed), \"inside\" (interpolate internally only, use zero outside leftmost and rightmost value), and \"none\" (treat NaN as zero everywhere)."
      },
      "pointSize": {
        "default": "1",
        "labels": ["Data Line display"],
        "type": "integer",
        "description": "The size of the dot to draw on each point in pixels (see drawPoints). A dot is always drawn when a point is \"isolated\", i.e. there is a missing point on either side of it. This also controls the size of those dots."
      },
      "labelsDivStyles": {
        "default": "null",
        "labels": ["Legend"],
        "type": "{}",
        "description": "Additional styles to apply to the currently-highlighted points div. For example, { 'fontWeight': 'bold' } will make the labels bold. In general, it is better to use CSS to style the .dygraph-legend class than to use this property."
      },
      "drawPoints": {
        "default": "false",
        "labels": ["Data Line display"],
        "type": "boolean",
        "description": "Draw a small dot at each point, in addition to a line going through the point. This makes the individual data points easier to see, but can increase visual clutter in the chart. The small dot can be replaced with a custom rendering by supplying a <a href='#drawPointCallback'>drawPointCallback</a>."
      },
      "drawGapEdgePoints": {
        "default": "false",
        "labels": ["Data Line display"],
        "type": "boolean",
        "description": "Draw points at the edges of gaps in the data. This improves visibility of small data segments or other data irregularities."
      },
      "drawPointCallback": {
        "default": "null",
        "labels": ["Data Line display"],
        "type": "function(g, seriesName, canvasContext, cx, cy, color, pointSize)",
        "parameters": [
          [ "g" , "the reference graph" ],
          [ "seriesName" , "the name of the series" ],
          [ "canvasContext" , "the canvas to draw on" ],
          [ "cx" , "center x coordinate" ],
          [ "cy" , "center y coordinate" ],
          [ "color" , "series color" ],
          [ "pointSize" , "the radius of the image." ],
          [ "idx" , "the row-index of the point in the data."]
        ],
        "description": "Draw a custom item when drawPoints is enabled. Default is a small dot matching the series color. This method should constrain drawing to within pointSize pixels from (cx, cy).  Also see <a href='#drawHighlightPointCallback'>drawHighlightPointCallback</a>"
      },
      "height": {
        "default": "320",
        "labels": ["Overall display"],
        "type": "integer",
        "description": "Height, in pixels, of the chart. If the container div has been explicitly sized, this will be ignored."
      },
      "zoomCallback": {
        "default": "null",
        "labels": ["Callbacks"],
        "type": "function(minDate, maxDate, yRanges)",
        "parameters": [
          [ "minDate" , "milliseconds since epoch" ],
          [ "maxDate" , "milliseconds since epoch." ],
          [ "yRanges" , "is an array of [bottom, top] pairs, one for each y-axis." ]
        ],
        "description": "A function to call when the zoom window is changed (either by zooming in or out)."
      },
      "pointClickCallback": {
        "snippet": "function(e, point){<br>&nbsp;&nbsp;alert(point);<br>}",
        "default": "null",
        "labels": ["Callbacks", "Interactive Elements"],
        "type": "function(e, point)",
        "parameters": [
          [ "e" , "the event object for the click" ],
          [ "point" , "the point that was clicked See <a href='#point_properties'>Point properties</a> for details" ]
        ],
        "description": "A function to call when a data point is clicked. and the point that was clicked."
      },
      "color": {
        "default": "(see description)",
        "labels": ["Data Series Colors"],
        "type": "string",
        "example": "red",
        "description": "A per-series color definition. Used in conjunction with, and overrides, the colors option."
      },
      "colors": {
        "default": "(see description)",
        "labels": ["Data Series Colors"],
        "type": "array<string>",
        "example": "['red', '#00FF00']",
        "description": "List of colors for the data series. These can be of the form \"#AABBCC\" or \"rgb(255,100,200)\" or \"yellow\", etc. If not specified, equally-spaced points around a color wheel are used. Overridden by the 'color' option."
      },
      "connectSeparatedPoints": {
        "default": "false",
        "labels": ["Data Line display"],
        "type": "boolean",
        "description": "Usually, when Dygraphs encounters a missing value in a data series, it interprets this as a gap and draws it as such. If, instead, the missing values represents an x-value for which only a different series has data, then you'll want to connect the dots by setting this to true. To explicitly include a gap with this option set, use a value of NaN."
      },
      "highlightCallback": {
        "default": "null",
        "labels": ["Callbacks"],
        "type": "function(event, x, points, row, seriesName)",
        "description": "When set, this callback gets called every time a new point is highlighted.",
        "parameters": [
          ["event", "the JavaScript mousemove event"],
          ["x", "the x-coordinate of the highlighted points"],
          ["points", "an array of highlighted points: <code>[ {name: 'series', yval: y-value}, &hellip; ]</code>"],
          ["row", "integer index of the highlighted row in the data table, starting from 0"],
          ["seriesName", "name of the highlighted series, only present if highlightSeriesOpts is set."]
        ]
      },
      "drawHighlightPointCallback": {
        "default": "null",
        "labels": ["Data Line display"],
        "type": "function(g, seriesName, canvasContext, cx, cy, color, pointSize)",
        "parameters": [
          [ "g" , "the reference graph" ],
          [ "seriesName" , "the name of the series" ],
          [ "canvasContext" , "the canvas to draw on" ],
          [ "cx" , "center x coordinate" ],
          [ "cy" , "center y coordinate" ],
          [ "color" , "series color" ],
          [ "pointSize" , "the radius of the image." ],
          [ "idx" , "the row-index of the point in the data."]
        ],
        "description": "Draw a custom item when a point is highlighted.  Default is a small dot matching the series color. This method should constrain drawing to within pointSize pixels from (cx, cy) Also see <a href='#drawPointCallback'>drawPointCallback</a>"
      },
      "highlightSeriesOpts": {
        "default": "null",
        "labels": ["Interactive Elements"],
        "type": "Object",
        "description": "When set, the options from this object are applied to the timeseries closest to the mouse pointer for interactive highlighting. See also 'highlightCallback'. Example: highlightSeriesOpts: { strokeWidth: 3 }."
      },
      "highlightSeriesBackgroundAlpha": {
        "default": "0.5",
        "labels": ["Interactive Elements"],
        "type": "float",
        "description": "Fade the background while highlighting series. 1=fully visible background (disable fading), 0=hiddden background (show highlighted series only)."
      },
      "includeZero": {
        "default": "false",
        "labels": ["Axis display"],
        "type": "boolean",
        "description": "Usually, dygraphs will use the range of the data plus some padding to set the range of the y-axis. If this option is set, the y-axis will always include zero, typically as the lowest value. This can be used to avoid exaggerating the variance in the data"
      },
      "rollPeriod": {
        "default": "1",
        "labels": ["Error Bars", "Rolling Averages"],
        "type": "integer &gt;= 1",
        "description": "Number of days over which to average data. Discussed extensively above."
      },
      "unhighlightCallback": {
        "default": "null",
        "labels": ["Callbacks"],
        "type": "function(event)",
        "parameters": [
          [ "event" , "the mouse event" ]
        ],
        "description": "When set, this callback gets called every time the user stops highlighting any point by mousing out of the graph."
      },
      "axisTickSize": {
        "default": "3.0",
        "labels": ["Axis display"],
        "type": "number",
        "description": "The size of the line to display next to each tick mark on x- or y-axes."
      },
      "labelsSeparateLines": {
        "default": "false",
        "labels": ["Legend"],
        "type": "boolean",
        "description": "Put <code>&lt;br/&gt;</code> between lines in the label string. Often used in conjunction with <strong>labelsDiv</strong>."
      },
      "xValueFormatter": {
        "default": "",
        "labels": ["Deprecated"],
        "type": "",
        "description": "Prefer axes: { x: { valueFormatter } }"
      },
      "valueFormatter": {
        "default": "Depends on the type of your data.",
        "labels": ["Legend", "Value display/formatting"],
        "type": "function(num or millis, opts, seriesName, dygraph, row, col)",
        "description": "Function to provide a custom display format for the values displayed on mouseover. This does not affect the values that appear on tick marks next to the axes. To format those, see axisLabelFormatter. This is usually set on a <a href='per-axis.html'>per-axis</a> basis. .",
        "parameters": [
          ["num_or_millis", "The value to be formatted. This is always a number. For date axes, it's millis since epoch. You can call new Date(millis) to get a Date object."],
          ["opts", "This is a function you can call to access various options (e.g. opts('labelsKMB')). It returns per-axis values for the option when available."],
          ["seriesName", "The name of the series from which the point came, e.g. 'X', 'Y', 'A', etc."],
          ["dygraph", "The dygraph object for which the formatting is being done"],
          ["row", "The row of the data from which this point comes. g.getValue(row, 0) will return the x-value for this point."],
          ["col", "The column of the data from which this point comes. g.getValue(row, col) will return the original y-value for this point. This can be used to get the full confidence interval for the point, or access un-rolled values for the point."]
        ]
      },
      "pixelsPerYLabel": {
        "default": "",
        "labels": ["Deprecated"],
        "type": "integer",
        "description": "Prefer axes: { y: { pixelsPerLabel } }"
      },
      "annotationMouseOverHandler": {
        "default": "null",
        "labels": ["Annotations"],
        "type": "function(annotation, point, dygraph, event)",
        "description": "If provided, this function is called whenever the user mouses over an annotation."
      },
      "annotationMouseOutHandler": {
        "default": "null",
        "labels": ["Annotations"],
        "type": "function(annotation, point, dygraph, event)",
        "parameters": [
          [ "annotation" , "the annotation left" ],
          [ "point" , "the point associated with the annotation" ],
          [ "dygraph" , "the reference graph" ],
          [ "event" , "the mouse event" ]
        ],
        "description": "If provided, this function is called whenever the user mouses out of an annotation."
      },
      "annotationClickHandler": {
        "default": "null",
        "labels": ["Annotations"],
        "type": "function(annotation, point, dygraph, event)",
        "parameters": [
          [ "annotation" , "the annotation left" ],
          [ "point" , "the point associated with the annotation" ],
          [ "dygraph" , "the reference graph" ],
          [ "event" , "the mouse event" ]
        ],
        "description": "If provided, this function is called whenever the user clicks on an annotation."
      },
      "annotationDblClickHandler": {
        "default": "null",
        "labels": ["Annotations"],
        "type": "function(annotation, point, dygraph, event)",
        "parameters": [
          [ "annotation" , "the annotation left" ],
          [ "point" , "the point associated with the annotation" ],
          [ "dygraph" , "the reference graph" ],
          [ "event" , "the mouse event" ]
        ],
        "description": "If provided, this function is called whenever the user double-clicks on an annotation."
      },
      "drawCallback": {
        "default": "null",
        "labels": ["Callbacks"],
        "type": "function(dygraph, is_initial)",
        "parameters": [
          [ "dygraph" , "The graph being drawn" ],
          [ "is_initial" , "True if this is the initial draw, false for subsequent draws." ]
        ],
        "description": "When set, this callback gets called every time the dygraph is drawn. This includes the initial draw, after zooming and repeatedly while panning."
      },
      "labelsKMG2": {
        "default": "false",
        "labels": ["Value display/formatting"],
        "type": "boolean",
        "description": "Show k/M/G for kilo/Mega/Giga on y-axis. This is different than <code>labelsKMB</code> in that it uses base 2, not 10."
      },
      "delimiter": {
        "default": ",",
        "labels": ["CSV parsing"],
        "type": "string",
        "description": "The delimiter to look for when separating fields of a CSV file. Setting this to a tab is not usually necessary, since tab-delimited data is auto-detected."
      },
      "axisLabelFontSize": {
        "default": "14",
        "labels": ["Axis display"],
        "type": "integer",
        "description": "Size of the font (in pixels) to use in the axis labels, both x- and y-axis."
      },
      "underlayCallback": {
        "default": "null",
        "labels": ["Callbacks"],
        "type": "function(context, area, dygraph)",
        "parameters": [
          [ "context" , "the canvas drawing context on which to draw" ],
          [ "area" , "An object with {x,y,w,h} properties describing the drawing area." ],
          [ "dygraph" , "the reference graph" ]
        ],
        "description": "When set, this callback gets called before the chart is drawn. It details on how to use this."
      },
      "width": {
        "default": "480",
        "labels": ["Overall display"],
        "type": "integer",
        "description": "Width, in pixels, of the chart. If the container div has been explicitly sized, this will be ignored."
      },
      "interactionModel": {
        "default": "...",
        "labels": ["Interactive Elements"],
        "type": "Object",
        "description": "TODO(konigsberg): document this"
      },
      "ticker": {
        "default": "Dygraph.dateTicker or Dygraph.numericTicks",
        "labels": ["Axis display"],
        "type": "function(min, max, pixels, opts, dygraph, vals) -> [{v: ..., label: ...}, ...]",
        "parameters": [
          [ "min" , "" ],
          [ "max" , "" ],
          [ "pixels" , "" ],
          [ "opts" , "" ],
          [ "dygraph" , "the reference graph" ],
          [ "vals" , "" ]
        ],
        "description": "This lets you specify an arbitrary function to generate tick marks on an axis. The tick marks are an array of (value, label) pairs. The built-in functions go to great lengths to choose good tick marks so, if you set this option, you'll most likely want to call one of them and modify the result. See dygraph-tickers.js for an extensive discussion. This is set on a <a href='per-axis.html'>per-axis</a> basis."
      },
      "xAxisLabelWidth": {
        "default": "",
        "labels": ["Deprecated"],
        "type": "integer",
        "description": "Prefer axes: { x: { axisLabelWidth } }"
      },
      "xAxisHeight": {
        "default": "(null)",
        "labels": ["Axis display"],
        "type": "integer",
        "description": "Height, in pixels, of the x-axis. If not set explicitly, this is computed based on axisLabelFontSize and axisTickSize."
      },
      "showLabelsOnHighlight": {
        "default": "true",
        "labels": ["Interactive Elements", "Legend"],
        "type": "boolean",
        "description": "Whether to show the legend upon mouseover."
      },
      "axis": {
        "default": "(none)",
        "labels": ["Axis display"],
        "type": "string",
        "description": "Set to either 'y1' or 'y2' to assign a series to a y-axis (primary or secondary). Must be set per-series."
      },
      "pixelsPerXLabel": {
        "default": "",
        "labels": ["Deprecated"],
        "type": "integer",
        "description": "Prefer axes { x: { pixelsPerLabel } }"
      },
      "pixelsPerLabel": {
        "default": "70 (x-axis) or 30 (y-axes)",
        "labels": ["Axis display", "Grid"],
        "type": "integer",
        "description": "Number of pixels to require between each x- and y-label. Larger values will yield a sparser axis with fewer ticks. This is set on a <a href='per-axis.html'>per-axis</a> basis."
      },
      "labelsDiv": {
        "default": "null",
        "labels": ["Legend"],
        "type": "DOM element or string",
        "example": "<code style='font-size: small'>document.getElementById('foo')</code>or<code>'foo'",
        "description": "Show data labels in an external div, rather than on the graph.  This value can either be a div element or a div id."
      },
      "fractions": {
        "default": "false",
        "labels": ["CSV parsing", "Error Bars"],
        "type": "boolean",
        "description": "When set, attempt to parse each cell in the CSV file as \"a/b\", where a and b are integers. The ratio will be plotted. This allows computation of Wilson confidence intervals (see below)."
      },
      "logscale": {
        "default": "false",
        "labels": ["Axis display"],
        "type": "boolean",
        "description": "When set for the y-axis or x-axis, the graph shows that axis in log scale. Any values less than or equal to zero are not displayed. Showing log scale with ranges that go below zero will result in an unviewable graph.\n\n Not compatible with showZero. connectSeparatedPoints is ignored. This is ignored for date-based x-axes."
      },
      "strokeWidth": {
        "default": "1.0",
        "labels": ["Data Line display"],
        "type": "float",
        "example": "0.5, 2.0",
        "description": "The width of the lines connecting data points. This can be used to increase the contrast or some graphs."
      },
      "strokePattern": {
        "default": "null",
        "labels": ["Data Line display"],
        "type": "array<integer>",
        "example": "[10, 2, 5, 2]",
        "description": "A custom pattern array where the even index is a draw and odd is a space in pixels. If null then it draws a solid line. The array should have a even length as any odd lengthed array could be expressed as a smaller even length array. This is used to create dashed lines."
      },
      "strokeBorderWidth": {
        "default": "null",
        "labels": ["Data Line display"],
        "type": "float",
        "example": "1.0",
        "description": "Draw a border around graph lines to make crossing lines more easily distinguishable. Useful for graphs with many lines."
      },
      "strokeBorderColor": {
        "default": "white",
        "labels": ["Data Line display"],
        "type": "string",
        "example": "red, #ccffdd",
        "description": "Color for the line border used if strokeBorderWidth is set."
      },
      "wilsonInterval": {
        "default": "true",
        "labels": ["Error Bars"],
        "type": "boolean",
        "description": "Use in conjunction with the \"fractions\" option. Instead of plotting +/- N standard deviations, dygraphs will compute a Wilson confidence interval and plot that. This has more reasonable behavior for ratios close to 0 or 1."
      },
      "fillGraph": {
        "default": "false",
        "labels": ["Data Line display"],
        "type": "boolean",
        "description": "Should the area underneath the graph be filled? This option is not compatible with error bars. This may be set on a <a href='per-axis.html'>per-series</a> basis."
      },
      "highlightCircleSize": {
        "default": "3",
        "labels": ["Interactive Elements"],
        "type": "integer",
        "description": "The size in pixels of the dot drawn over highlighted points."
      },
      "gridLineColor": {
        "default": "rgb(128,128,128)",
        "labels": ["Grid"],
        "type": "red, blue",
        "description": "The color of the gridlines. This may be set on a per-axis basis to define each axis' grid separately."
      },
      "gridLinePattern": {
        "default": "null",
        "labels": ["Grid"],
        "type": "array<integer>",
        "example": "[10, 2, 5, 2]",
        "description": "A custom pattern array where the even index is a draw and odd is a space in pixels. If null then it draws a solid line. The array should have a even length as any odd lengthed array could be expressed as a smaller even length array. This is used to create dashed gridlines."
      },
      "visibility": {
        "default": "[true, true, ...]",
        "labels": ["Data Line display"],
        "type": "Array of booleans",
        "description": "Which series should initially be visible? Once the Dygraph has been constructed, you can access and modify the visibility of each series using the <code>visibility</code> and <code>setVisibility</code> methods."
      },
      "valueRange": {
        "default": "Full range of the input is shown",
        "labels": ["Axis display"],
        "type": "Array of two numbers",
        "example": "[10, 110]",
        "description": "Explicitly set the vertical range of the graph to [low, high]. This may be set on a per-axis basis to define each y-axis separately. If either limit is unspecified, it will be calculated automatically (e.g. [null, 30] to automatically calculate just the lower bound)"
      },
      "labelsDivWidth": {
        "default": "250",
        "labels": ["Legend"],
        "type": "integer",
        "description": "Width (in pixels) of the div which shows information on the currently-highlighted points."
      },
      "colorSaturation": {
        "default": "1.0",
        "labels": ["Data Series Colors"],
        "type": "float (0.0 - 1.0)",
        "description": "If <strong>colors</strong> is not specified, saturation of the automatically-generated data series colors."
      },
      "yAxisLabelWidth": {
        "default": "",
        "labels": ["Deprecated"],
        "type": "integer",
        "description": "Prefer axes { y: { axisLabelWidth } }"
      },
      "hideOverlayOnMouseOut": {
        "default": "true",
        "labels": ["Interactive Elements", "Legend"],
        "type": "boolean",
        "description": "Whether to hide the legend when the mouse leaves the chart area."
      },
      "yValueFormatter": {
        "default": "",
        "labels": ["Deprecated"],
        "type": "",
        "description": "Prefer axes: { y: { valueFormatter } }"
      },
      "legend": {
        "default": "onmouseover",
        "labels": ["Legend"],
        "type": "string",
        "description": "When to display the legend. By default, it only appears when a user mouses over the chart. Set it to \"always\" to always display a legend of some sort. When set to \"follow\", legend follows highlighted points."
      },
      "labelsShowZeroValues": {
        "default": "true",
        "labels": ["Legend"],
        "type": "boolean",
        "description": "Show zero value labels in the labelsDiv."
      },
      "stepPlot": {
        "default": "false",
        "labels": ["Data Line display"],
        "type": "boolean",
        "description": "When set, display the graph as a step plot instead of a line plot. This option may either be set for the whole graph or for single series."
      },
      "labelsUTC": {
        "default": "false",
        "labels": ["Value display/formatting", "Axis display"],
        "type": "boolean",
        "description": "Show date/time labels according to UTC (instead of local time)."
      },
      "labelsKMB": {
        "default": "false",
        "labels": ["Value display/formatting"],
        "type": "boolean",
        "description": "Show K/M/B for thousands/millions/billions on y-axis."
      },
      "rightGap": {
        "default": "5",
        "labels": ["Overall display"],
        "type": "integer",
        "description": "Number of pixels to leave blank at the right edge of the Dygraph. This makes it easier to highlight the right-most data point."
      },
      "avoidMinZero": {
        "default": "false",
        "labels": ["Deprecated"],
        "type": "boolean",
        "description": "Deprecated, please use yRangePad instead. When set, the heuristic that fixes the Y axis at zero for a data set with the minimum Y value of zero is disabled. \nThis is particularly useful for data sets that contain many zero values, especially for step plots which may otherwise have lines not visible running along the bottom axis."
      },
      "drawAxesAtZero": {
        "default": "false",
        "labels": ["Axis display"],
        "type": "boolean",
        "description": "When set, draw the X axis at the Y=0 position and the Y axis at the X=0 position if those positions are inside the graph's visible area. Otherwise, draw the axes at the bottom or left graph edge as usual."
      },
      "xRangePad": {
        "default": "0",
        "labels": ["Axis display"],
        "type": "float",
        "description": "Add the specified amount of extra space (in pixels) around the X-axis value range to ensure points at the edges remain visible."
      },
      "yRangePad": {
        "default": "null",
        "labels": ["Axis display"],
        "type": "float",
        "description": "If set, add the specified amount of extra space (in pixels) around the Y-axis value range to ensure points at the edges remain visible. If unset, use the traditional Y padding algorithm."
      },
      "xAxisLabelFormatter": {
        "default": "",
        "labels": ["Deprecated"],
        "type": "",
        "description": "Prefer axes { x: { axisLabelFormatter } }"
      },
      "axisLabelFormatter": {
        "default": "Depends on the data type",
        "labels": ["Axis display"],
        "type": "function(number or Date, granularity, opts, dygraph)",
        "parameters": [
          [ "number or date" , "Either a number (for a numeric axis) or a Date object (for a date axis)" ],
          [ "granularity" , "specifies how fine-grained the axis is. For date axes, this is a reference to the time granularity enumeration, defined in dygraph-tickers.js, e.g. Dygraph.WEEKLY." ],
          [ "opts" , "a function which provides access to various options on the dygraph, e.g. opts('labelsKMB')." ],
          [ "dygraph" , "the referenced graph" ]
        ],
        "description": "Function to call to format the tick values that appear along an axis. This is usually set on a <a href='per-axis.html'>per-axis</a> basis."
      },
      "clickCallback": {
        "snippet": "function(e, date_millis){<br>&nbsp;&nbsp;alert(new Date(date_millis));<br>}",
        "default": "null",
        "labels": ["Callbacks"],
        "type": "function(e, x, points)",
        "parameters": [
          [ "e" , "The event object for the click" ],
          [ "x" , "The x value that was clicked (for dates, this is milliseconds since epoch)" ],
          [ "points" , "The closest points along that date. See <a href='#point_properties'>Point properties</a> for details." ]
        ],
        "description": "A function to call when the canvas is clicked."
      },
      "yAxisLabelFormatter": {
        "default": "",
        "labels": ["Deprecated"],
        "type": "",
        "description": "Prefer axes: { y: { axisLabelFormatter } }"
      },
      "labels": {
        "default": "[\"X\", \"Y1\", \"Y2\", ...]*",
        "labels": ["Legend"],
        "type": "array<string>",
        "description": "A name for each data series, including the independent (X) series. For CSV files and DataTable objections, this is determined by context. For raw data, this must be specified. If it is not, default values are supplied and a warning is logged."
      },
      "dateWindow": {
        "default": "Full range of the input is shown",
        "labels": ["Axis display"],
        "type": "Array of two numbers",
        "example": "[<br>&nbsp;&nbsp;Date.parse('2006-01-01'),<br>&nbsp;&nbsp;(new Date()).valueOf()<br>]",
        "description": "Initially zoom in on a section of the graph. Is of the form [earliest, latest], where earliest/latest are milliseconds since epoch. If the data for the x-axis is numeric, the values in dateWindow must also be numbers."
      },
      "showRoller": {
        "default": "false",
        "labels": ["Interactive Elements", "Rolling Averages"],
        "type": "boolean",
        "description": "If the rolling average period text box should be shown."
      },
      "sigma": {
        "default": "2.0",
        "labels": ["Error Bars"],
        "type": "float",
        "description": "When errorBars is set, shade this many standard deviations above/below each point."
      },
      "customBars": {
        "default": "false",
        "labels": ["CSV parsing", "Error Bars"],
        "type": "boolean",
        "description": "When set, parse each CSV cell as \"low;middle;high\". Error bars will be drawn for each point between low and high, with the series itself going through middle."
      },
      "colorValue": {
        "default": "1.0",
        "labels": ["Data Series Colors"],
        "type": "float (0.0 - 1.0)",
        "description": "If colors is not specified, value of the data series colors, as in hue/saturation/value. (0.0-1.0, default 0.5)"
      },
      "errorBars": {
        "default": "false",
        "labels": ["CSV parsing", "Error Bars"],
        "type": "boolean",
        "description": "Does the data contain standard deviations? Setting this to true alters the input format (see above)."
      },
      "displayAnnotations": {
        "default": "false",
        "labels": ["Annotations"],
        "type": "boolean",
        "description": "Only applies when Dygraphs is used as a GViz chart. Causes string columns following a data series to be interpreted as annotations on points in that series. This is the same format used by Google's AnnotatedTimeLine chart."
      },
      "panEdgeFraction": {