text: /* *
   *
   *  (c) 2010-2020 Torstein Honsi
   *
   *  License: www.highcharts.com/license
   *
   *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
   *
   * */
  'use strict';
  import Axis from './Axis.js';
  import H from './Globals.js';
  import Point from './Point.js';
  import U from './Utilities.js';
  var addEvent = U.addEvent, arrayMax = U.arrayMax, arrayMin = U.arrayMin, clamp = U.clamp, defined = U.defined, extend = U.extend, find = U.find, format = U.format, isNumber = U.isNumber, isString = U.isString, merge = U.merge, pick = U.pick, splat = U.splat;
  import './Chart.js';
  import './Pointer.js';
  import './Series.js';
  import './SvgRenderer.js';
  // Has a dependency on Navigator due to the use of
  // defaultOptions.navigator
  import './Navigator.js';
  // Has a dependency on Scrollbar due to the use of
  // defaultOptions.scrollbar
  import './Scrollbar.js';
  // Has a dependency on RangeSelector due to the use of
  // defaultOptions.rangeSelector
  import './RangeSelector.js';
  var Chart = H.Chart, Renderer = H.Renderer, Series = H.Series, SVGRenderer = H.SVGRenderer, seriesProto = Series.prototype, seriesInit = seriesProto.init, seriesProcessData = seriesProto.processData, pointTooltipFormatter = Point.prototype.tooltipFormatter;
  /**
   * Compare the values of the series against the first non-null, non-
   * zero value in the visible range. The y axis will show percentage
   * or absolute change depending on whether `compare` is set to `"percent"`
   * or `"value"`. When this is applied to multiple series, it allows
   * comparing the development of the series against each other. Adds
   * a `change` field to every point object.
   *
   * @see [compareBase](#plotOptions.series.compareBase)
   * @see [Axis.setCompare()](/class-reference/Highcharts.Axis#setCompare)
   *
   * @sample {highstock} stock/plotoptions/series-compare-percent/
   *         Percent
   * @sample {highstock} stock/plotoptions/series-compare-value/
   *         Value
   *
   * @type      {string}
   * @since     1.0.1
   * @product   highstock
   * @apioption plotOptions.series.compare
   */
  /**
   * Defines if comparison should start from the first point within the visible
   * range or should start from the first point **before** the range.
   *
   * In other words, this flag determines if first point within the visible range
   * will have 0% (`compareStart=true`) or should have been already calculated
   * according to the previous point (`compareStart=false`).
   *
   * @sample {highstock} stock/plotoptions/series-comparestart/
   *         Calculate compare within visible range
   *
   * @type      {boolean}
   * @default   false
   * @since     6.0.0
   * @product   highstock
   * @apioption plotOptions.series.compareStart
   */
  /**
   * When [compare](#plotOptions.series.compare) is `percent`, this option
   * dictates whether to use 0 or 100 as the base of comparison.
   *
   * @sample {highstock} stock/plotoptions/series-comparebase/
   *         Compare base is 100
   *
   * @type       {number}
   * @default    0
   * @since      5.0.6
   * @product    highstock
   * @validvalue [0, 100]
   * @apioption  plotOptions.series.compareBase
   */
  /* eslint-disable no-invalid-this, valid-jsdoc */
  /**
   * Factory function for creating new stock charts. Creates a new
   * {@link Highcharts.Chart|Chart} object with different default options than the
   * basic Chart.
   *
   * @example
   * var chart = Highcharts.stockChart('container', {
   *     series: [{
   *         data: [1, 2, 3, 4, 5, 6, 7, 8, 9],
   *         pointInterval: 24 * 60 * 60 * 1000
   *     }]
   * });
   *
   * @function Highcharts.stockChart
   *
   * @param {string|Highcharts.HTMLDOMElement} [renderTo]
   *        The DOM element to render to, or its id.
   *
   * @param {Highcharts.Options} options
   *        The chart options structure as described in the
   *        [options reference](https://api.highcharts.com/highstock).
   *
   * @param {Highcharts.ChartCallbackFunction} [callback]
   *        A function to execute when the chart object is finished loading and
   *        rendering. In most cases the chart is built in one thread, but in
   *        Internet Explorer version 8 or less the chart is sometimes
   *        initialized before the document is ready, and in these cases the
   *        chart object will not be finished synchronously. As a consequence,
   *        code that relies on the newly built Chart object should always run in
   *        the callback. Defining a
   *        [chart.events.load](https://api.highcharts.com/highstock/chart.events.load)
   *        handler is equivalent.
   *
   * @return {Highcharts.Chart}
   *         The chart object.
   */
  H.StockChart = H.stockChart = function (a, b, c) {
      var hasRenderToArg = isString(a) || a.nodeName, options = arguments[hasRenderToArg ? 1 : 0], userOptions = options, 
      // to increase performance, don't merge the data
      seriesOptions = options.series, defaultOptions = H.getOptions(), opposite, 
      // Always disable startOnTick:true on the main axis when the navigator
      // is enabled (#1090)
      navigatorEnabled = pick(options.navigator && options.navigator.enabled, defaultOptions.navigator.enabled, true);
      // apply X axis options to both single and multi y axes
      options.xAxis = splat(options.xAxis || {}).map(function (xAxisOptions, i) {
          return merge({
              minPadding: 0,
              maxPadding: 0,
              overscroll: 0,
              ordinal: true,
              title: {
                  text: null
              },
              labels: {
                  overflow: 'justify'
              },
              showLastLabel: true
          }, defaultOptions.xAxis, // #3802
          defaultOptions.xAxis && defaultOptions.xAxis[i], // #7690
          xAxisOptions, // user options
          {
              type: 'datetime',
              categories: null
          }, (navigatorEnabled ? {
              startOnTick: false,
              endOnTick: false
          } : null));
      });
      // apply Y axis options to both single and multi y axes
      options.yAxis = splat(options.yAxis || {}).map(function (yAxisOptions, i) {
          opposite = pick(yAxisOptions.opposite, true);
          return merge({
              labels: {
                  y: -2
              },
              opposite: opposite,
              /**
               * @default {highcharts} true
               * @default {highstock} false
               * @apioption yAxis.showLastLabel
               *
               * @private
               */
              showLastLabel: !!(
              // #6104, show last label by default for category axes
              yAxisOptions.categories ||
                  yAxisOptions.type === 'category'),
              title: {
                  text: null
              }
          }, defaultOptions.yAxis, // #3802
          defaultOptions.yAxis && defaultOptions.yAxis[i], // #7690
          yAxisOptions // user options
          );
      });
      options.series = null;
      options = merge({
          chart: {
              panning: {
                  enabled: true,
                  type: 'x'
              },
              pinchType: 'x'
          },
          navigator: {
              enabled: navigatorEnabled
          },
          scrollbar: {
              // #4988 - check if setOptions was called
              enabled: pick(defaultOptions.scrollbar.enabled, true)
          },
          rangeSelector: {
              // #4988 - check if setOptions was called
              enabled: pick(defaultOptions.rangeSelector.enabled, true)
          },
          title: {
              text: null
          },
          tooltip: {
              split: pick(defaultOptions.tooltip.split, true),
              crosshairs: true
          },
          legend: {
              enabled: false
          }
      }, options, // user's options
      {
          isStock: true // internal flag
      });
      options.series = userOptions.series = seriesOptions;
      return hasRenderToArg ?
          new Chart(a, options, c) :
          new Chart(options, b);
  };
  // Handle som Stock-specific series defaults, override the plotOptions before
  // series options are handled.
  addEvent(Series, 'setOptions', function (e) {
      var overrides;
      if (this.chart.options.isStock) {
          if (this.is('column') || this.is('columnrange')) {
              overrides = {
                  borderWidth: 0,
                  shadow: false
              };
          }
          else if (!this.is('scatter') && !this.is('sma')) {
              overrides = {
                  marker: {
                      enabled: false,
                      radius: 2
                  }
              };
          }
          if (overrides) {
              e.plotOptions[this.type] = merge(e.plotOptions[this.type], overrides);
          }
      }
  });
  // Override the automatic label alignment so that the first Y axis' labels
  // are drawn on top of the grid line, and subsequent axes are drawn outside
  addEvent(Axis, 'autoLabelAlign', function (e) {
      var chart = this.chart, options = this.options, panes = chart._labelPanes = chart._labelPanes || {}, key, labelOptions = this.options.labels;
      if (this.chart.options.isStock && this.coll === 'yAxis') {
          key = options.top + ',' + options.height;
          // do it only for the first Y axis of each pane
          if (!panes[key] && labelOptions.enabled) {
              if (labelOptions.x === 15) { // default
                  labelOptions.x = 0;
              }
              if (typeof labelOptions.align === 'undefined') {
                  labelOptions.align = 'right';
              }
              panes[key] = this;
              e.align = 'right';
              e.preventDefault();
          }
      }
  });
  // Clear axis from label panes (#6071)
  addEvent(Axis, 'destroy', function () {
      var chart = this.chart, key = this.options && (this.options.top + ',' + this.options.height);
      if (key && chart._labelPanes && chart._labelPanes[key] === this) {
          delete chart._labelPanes[key];
      }
  });
  // Override getPlotLinePath to allow for multipane charts
  addEvent(Axis, 'getPlotLinePath', function (e) {
      var axis = this, series = (this.isLinked && !this.series ?
          this.linkedParent.series :
          this.series), chart = axis.chart, renderer = chart.renderer, axisLeft = axis.left, axisTop = axis.top, x1, y1, x2, y2, result = [], axes = [], // #3416 need a default array
      axes2, uniqueAxes, translatedValue = e.translatedValue, value = e.value, force = e.force, transVal;
      /**
       * Return the other axis based on either the axis option or on related
       * series.
       * @private
       */
      function getAxis(coll) {
          var otherColl = coll === 'xAxis' ? 'yAxis' : 'xAxis', opt = axis.options[otherColl];
          // Other axis indexed by number
          if (isNumber(opt)) {
              return [chart[otherColl][opt]];
          }
          // Other axis indexed by id (like navigator)
          if (isString(opt)) {
              return [chart.get(opt)];
          }
          // Auto detect based on existing series
          return series.map(function (s) {
              return s[otherColl];
          });
      }
      if ( // For stock chart, by default render paths across the panes
      // except the case when `acrossPanes` is disabled by user (#6644)
      (chart.options.isStock && e.acrossPanes !== false) &&
          // Ignore in case of colorAxis or zAxis. #3360, #3524, #6720
          axis.coll === 'xAxis' || axis.coll === 'yAxis') {
          e.preventDefault();
          // Get the related axes based on series
          axes = getAxis(axis.coll);
          // Get the related axes based options.*Axis setting #2810
          axes2 = (axis.isXAxis ? chart.yAxis : chart.xAxis);
          axes2.forEach(function (A) {
              if (defined(A.options.id) ?
                  A.options.id.indexOf('navigator') === -1 :
                  true) {
                  var a = (A.isXAxis ? 'yAxis' : 'xAxis'), rax = (defined(A.options[a]) ?
                      chart[a][A.options[a]] :
                      chart[a][0]);
                  if (axis === rax) {
                      axes.push(A);
                  }
              }
          });
          // Remove duplicates in the axes array. If there are no axes in the axes
          // array, we are adding an axis without data, so we need to populate
          // this with grid lines (#2796).
          uniqueAxes = axes.length ?
              [] :
              [axis.isXAxis ? chart.yAxis[0] : chart.xAxis[0]]; // #3742
          axes.forEach(function (axis2) {
              if (uniqueAxes.indexOf(axis2) === -1 &&
                  // Do not draw on axis which overlap completely. #5424
                  !find(uniqueAxes, function (unique) {
                      return unique.pos === axis2.pos && unique.len === axis2.len;
                  })) {
                  uniqueAxes.push(axis2);
              }
          });
          transVal = pick(translatedValue, axis.translate(value, null, null, e.old));
          if (isNumber(transVal)) {
              if (axis.horiz) {
                  uniqueAxes.forEach(function (axis2) {
                      var skip;
                      y1 = axis2.pos;
                      y2 = y1 + axis2.len;
                      x1 = x2 = Math.round(transVal + axis.transB);
                      // outside plot area
                      if (force !== 'pass' &&
                          (x1 < axisLeft || x1 > axisLeft + axis.width)) {
                          if (force) {
                              x1 = x2 = clamp(x1, axisLeft, axisLeft + axis.width);
                          }
                          else {
                              skip = true;
                          }
                      }
                      if (!skip) {
                          result.push(['M', x1, y1], ['L', x2, y2]);
                      }
                  });
              }
              else {
                  uniqueAxes.forEach(function (axis2) {
                      var skip;
                      x1 = axis2.pos;
                      x2 = x1 + axis2.len;
                      y1 = y2 = Math.round(axisTop + axis.height - transVal);
                      // outside plot area
                      if (force !== 'pass' &&
                          (y1 < axisTop || y1 > axisTop + axis.height)) {
                          if (force) {
                              y1 = y2 = clamp(y1, axisTop, axisTop + axis.height);
                          }
                          else {
                              skip = true;
                          }
                      }
                      if (!skip) {
                          result.push(['M', x1, y1], ['L', x2, y2]);
                      }
                  });
              }
          }
          e.path = result.length > 0 ?
              renderer.crispPolyLine(result, e.lineWidth || 1) :
              // #3557 getPlotLinePath in regular Highcharts also returns null
              null;
      }
  });
  /**
   * Function to crisp a line with multiple segments
   *
   * @private
   * @function Highcharts.SVGRenderer#crispPolyLine
   * @param {Highcharts.SVGPathArray} points
   * @param {number} width
   * @return {Highcharts.SVGPathArray}
   */
  SVGRenderer.prototype.crispPolyLine = function (points, width) {
      // points format: [['M', 0, 0], ['L', 100, 0]]
      // normalize to a crisp line
      for (var i = 0; i < points.length; i = i + 2) {
          var start = points[i], end = points[i + 1];
          if (start[1] === end[1]) {
              // Substract due to #1129. Now bottom and left axis gridlines behave
              // the same.
              start[1] = end[1] =
                  Math.round(start[1]) - (width % 2 / 2);
          }
          if (start[2] === end[2]) {
              start[2] = end[2] =
                  Math.round(start[2]) + (width % 2 / 2);
          }
      }
      return points;
  };
  // Wrapper to hide the label
  addEvent(Axis, 'afterHideCrosshair', function () {
      if (this.crossLabel) {
          this.crossLabel = this.crossLabel.hide();
      }
  });
  // Extend crosshairs to also draw the label
  addEvent(Axis, 'afterDrawCrosshair', function (event) {
      // Check if the label has to be drawn
      if (!defined(this.crosshair.label) ||
          !this.crosshair.label.enabled ||
          !this.cross) {
          return;
      }
      var chart = this.chart, log = this.logarithmic, options = this.options.crosshair.label, // the label's options
      horiz = this.horiz, // axis orientation
      opposite = this.opposite, // axis position
      left = this.left, // left position
      top = this.top, // top position
      crossLabel = this.crossLabel, // the svgElement
      posx, posy, crossBox, formatOption = options.format, formatFormat = '', limit, align, tickInside = this.options.tickPosition === 'inside', snap = this.crosshair.snap !== false, value, offset = 0, 
      // Use last available event (#5287)
      e = event.e || (this.cross && this.cross.e), point = event.point, min = this.min, max = this.max;
      if (log) {
          min = log.lin2log(min);
          max = log.lin2log(max);
      }
      align = (horiz ? 'center' : opposite ?
          (this.labelAlign === 'right' ? 'right' : 'left') :
          (this.labelAlign === 'left' ? 'left' : 'center'));
      // If the label does not exist yet, create it.
      if (!crossLabel) {
          crossLabel = this.crossLabel = chart.renderer
              .label(null, null, null, options.shape || 'callout')
              .addClass('highcharts-crosshair-label' + (this.series[0] &&
              ' highcharts-color-' + this.series[0].colorIndex))
              .attr({
              align: options.align || align,
              padding: pick(options.padding, 8),
              r: pick(options.borderRadius, 3),
              zIndex: 2
          })
              .add(this.labelGroup);
          // Presentational
          if (!chart.styledMode) {
              crossLabel
                  .attr({
                  fill: options.backgroundColor ||
                      (this.series[0] && this.series[0].color) ||
                      '#666666',
                  stroke: options.borderColor || '',
                  'stroke-width': options.borderWidth || 0
              })
                  .css(extend({
                  color: '#ffffff',
                  fontWeight: 'normal',
                  fontSize: '11px',
                  textAlign: 'center'
              }, options.style));
          }
      }
      if (horiz) {
          posx = snap ? point.plotX + left : e.chartX;
          posy = top + (opposite ? 0 : this.height);
      }
      else {
          posx = opposite ? this.width + left : 0;
          posy = snap ? point.plotY + top : e.chartY;
      }
      if (!formatOption && !options.formatter) {
          if (this.dateTime) {
              formatFormat = '%b %d, %Y';
          }
          formatOption =
              '{value' + (formatFormat ? ':' + formatFormat : '') + '}';
      }
      // Show the label
      value = snap ?
          point[this.isXAxis ? 'x' : 'y'] :
          this.toValue(horiz ? e.chartX : e.chartY);
      crossLabel.attr({
          text: formatOption ?
              format(formatOption, { value: value }, chart) :
              options.formatter.call(this, value),
          x: posx,
          y: posy,
          // Crosshair should be rendered within Axis range (#7219)
          visibility: value < min || value > max ?
              'hidden' :
              'visible'
      });
      crossBox = crossLabel.getBBox();
      // now it is placed we can correct its position
      if (horiz) {
          if ((tickInside && !opposite) || (!tickInside && opposite)) {
              posy = crossLabel.y - crossBox.height;
          }
      }
      else {
          posy = crossLabel.y - (crossBox.height / 2);
      }
      // check the edges
      if (horiz) {
          limit = {
              left: left - crossBox.x,
              right: left + this.width - crossBox.x
          };
      }
      else {
          limit = {
              left: this.labelAlign === 'left' ? left : 0,
              right: this.labelAlign === 'right' ?
                  left + this.width :
                  chart.chartWidth
          };
      }
      // left edge
      if (crossLabel.translateX < limit.left) {
          offset = limit.left - crossLabel.translateX;
      }
      // right edge
      if (crossLabel.translateX + crossBox.width >= limit.right) {
          offset = -(crossLabel.translateX + crossBox.width - limit.right);
      }
      // show the crosslabel
      crossLabel.attr({
          x: posx + offset,
          y: posy,
          // First set x and y, then anchorX and anchorY, when box is actually
          // calculated, #5702
          anchorX: horiz ?
              posx :
              (this.opposite ? 0 : chart.chartWidth),
          anchorY: horiz ?
              (this.opposite ? chart.chartHeight : 0) :
              posy + crossBox.height / 2
      });
  });
  /* ************************************************************************** *
   *  Start value compare logic                                                 *
   * ************************************************************************** */
  /**
   * Extend series.init by adding a method to modify the y value used for plotting
   * on the y axis. This method is called both from the axis when finding dataMin
   * and dataMax, and from the series.translate method.
   *
   * @ignore
   * @function Highcharts.Series#init
   */
  seriesProto.init = function () {
      // Call base method
      seriesInit.apply(this, arguments);
      // Set comparison mode
      this.setCompare(this.options.compare);
  };
  /**
   * Highstock only. Set the
   * [compare](https://api.highcharts.com/highstock/plotOptions.series.compare)
   * mode of the series after render time. In most cases it is more useful running
   * {@link Axis#setCompare} on the X axis to update all its series.
   *
   * @function Highcharts.Series#setCompare
   *
   * @param {string} [compare]
   *        Can be one of `null` (default), `"percent"` or `"value"`.
   */
  seriesProto.setCompare = function (compare) {
      // Set or unset the modifyValue method
      this.modifyValue = (compare === 'value' || compare === 'percent') ?
          function (value, point) {
              var compareValue = this.compareValue;
              if (typeof value !== 'undefined' &&
                  typeof compareValue !== 'undefined') { // #2601, #5814
                  // Get the modified value
                  if (compare === 'value') {
                      value -= compareValue;
                      // Compare percent
                  }
                  else {
                      value = 100 * (value / compareValue) -
                          (this.options.compareBase === 100 ? 0 : 100);
                  }
                  // record for tooltip etc.
                  if (point) {
                      point.change = value;
                  }
                  return value;
              }
              return 0;
          } :
          null;
      // Survive to export, #5485
      this.userOptions.compare = compare;
      // Mark dirty
      if (this.chart.hasRendered) {
          this.isDirty = true;
      }
  };
  /**
   * Extend series.processData by finding the first y value in the plot area,
   * used for comparing the following values
   *
   * @ignore
   * @function Highcharts.Series#processData
   */
  seriesProto.processData = function (force) {
      var series = this, i, keyIndex = -1, processedXData, processedYData, compareStart = series.options.compareStart === true ? 0 : 1, length, compareValue;
      // call base method
      seriesProcessData.apply(this, arguments);
      if (series.xAxis && series.processedYData) { // not pies
          // local variables
          processedXData = series.processedXData;
          processedYData = series.processedYData;
          length = processedYData.length;
          // For series with more than one value (range, OHLC etc), compare
          // against close or the pointValKey (#4922, #3112, #9854)
          if (series.pointArrayMap) {
              keyIndex = series.pointArrayMap.indexOf(series.options.pointValKey || series.pointValKey || 'y');
          }
          // find the first value for comparison
          for (i = 0; i < length - compareStart; i++) {
              compareValue = processedYData[i] && keyIndex > -1 ?
                  processedYData[i][keyIndex] :
                  processedYData[i];
              if (isNumber(compareValue) &&
                  processedXData[i + compareStart] >=
                      series.xAxis.min &&
                  compareValue !== 0) {
                  series.compareValue = compareValue;
                  break;
              }
          }
      }
      return;
  };
  // Modify series extremes
  addEvent(Series, 'afterGetExtremes', function (e) {
      var dataExtremes = e.dataExtremes;
      if (this.modifyValue && dataExtremes) {
          var extremes = [
              this.modifyValue(dataExtremes.dataMin),
              this.modifyValue(dataExtremes.dataMax)
          ];
          dataExtremes.dataMin = arrayMin(extremes);
          dataExtremes.dataMax = arrayMax(extremes);
      }
  });
  /**
   * Highstock only. Set the compare mode on all series belonging to an Y axis
   * after render time.
   *
   * @see [series.plotOptions.compare](https://api.highcharts.com/highstock/series.plotOptions.compare)
   *
   * @sample stock/members/axis-setcompare/
   *         Set compoare
   *
   * @function Highcharts.Axis#setCompare
   *
   * @param {string} [compare]
   *        The compare mode. Can be one of `null` (default), `"value"` or
   *        `"percent"`.
   *
   * @param {boolean} [redraw=true]
   *        Whether to redraw the chart or to wait for a later call to
   *        {@link Chart#redraw}.
   */
  Axis.prototype.setCompare = function (compare, redraw) {
      if (!this.isXAxis) {
          this.series.forEach(function (series) {
              series.setCompare(compare);
          });
          if (pick(redraw, true)) {
              this.chart.redraw();
          }
      }
  };
  /**
   * Extend the tooltip formatter by adding support for the point.change variable
   * as well as the changeDecimals option.
   *
   * @ignore
   * @function Highcharts.Point#tooltipFormatter
   *
   * @param {string} pointFormat
   */
  Point.prototype.tooltipFormatter = function (pointFormat) {
      var point = this;
      var numberFormatter = point.series.chart.numberFormatter;
      pointFormat = pointFormat.replace('{point.change}', (point.change > 0 ? '+' : '') + numberFormatter(point.change, pick(point.series.tooltipOptions.changeDecimals, 2)));
      return pointTooltipFormatter.apply(this, [pointFormat]);
  };
  /* ************************************************************************** *
   *  End value compare logic                                                   *
   * ************************************************************************** */
  // Extend the Series prototype to create a separate series clip box. This is
  // related to using multiple panes, and a future pane logic should incorporate
  // this feature (#2754).
  addEvent(Series, 'render', function () {
      var chart = this.chart, clipHeight;
      // Only do this on not 3d (#2939, #5904) nor polar (#6057) charts, and only
      // if the series type handles clipping in the animate method (#2975).
      if (!(chart.is3d && chart.is3d()) &&
          !chart.polar &&
          this.xAxis &&
          !this.xAxis.isRadial // Gauge, #6192
      ) {
          clipHeight = this.yAxis.len;
          // Include xAxis line width (#8031) but only if the Y axis ends on the
          // edge of the X axis (#11005).
          if (this.xAxis.axisLine) {
              var dist = chart.plotTop + chart.plotHeight -
                  this.yAxis.pos - this.yAxis.len, lineHeightCorrection = Math.floor(this.xAxis.axisLine.strokeWidth() / 2);
              if (dist >= 0) {
                  clipHeight -= Math.max(lineHeightCorrection - dist, 0);
              }
          }
          // First render, initial clip box
          if (!this.clipBox && this.animate) {
              this.clipBox = merge(chart.clipBox);
              this.clipBox.width = this.xAxis.len;
              this.clipBox.height = clipHeight;
              // On redrawing, resizing etc, update the clip rectangle
          }
          else if (chart[this.sharedClipKey]) {
              // animate in case resize is done during initial animation
              chart[this.sharedClipKey].animate({
                  width: this.xAxis.len,
                  height: clipHeight
              });
              // also change markers clip animation for consistency
              // (marker clip rects should exist only on chart init)
              if (chart[this.sharedClipKey + 'm']) {
                  chart[this.sharedClipKey + 'm'].animate({
                      width: this.xAxis.len
                  });
              }
          }
      }
  });
  addEvent(Chart, 'update', function (e) {
      var options = e.options;
      // Use case: enabling scrollbar from a disabled state.
      // Scrollbar needs to be initialized from a controller, Navigator in this
      // case (#6615)
      if ('scrollbar' in options && this.navigator) {
          merge(true, this.options.scrollbar, options.scrollbar);
          this.navigator.update({}, false);
          delete options.scrollbar;
      }
  });
  