/* *
 *
 *  (c) 2010-2019 Torstein Honsi
 *
 *  License: www.highcharts.com/license
 *
 *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
 *
 * */
'use strict';
import H from './Globals.js';
/**
 * @interface Highcharts.PointOptionsObject
 */ /**
* Individual point events
* @name Highcharts.PointOptionsObject#events
* @type {Highcharts.PlotSeriesPointEventsOptions}
*/ /**
* @name Highcharts.PointOptionsObject#marker
* @type {Highcharts.PlotSeriesPointMarkerOptions}
*/
/**
 * Function callback when a series has been animated.
 *
 * @callback Highcharts.SeriesAfterAnimateCallbackFunction
 *
 * @param {Highcharts.Series} this
 *        The series where the event occured.
 *
 * @param {Highcharts.SeriesAfterAnimateEventObject} event
 *        Event arguments.
 */
/**
 * Event information regarding completed animation of a series.
 *
 * @interface Highcharts.SeriesAfterAnimateEventObject
 */ /**
* Animated series.
* @name Highcharts.SeriesAfterAnimateEventObject#target
* @type {Highcharts.Series}
*/ /**
* Event type.
* @name Highcharts.SeriesAfterAnimateEventObject#type
* @type {"afterAnimate"}
*/
/**
 * Function callback when the checkbox next to the series' name in the legend is
 * clicked.
 *
 * @callback Highcharts.SeriesCheckboxClickCallbackFunction
 *
 * @param {Highcharts.Series} this
 *        The series where the event occured.
 *
 * @param {Highcharts.SeriesCheckboxClickEventObject} event
 *        Event arguments.
 */
/**
 * Event information regarding check of a series box.
 *
 * @interface Highcharts.SeriesCheckboxClickEventObject
 */ /**
* Whether the box has been checked.
* @name Highcharts.SeriesCheckboxClickEventObject#checked
* @type {boolean}
*/ /**
* Related series.
* @name Highcharts.SeriesCheckboxClickEventObject#item
* @type {Highcharts.Series}
*/ /**
* Related series.
* @name Highcharts.SeriesCheckboxClickEventObject#target
* @type {Highcharts.Series}
*/ /**
* Event type.
* @name Highcharts.SeriesCheckboxClickEventObject#type
* @type {"checkboxClick"}
*/
/**
 * Function callback when a series is clicked. Return false to cancel toogle
 * actions.
 *
 * @callback Highcharts.SeriesClickCallbackFunction
 *
 * @param {Highcharts.Series} this
 *        The series where the event occured.
 *
 * @param {Highcharts.SeriesClickEventObject} event
 *        Event arguments.
 */
/**
 * Common information for a click event on a series.
 *
 * @interface Highcharts.SeriesClickEventObject
 * @extends global.Event
 */ /**
* Nearest point on the graph.
* @name Highcharts.SeriesClickEventObject#point
* @type {Highcharts.Point}
*/
/**
 * Gets fired when the series is hidden after chart generation time, either by
 * clicking the legend item or by calling `.hide()`.
 *
 * @callback Highcharts.SeriesHideCallbackFunction
 *
 * @param {Highcharts.Series} this
 *        The series where the event occured.
 *
 * @param {global.Event} event
 *        The event that occured.
 */
/**
 * The SVG value used for the `stroke-linecap` and `stroke-linejoin` of a line
 * graph.
 *
 * @typedef {"butt"|"round"|"square"|string} Highcharts.SeriesLinecapValue
 */
/**
 * Gets fired when the legend item belonging to the series is clicked. The
 * default action is to toggle the visibility of the series. This can be
 * prevented by returning `false` or calling `event.preventDefault()`.
 *
 * @callback Highcharts.SeriesLegendItemClickCallbackFunction
 *
 * @param {Highcharts.Series} this
 *        The series where the event occured.
 *
 * @param {Highcharts.SeriesLegendItemClickEventObject} event
 *        The event that occured.
 */
/**
 * Information about the event.
 *
 * @interface Highcharts.SeriesLegendItemClickEventObject
 */ /**
* Related browser event.
* @name Highcharts.SeriesLegendItemClickEventObject#browserEvent
* @type {global.PointerEvent}
*/ /**
* Prevent the default action of toggle the visibility of the series.
* @name Highcharts.SeriesLegendItemClickEventObject#preventDefault
* @type {Function}
*/ /**
* Related series.
* @name Highcharts.SeriesCheckboxClickEventObject#target
* @type {Highcharts.Series}
*/ /**
* Event type.
* @name Highcharts.SeriesCheckboxClickEventObject#type
* @type {"checkboxClick"}
*/
/**
 * Gets fired when the mouse leaves the graph.
 *
 * @callback Highcharts.SeriesMouseOutCallbackFunction
 *
 * @param {Highcharts.Series} this
 *        Series where the event occured.
 *
 * @param {global.PointerEvent} event
 *        Event that occured.
 */
/**
 * Gets fired when the mouse enters the graph.
 *
 * @callback Highcharts.SeriesMouseOverCallbackFunction
 *
 * @param {Highcharts.Series} this
 *        Series where the event occured.
 *
 * @param {global.PointerEvent} event
 *        Event that occured.
 */
/**
 * Translation and scale for the plot area of a series.
 *
 * @interface Highcharts.SeriesPlotBoxObject
 */ /**
* @name Highcharts.SeriesPlotBoxObject#scaleX
* @type {number}
*/ /**
* @name Highcharts.SeriesPlotBoxObject#scaleY
* @type {number}
*/ /**
* @name Highcharts.SeriesPlotBoxObject#translateX
* @type {number}
*/ /**
* @name Highcharts.SeriesPlotBoxObject#translateY
* @type {number}
*/
/**
 * Gets fired when the series is shown after chart generation time, either by
 * clicking the legend item or by calling `.show()`.
 *
 * @callback Highcharts.SeriesShowCallbackFunction
 *
 * @param {Highcharts.Series} this
 *        Series where the event occured.
 *
 * @param {global.Event} event
 *        Event that occured.
 */
import U from './Utilities.js';
var defined = U.defined, erase = U.erase, isArray = U.isArray, isNumber = U.isNumber, isString = U.isString, objectEach = U.objectEach, splat = U.splat;
import './Options.js';
import './Legend.js';
import './Point.js';
import './SvgRenderer.js';
var addEvent = H.addEvent, animObject = H.animObject, arrayMax = H.arrayMax, arrayMin = H.arrayMin, correctFloat = H.correctFloat, defaultOptions = H.defaultOptions, defaultPlotOptions = H.defaultPlotOptions, extend = H.extend, fireEvent = H.fireEvent, LegendSymbolMixin = H.LegendSymbolMixin, // @todo add as a requirement
merge = H.merge, pick = H.pick, Point = H.Point, // @todo  add as a requirement
removeEvent = H.removeEvent, SVGElement = H.SVGElement, syncTimeout = H.syncTimeout, win = H.win;
/**
 * This is the base series prototype that all other series types inherit from.
 * A new series is initialized either through the
 * [series](https://api.highcharts.com/highcharts/series)
 * option structure, or after the chart is initialized, through
 * {@link Highcharts.Chart#addSeries}.
 *
 * The object can be accessed in a number of ways. All series and point event
 * handlers give a reference to the `series` object. The chart object has a
 * {@link Highcharts.Chart#series|series} property that is a collection of all
 * the chart's series. The point objects and axis objects also have the same
 * reference.
 *
 * Another way to reference the series programmatically is by `id`. Add an id
 * in the series configuration options, and get the series object by
 * {@link Highcharts.Chart#get}.
 *
 * Configuration options for the series are given in three levels. Options for
 * all series in a chart are given in the
 * [plotOptions.series](https://api.highcharts.com/highcharts/plotOptions.series)
 * object. Then options for all series of a specific type
 * are given in the plotOptions of that type, for example `plotOptions.line`.
 * Next, options for one single series are given in the series array, or as
 * arguments to `chart.addSeries`.
 *
 * The data in the series is stored in various arrays.
 *
 * - First, `series.options.data` contains all the original config options for
 *   each point whether added by options or methods like `series.addPoint`.
 *
 * - Next, `series.data` contains those values converted to points, but in case
 *   the series data length exceeds the `cropThreshold`, or if the data is
 *   grouped, `series.data` doesn't contain all the points. It only contains the
 *   points that have been created on demand.
 *
 * - Then there's `series.points` that contains all currently visible point
 *   objects. In case of cropping, the cropped-away points are not part of this
 *   array. The `series.points` array starts at `series.cropStart` compared to
 *   `series.data` and `series.options.data`. If however the series data is
 *   grouped, these can't be correlated one to one.
 *
 * - `series.xData` and `series.processedXData` contain clean x values,
 *   equivalent to `series.data` and `series.points`.
 *
 * - `series.yData` and `series.processedYData` contain clean y values,
 *   equivalent to `series.data` and `series.points`.
 *
 * @class
 * @name Highcharts.Series
 *
 * @param {Highcharts.Chart} chart
 *        The chart instance.
 *
 * @param {Highcharts.SeriesOptionsType|object} options
 *        The series options.
 */ /**
* The line series is the base type and is therefor the series base prototype.
*
* @private
* @class
* @name Highcharts.seriesTypes.line
*
* @augments Highcharts.Series
*/
H.Series = H.seriesType('line', 
/**
 * Series options for specific data and the data itself. In TypeScript you
 * have to cast the series options to specific series types, to get all
 * possible options for a series.
 *
 * @example
 * // TypeScript example
 * Highcharts.chart('container', {
 *     series: [{
 *         color: '#06C',
 *         data: [[0, 1], [2, 3]]
 *     } as Highcharts.SeriesLineOptions ]
 * });
 *
 * @type      {Array<*>}
 * @apioption series
 */
/**
 * An id for the series. This can be used after render time to get a pointer
 * to the series object through `chart.get()`.
 *
 * @sample {highcharts} highcharts/plotoptions/series-id/
 *         Get series by id
 *
 * @type      {string}
 * @since     1.2.0
 * @apioption series.id
 */
/**
 * The index of the series in the chart, affecting the internal index in the
 * `chart.series` array, the visible Z index as well as the order in the
 * legend.
 *
 * @type      {number}
 * @since     2.3.0
 * @apioption series.index
 */
/**
 * The sequential index of the series in the legend.
 *
 * @see [legend.reversed](#legend.reversed),
 *      [yAxis.reversedStacks](#yAxis.reversedStacks)
 *
 * @sample {highcharts|highstock} highcharts/series/legendindex/
 *         Legend in opposite order
 *
 * @type      {number}
 * @apioption series.legendIndex
 */
/**
 * The name of the series as shown in the legend, tooltip etc.
 *
 * @sample {highcharts} highcharts/series/name/
 *         Series name
 * @sample {highmaps} maps/demo/category-map/
 *         Series name
 *
 * @type      {string}
 * @apioption series.name
 */
/**
 * This option allows grouping series in a stacked chart. The stack option
 * can be a string or anything else, as long as the grouped series' stack
 * options match each other after conversion into a string.
 *
 * @sample {highcharts} highcharts/series/stack/
 *         Stacked and grouped columns
 *
 * @type      {number|string}
 * @since     2.1
 * @product   highcharts highstock
 * @apioption series.stack
 */
/**
 * The type of series, for example `line` or `column`. By default, the
 * series type is inherited from [chart.type](#chart.type), so unless the
 * chart is a combination of series types, there is no need to set it on the
 * series level.
 *
 * In TypeScript instead the `type` option must always be set.
 *
 * @sample {highcharts} highcharts/series/type/
 *         Line and column in the same chart
 * @sample highcharts/series/type-dynamic/
 *         Dynamic types with button selector
 * @sample {highmaps} maps/demo/mapline-mappoint/
 *         Multiple types in the same map
 *
 * @type      {string}
 * @apioption series.type
 */
/**
 * When using dual or multiple x axes, this number defines which xAxis the
 * particular series is connected to. It refers to either the
 * {@link #xAxis.id|axis id}
 * or the index of the axis in the xAxis array, with 0 being the first.
 *
 * @type      {number|string}
 * @default   0
 * @product   highcharts highstock
 * @apioption series.xAxis
 */
/**
 * When using dual or multiple y axes, this number defines which yAxis the
 * particular series is connected to. It refers to either the
 * {@link #yAxis.id|axis id}
 * or the index of the axis in the yAxis array, with 0 being the first.
 *
 * @sample {highcharts} highcharts/series/yaxis/
 *         Apply the column series to the secondary Y axis
 *
 * @type      {number|string}
 * @default   0
 * @product   highcharts highstock
 * @apioption series.yAxis
 */
/**
 * Define the visual z index of the series.
 *
 * @sample {highcharts} highcharts/plotoptions/series-zindex-default/
 *         With no z index, the series defined last are on top
 * @sample {highcharts} highcharts/plotoptions/series-zindex/
 *         With a z index, the series with the highest z index is on top
 * @sample {highstock} highcharts/plotoptions/series-zindex-default/
 *         With no z index, the series defined last are on top
 * @sample {highstock} highcharts/plotoptions/series-zindex/
 *         With a z index, the series with the highest z index is on top
 *
 * @type      {number}
 * @product   highcharts highstock
 * @apioption series.zIndex
 */
null, 
/**
 * General options for all series types.
 *
 * @optionparent plotOptions.series
 */
{
    /**
     * The SVG value used for the `stroke-linecap` and `stroke-linejoin`
     * of a line graph. Round means that lines are rounded in the ends and
     * bends.
     *
     * @type       {Highcharts.SeriesLinecapValue}
     * @default    round
     * @since      3.0.7
     * @apioption  plotOptions.line.linecap
     */
    /**
     * Pixel width of the graph line.
     *
     * @see In styled mode, the line stroke-width can be set with the
     *      `.highcharts-graph` class name.
     *
     * @sample {highcharts} highcharts/plotoptions/series-linewidth-general/
     *         On all series
     * @sample {highcharts} highcharts/plotoptions/series-linewidth-specific/
     *         On one single series
     *
     * @product highcharts highstock
     *
     * @private
     */
    lineWidth: 2,
    /**
     * For some series, there is a limit that shuts down initial animation
     * by default when the total number of points in the chart is too high.
     * For example, for a column chart and its derivatives, animation does
     * not run if there is more than 250 points totally. To disable this
     * cap, set `animationLimit` to `Infinity`.
     *
     * @type      {number}
     * @apioption plotOptions.series.animationLimit
     */
    /**
     * Allow this series' points to be selected by clicking on the graphic
     * (columns, point markers, pie slices, map areas etc).
     *
     * The selected points can be handled by point select and unselect
     * events, or collectively by the [getSelectedPoints](
     * Highcharts.Chart#getSelectedPoints) function.
     *
     * And alternative way of selecting points is through dragging.
     *
     * @sample {highcharts} highcharts/plotoptions/series-allowpointselect-line/
     *         Line
     * @sample {highcharts} highcharts/plotoptions/series-allowpointselect-column/
     *         Column
     * @sample {highcharts} highcharts/plotoptions/series-allowpointselect-pie/
     *         Pie
     * @sample {highcharts} highcharts/chart/events-selection-points/
     *         Select a range of points through a drag selection
     * @sample {highmaps} maps/plotoptions/series-allowpointselect/
     *         Map area
     * @sample {highmaps} maps/plotoptions/mapbubble-allowpointselect/
     *         Map bubble
     *
     * @since 1.2.0
     *
     * @private
     */
    allowPointSelect: false,
    /**
     * If true, a checkbox is displayed next to the legend item to allow
     * selecting the series. The state of the checkbox is determined by
     * the `selected` option.
     *
     * @productdesc {highmaps}
     * Note that if a `colorAxis` is defined, the color axis is represented
     * in the legend, not the series.
     *
     * @sample {highcharts} highcharts/plotoptions/series-showcheckbox-true/
     *         Show select box
     *
     * @since 1.2.0
     *
     * @private
     */
    showCheckbox: false,
    /**
     * Enable or disable the initial animation when a series is displayed.
     * The animation can also be set as a configuration object. Please
     * note that this option only applies to the initial animation of the
     * series itself. For other animations, see [chart.animation](
     * #chart.animation) and the animation parameter under the API methods.
     * The following properties are supported:
     *
     * - `duration`: The duration of the animation in milliseconds.
     *
     * - `easing`: Can be a string reference to an easing function set on
     *   the `Math` object or a function. See the _Custom easing function_
     *   demo below.
     *
     * Due to poor performance, animation is disabled in old IE browsers
     * for several chart types.
     *
     * @sample {highcharts} highcharts/plotoptions/series-animation-disabled/
     *         Animation disabled
     * @sample {highcharts} highcharts/plotoptions/series-animation-slower/
     *         Slower animation
     * @sample {highcharts} highcharts/plotoptions/series-animation-easing/
     *         Custom easing function
     * @sample {highstock} stock/plotoptions/animation-slower/
     *         Slower animation
     * @sample {highstock} stock/plotoptions/animation-easing/
     *         Custom easing function
     * @sample {highmaps} maps/plotoptions/series-animation-true/
     *         Animation enabled on map series
     * @sample {highmaps} maps/plotoptions/mapbubble-animation-false/
     *         Disabled on mapbubble series
     *
     * @type    {boolean|Highcharts.AnimationOptionsObject}
     * @default {highcharts} true
     * @default {highstock} true
     * @default {highmaps} false
     *
     * @private
     */
    animation: {
        /**
         * @type      {number}
         * @default   1000
         * @apioption plotOptions.series.animation.duration
         */
        duration: 1000
    },
    /**
     * An additional class name to apply to the series' graphical elements.
     * This option does not replace default class names of the graphical
     * element.
     *
     * @type      {string}
     * @since     5.0.0
     * @apioption plotOptions.series.className
     */
    /**
     * Disable this option to allow series rendering in the whole plotting
     * area.
     *
     * **Note:** Clipping should be always enabled when
     * [chart.zoomType](#chart.zoomType) is set
     *
     * @sample {highcharts} highcharts/plotoptions/series-clip/
     *         Disabled clipping
     *
     * @default   true
     * @type      {boolean}
     * @since     3.0.0
     * @apioption plotOptions.series.clip
     */
    /**
     * The main color of the series. In line type series it applies to the
     * line and the point markers unless otherwise specified. In bar type
     * series it applies to the bars unless a color is specified per point.
     * The default value is pulled from the `options.colors` array.
     *
     * In styled mode, the color can be defined by the
     * [colorIndex](#plotOptions.series.colorIndex) option. Also, the series
     * color can be set with the `.highcharts-series`,
     * `.highcharts-color-{n}`, `.highcharts-{type}-series` or
     * `.highcharts-series-{n}` class, or individual classes given by the
     * `className` option.
     *
     * @productdesc {highmaps}
     * In maps, the series color is rarely used, as most choropleth maps use
     * the color to denote the value of each point. The series color can
     * however be used in a map with multiple series holding categorized
     * data.
     *
     * @sample {highcharts} highcharts/plotoptions/series-color-general/
     *         General plot option
     * @sample {highcharts} highcharts/plotoptions/series-color-specific/
     *         One specific series
     * @sample {highcharts} highcharts/plotoptions/series-color-area/
     *         Area color
     * @sample {highcharts} highcharts/series/infographic/
     *         Pattern fill
     * @sample {highmaps} maps/demo/category-map/
     *         Category map by multiple series
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @apioption plotOptions.series.color
     */
    /**
     * Styled mode only. A specific color index to use for the series, so
     * its graphic representations are given the class name
     * `highcharts-color-{n}`.
     *
     * @type      {number}
     * @since     5.0.0
     * @apioption plotOptions.series.colorIndex
     */
    /**
     * Whether to connect a graph line across null points, or render a gap
     * between the two points on either side of the null.
     *
     * @sample {highcharts} highcharts/plotoptions/series-connectnulls-false/
     *         False by default
     * @sample {highcharts} highcharts/plotoptions/series-connectnulls-true/
     *         True
     *
     * @type      {boolean}
     * @default   false
     * @product   highcharts highstock
     * @apioption plotOptions.series.connectNulls
     */
    /**
     * You can set the cursor to "pointer" if you have click events attached
     * to the series, to signal to the user that the points and lines can
     * be clicked.
     *
     * In styled mode, the series cursor can be set with the same classes
     * as listed under [series.color](#plotOptions.series.color).
     *
     * @sample {highcharts} highcharts/plotoptions/series-cursor-line/
     *         On line graph
     * @sample {highcharts} highcharts/plotoptions/series-cursor-column/
     *         On columns
     * @sample {highcharts} highcharts/plotoptions/series-cursor-scatter/
     *         On scatter markers
     * @sample {highstock} stock/plotoptions/cursor/
     *         Pointer on a line graph
     * @sample {highmaps} maps/plotoptions/series-allowpointselect/
     *         Map area
     * @sample {highmaps} maps/plotoptions/mapbubble-allowpointselect/
     *         Map bubble
     *
     * @type      {string|Highcharts.CursorValue}
     * @apioption plotOptions.series.cursor
     */
    /**
     * A name for the dash style to use for the graph, or for some series
     * types the outline of each shape.
     *
     * In styled mode, the
     * [stroke dash-array](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/css/series-dashstyle/)
     * can be set with the same classes as listed under
     * [series.color](#plotOptions.series.color).
     *
     * @sample {highcharts} highcharts/plotoptions/series-dashstyle-all/
     *         Possible values demonstrated
     * @sample {highcharts} highcharts/plotoptions/series-dashstyle/
     *         Chart suitable for printing in black and white
     * @sample {highstock} highcharts/plotoptions/series-dashstyle-all/
     *         Possible values demonstrated
     * @sample {highmaps} highcharts/plotoptions/series-dashstyle-all/
     *         Possible values demonstrated
     * @sample {highmaps} maps/plotoptions/series-dashstyle/
     *         Dotted borders on a map
     *
     * @type      {Highcharts.DashStyleValue}
     * @default   Solid
     * @since     2.1
     * @apioption plotOptions.series.dashStyle
     */
    /**
     * Requires the Accessibility module.
     *
     * A description of the series to add to the screen reader information
     * about the series.
     *
     * @type      {string}
     * @since     5.0.0
     * @apioption plotOptions.series.description
     */
    /**
     * Enable or disable the mouse tracking for a specific series. This
     * includes point tooltips and click events on graphs and points. For
     * large datasets it improves performance.
     *
     * @sample {highcharts} highcharts/plotoptions/series-enablemousetracking-false/
     *         No mouse tracking
     * @sample {highmaps} maps/plotoptions/series-enablemousetracking-false/
     *         No mouse tracking
     *
     * @type      {boolean}
     * @default   true
     * @apioption plotOptions.series.enableMouseTracking
     */
    /**
     * Whether to use the Y extremes of the total chart width or only the
     * zoomed area when zooming in on parts of the X axis. By default, the
     * Y axis adjusts to the min and max of the visible data. Cartesian
     * series only.
     *
     * @type      {boolean}
     * @default   false
     * @since     4.1.6
     * @product   highcharts highstock gantt
     * @apioption plotOptions.series.getExtremesFromAll
     */
    /**
     * An array specifying which option maps to which key in the data point
     * array. This makes it convenient to work with unstructured data arrays
     * from different sources.
     *
     * @see [series.data](#series.line.data)
     *
     * @sample {highcharts|highstock} highcharts/series/data-keys/
     *         An extended data array with keys
     * @sample {highcharts|highstock} highcharts/series/data-nested-keys/
     *         Nested keys used to access object properties
     *
     * @type      {Array<string>}
     * @since     4.1.6
     * @apioption plotOptions.series.keys
     */
    /**
     * The line cap used for line ends and line joins on the graph.
     *
     * @type       {Highcharts.SeriesLinecapValue}
     * @default    round
     * @product    highcharts highstock
     * @apioption  plotOptions.series.linecap
     */
    /**
     * The [id](#series.id) of another series to link to. Additionally,
     * the value can be ":previous" to link to the previous series. When
     * two series are linked, only the first one appears in the legend.
     * Toggling the visibility of this also toggles the linked series.
     *
     * @sample {highcharts|highstock} highcharts/demo/arearange-line/
     *         Linked series
     *
     * @type      {string}
     * @since     3.0
     * @product   highcharts highstock gantt
     * @apioption plotOptions.series.linkedTo
     */
    /**
     * Options for the corresponding navigator series if `showInNavigator`
     * is `true` for this series. Available options are the same as any
     * series, documented at [plotOptions](#plotOptions.series) and
     * [series](#series).
     *
     * These options are merged with options in [navigator.series](
     * #navigator.series), and will take precedence if the same option is
     * defined both places.
     *
     * @see [navigator.series](#navigator.series)
     *
     * @type      {Highcharts.PlotSeriesOptions}
     * @since     5.0.0
     * @product   highstock
     * @apioption plotOptions.series.navigatorOptions
     */
    /**
     * The color for the parts of the graph or points that are below the
     * [threshold](#plotOptions.series.threshold).
     *
     * @see In styled mode, a negative color is applied by setting this option
     *      to `true` combined with the `.highcharts-negative` class name.
     *
     * @sample {highcharts} highcharts/plotoptions/series-negative-color/
     *         Spline, area and column
     * @sample {highcharts} highcharts/plotoptions/arearange-negativecolor/
     *         Arearange
     * @sample {highcharts} highcharts/css/series-negative-color/
     *         Styled mode
     * @sample {highstock} highcharts/plotoptions/series-negative-color/
     *         Spline, area and column
     * @sample {highstock} highcharts/plotoptions/arearange-negativecolor/
     *         Arearange
     * @sample {highmaps} highcharts/plotoptions/series-negative-color/
     *         Spline, area and column
     * @sample {highmaps} highcharts/plotoptions/arearange-negativecolor/
     *         Arearange
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @since     3.0
     * @apioption plotOptions.series.negativeColor
     */
    /**
     * Same as
     * [accessibility.pointDescriptionFormatter](#accessibility.pointDescriptionFormatter),
     * but for an individual series. Overrides the chart wide configuration.
     *
     * @type      {Function}
     * @since     5.0.12
     * @apioption plotOptions.series.pointDescriptionFormatter
     */
    /**
     * If no x values are given for the points in a series, `pointInterval`
     * defines the interval of the x values. For example, if a series
     * contains one value every decade starting from year 0, set
     * `pointInterval` to `10`. In true `datetime` axes, the `pointInterval`
     * is set in milliseconds.
     *
     * It can be also be combined with `pointIntervalUnit` to draw irregular
     * time intervals.
     *
     * Please note that this options applies to the _series data_, not the
     * interval of the axis ticks, which is independent.
     *
     * @sample {highcharts} highcharts/plotoptions/series-pointstart-datetime/
     *         Datetime X axis
     * @sample {highstock} stock/plotoptions/pointinterval-pointstart/
     *         Using pointStart and pointInterval
     *
     * @type      {number}
     * @default   1
     * @product   highcharts highstock gantt
     * @apioption plotOptions.series.pointInterval
     */
    /**
     * On datetime series, this allows for setting the
     * [pointInterval](#plotOptions.series.pointInterval) to irregular time
     * units, `day`, `month` and `year`. A day is usually the same as 24
     * hours, but `pointIntervalUnit` also takes the DST crossover into
     * consideration when dealing with local time. Combine this option with
     * `pointInterval` to draw weeks, quarters, 6 months, 10 years etc.
     *
     * Please note that this options applies to the _series data_, not the
     * interval of the axis ticks, which is independent.
     *
     * @sample {highcharts} highcharts/plotoptions/series-pointintervalunit/
     *         One point a month
     * @sample {highstock} highcharts/plotoptions/series-pointintervalunit/
     *         One point a month
     *
     * @type       {string}
     * @since      4.1.0
     * @product    highcharts highstock gantt
     * @validvalue ["day", "month", "year"]
     * @apioption  plotOptions.series.pointIntervalUnit
     */
    /**
     * Possible values: `"on"`, `"between"`, `number`.
     *
     * In a column chart, when pointPlacement is `"on"`, the point will not
     * create any padding of the X axis. In a polar column chart this means
     * that the first column points directly north. If the pointPlacement is
     * `"between"`, the columns will be laid out between ticks. This is
     * useful for example for visualising an amount between two points in
     * time or in a certain sector of a polar chart.
     *
     * Since Highcharts 3.0.2, the point placement can also be numeric,
     * where 0 is on the axis value, -0.5 is between this value and the
     * previous, and 0.5 is between this value and the next. Unlike the
     * textual options, numeric point placement options won't affect axis
     * padding.
     *
     * Note that pointPlacement needs a [pointRange](
     * #plotOptions.series.pointRange) to work. For column series this is
     * computed, but for line-type series it needs to be set.
     *
     * For the `xrange` series type and gantt charts, if the Y axis is a
     * category axis, the `pointPlacement` applies to the Y axis rather than
     * the (typically datetime) X axis.
     *
     * Defaults to `undefined` in cartesian charts, `"between"` in polar
     * charts.
     *
     * @see [xAxis.tickmarkPlacement](#xAxis.tickmarkPlacement)
     *
     * @sample {highcharts|highstock} highcharts/plotoptions/series-pointplacement-between/
     *         Between in a column chart
     * @sample {highcharts|highstock} highcharts/plotoptions/series-pointplacement-numeric/
     *         Numeric placement for custom layout
     * @sample {highcharts|highstock} maps/plotoptions/heatmap-pointplacement/
     *         Placement in heatmap
     *
     * @type      {string|number}
     * @since     2.3.0
     * @product   highcharts highstock gantt
     * @apioption plotOptions.series.pointPlacement
     */
    /**
     * If no x values are given for the points in a series, pointStart
     * defines on what value to start. For example, if a series contains one
     * yearly value starting from 1945, set pointStart to 1945.
     *
     * @sample {highcharts} highcharts/plotoptions/series-pointstart-linear/
     *         Linear
     * @sample {highcharts} highcharts/plotoptions/series-pointstart-datetime/
     *         Datetime
     * @sample {highstock} stock/plotoptions/pointinterval-pointstart/
     *         Using pointStart and pointInterval
     *
     * @type      {number}
     * @default   0
     * @product   highcharts highstock gantt
     * @apioption plotOptions.series.pointStart
     */
    /**
     * Whether to select the series initially. If `showCheckbox` is true,
     * the checkbox next to the series name in the legend will be checked
     * for a selected series.
     *
     * @sample {highcharts} highcharts/plotoptions/series-selected/
     *         One out of two series selected
     *
     * @type      {boolean}
     * @default   false
     * @since     1.2.0
     * @apioption plotOptions.series.selected
     */
    /**
     * Whether to apply a drop shadow to the graph line. Since 2.3 the
     * shadow can be an object configuration containing `color`, `offsetX`,
     * `offsetY`, `opacity` and `width`.
     *
     * @sample {highcharts} highcharts/plotoptions/series-shadow/
     *         Shadow enabled
     *
     * @type      {boolean|Highcharts.ShadowOptionsObject}
     * @default   false
     * @apioption plotOptions.series.shadow
     */
    /**
     * Whether to display this particular series or series type in the
     * legend. The default value is `true` for standalone series, `false`
     * for linked series.
     *
     * @sample {highcharts} highcharts/plotoptions/series-showinlegend/
     *         One series in the legend, one hidden
     *
     * @type      {boolean}
     * @default   true
     * @apioption plotOptions.series.showInLegend
     */
    /**
     * Whether or not to show the series in the navigator. Takes precedence
     * over [navigator.baseSeries](#navigator.baseSeries) if defined.
     *
     * @type      {boolean}
     * @since     5.0.0
     * @product   highstock
     * @apioption plotOptions.series.showInNavigator
     */
    /**
     * If set to `true`, the accessibility module will skip past the points
     * in this series for keyboard navigation.
     *
     * @type      {boolean}
     * @since     5.0.12
     * @apioption plotOptions.series.skipKeyboardNavigation
     */
    /**
     * Whether to stack the values of each series on top of each other.
     * Possible values are `undefined` to disable, `"normal"` to stack by
     * value or `"percent"`. When stacking is enabled, data must be sorted
     * in ascending X order. A special stacking option is with the
     * streamgraph series type, where the stacking option is set to
     * `"stream"`. The second one is `"overlap"`, which only applies to
     * waterfall series.
     *
     * @see [yAxis.reversedStacks](#yAxis.reversedStacks)
     *
     * @sample {highcharts} highcharts/plotoptions/series-stacking-line/
     *         Line
     * @sample {highcharts} highcharts/plotoptions/series-stacking-column/
     *         Column
     * @sample {highcharts} highcharts/plotoptions/series-stacking-bar/
     *         Bar
     * @sample {highcharts} highcharts/plotoptions/series-stacking-area/
     *         Area
     * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-line/
     *         Line
     * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-column/
     *         Column
     * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-bar/
     *         Bar
     * @sample {highcharts} highcharts/plotoptions/series-stacking-percent-area/
     *         Area
     * @sample {highcharts} highcharts/plotoptions/series-waterfall-with-normal-stacking
     *         Waterfall with normal stacking
     * @sample {highcharts} highcharts/plotoptions/series-waterfall-with-overlap-stacking
     *         Waterfall with overlap stacking
     * @sample {highstock} stock/plotoptions/stacking/
     *         Area
     *
     * @type       {string}
     * @product    highcharts highstock
     * @validvalue ["normal", "overlap", "percent", "stream"]
     * @apioption  plotOptions.series.stacking
     */
    /**
     * Whether to apply steps to the line. Possible values are `left`,
     * `center` and `right`.
     *
     * @sample {highcharts} highcharts/plotoptions/line-step/
     *         Different step line options
     * @sample {highcharts} highcharts/plotoptions/area-step/
     *         Stepped, stacked area
     * @sample {highstock} stock/plotoptions/line-step/
     *         Step line
     *
     * @type       {string}
     * @since      1.2.5
     * @product    highcharts highstock
     * @validvalue ["left", "center", "right"]
     * @apioption  plotOptions.series.step
     */
    /**
     * The threshold, also called zero level or base level. For line type
     * series this is only used in conjunction with
     * [negativeColor](#plotOptions.series.negativeColor).
     *
     * @see [softThreshold](#plotOptions.series.softThreshold).
     *
     * @type      {number}
     * @default   0
     * @since     3.0
     * @product   highcharts highstock
     * @apioption plotOptions.series.threshold
     */
    /**
     * Set the initial visibility of the series.
     *
     * @sample {highcharts} highcharts/plotoptions/series-visible/
     *         Two series, one hidden and one visible
     * @sample {highstock} stock/plotoptions/series-visibility/
     *         Hidden series
     *
     * @type      {boolean}
     * @default   true
     * @apioption plotOptions.series.visible
     */
    /**
     * Defines the Axis on which the zones are applied.
     *
     * @see [zones](#plotOptions.series.zones)
     *
     * @sample {highcharts} highcharts/series/color-zones-zoneaxis-x/
     *         Zones on the X-Axis
     * @sample {highstock} highcharts/series/color-zones-zoneaxis-x/
     *         Zones on the X-Axis
     *
     * @type      {string}
     * @default   y
     * @since     4.1.0
     * @product   highcharts highstock
     * @apioption plotOptions.series.zoneAxis
     */
    /**
     * General event handlers for the series items. These event hooks can
     * also be attached to the series at run time using the
     * `Highcharts.addEvent` function.
     *
     * @private
     */
    events: {},
    /**
     * Fires after the series has finished its initial animation, or in case
     * animation is disabled, immediately as the series is displayed.
     *
     * @sample {highcharts} highcharts/plotoptions/series-events-afteranimate/
     *         Show label after animate
     * @sample {highstock} highcharts/plotoptions/series-events-afteranimate/
     *         Show label after animate
     *
     * @type      {Highcharts.SeriesAfterAnimateCallbackFunction}
     * @since     4.0
     * @product   highcharts highstock gantt
     * @context   Highcharts.Series
     * @apioption plotOptions.series.events.afterAnimate
     */
    /**
     * Fires when the checkbox next to the series' name in the legend is
     * clicked. One parameter, `event`, is passed to the function. The state
     * of the checkbox is found by `event.checked`. The checked item is
     * found by `event.item`. Return `false` to prevent the default action
     * which is to toggle the select state of the series.
     *
     * @sample {highcharts} highcharts/plotoptions/series-events-checkboxclick/
     *         Alert checkbox status
     *
     * @type      {Highcharts.SeriesCheckboxClickCallbackFunction}
     * @since     1.2.0
     * @context   Highcharts.Series
     * @apioption plotOptions.series.events.checkboxClick
     */
    /**
     * Fires when the series is clicked. One parameter, `event`, is passed
     * to the function, containing common event information. Additionally,
     * `event.point` holds a pointer to the nearest point on the graph.
     *
     * @sample {highcharts} highcharts/plotoptions/series-events-click/
     *         Alert click info
     * @sample {highstock} stock/plotoptions/series-events-click/
     *         Alert click info
     * @sample {highmaps} maps/plotoptions/series-events-click/
     *         Display click info in subtitle
     *
     * @type      {Highcharts.SeriesClickCallbackFunction}
     * @context   Highcharts.Series
     * @apioption plotOptions.series.events.click
     */
    /**
     * Fires when the series is hidden after chart generation time, either
     * by clicking the legend item or by calling `.hide()`.
     *
     * @sample {highcharts} highcharts/plotoptions/series-events-hide/
     *         Alert when the series is hidden by clicking the legend item
     *
     * @type      {Highcharts.SeriesHideCallbackFunction}
     * @since     1.2.0
     * @context   Highcharts.Series
     * @apioption plotOptions.series.events.hide
     */
    /**
     * Fires when the legend item belonging to the series is clicked. One
     * parameter, `event`, is passed to the function. The default action
     * is to toggle the visibility of the series. This can be prevented
     * by returning `false` or calling `event.preventDefault()`.
     *
     * @sample {highcharts} highcharts/plotoptions/series-events-legenditemclick/
     *         Confirm hiding and showing
     *
     * @type      {Highcharts.SeriesLegendItemClickCallbackFunction}
     * @context   Highcharts.Series
     * @apioption plotOptions.series.events.legendItemClick
     */
    /**
     * Fires when the mouse leaves the graph. One parameter, `event`, is
     * passed to the function, containing common event information. If the
     * [stickyTracking](#plotOptions.series) option is true, `mouseOut`
     * doesn't happen before the mouse enters another graph or leaves the
     * plot area.
     *
     * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-sticky/
     *         With sticky tracking by default
     * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-no-sticky/
     *         Without sticky tracking
     *
     * @type      {Highcharts.SeriesMouseOutCallbackFunction}
     * @context   Highcharts.Series
     * @apioption plotOptions.series.events.mouseOut
     */
    /**
     * Fires when the mouse enters the graph. One parameter, `event`, is
     * passed to the function, containing common event information.
     *
     * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-sticky/
     *         With sticky tracking by default
     * @sample {highcharts} highcharts/plotoptions/series-events-mouseover-no-sticky/
     *         Without sticky tracking
     *
     * @type      {Highcharts.SeriesMouseOverCallbackFunction}
     * @context   Highcharts.Series
     * @apioption plotOptions.series.events.mouseOver
     */
    /**
     * Fires when the series is shown after chart generation time, either
     * by clicking the legend item or by calling `.show()`.
     *
     * @sample {highcharts} highcharts/plotoptions/series-events-show/
     *         Alert when the series is shown by clicking the legend item.
     *
     * @type      {Highcharts.SeriesShowCallbackFunction}
     * @since     1.2.0
     * @context   Highcharts.Series
     * @apioption plotOptions.series.events.show
     */
    /**
     * Options for the point markers of line-like series. Properties like
     * `fillColor`, `lineColor` and `lineWidth` define the visual appearance
     * of the markers. Other series types, like column series, don't have
     * markers, but have visual options on the series level instead.
     *
     * In styled mode, the markers can be styled with the
     * `.highcharts-point`, `.highcharts-point-hover` and
     * `.highcharts-point-select` class names.
     *
     * @private
     */
    marker: {
        /**
         * The width of the point marker's outline.
         *
         * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/
         *         2px blue marker
         */
        lineWidth: 0,
        /**
         * The color of the point marker's outline. When `undefined`, the
         * series' or point's color is used.
         *
         * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/
         *         Inherit from series color (undefined)
         *
         * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
         */
        lineColor: '#ffffff',
        /**
         * The fill color of the point marker. When `undefined`, the series'
         * or point's color is used.
         *
         * @sample {highcharts} highcharts/plotoptions/series-marker-fillcolor/
         *         White fill
         *
         * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
         * @apioption plotOptions.series.marker.fillColor
         */
        /**
         * Enable or disable the point marker. If `undefined`, the markers
         * are hidden when the data is dense, and shown for more widespread
         * data points.
         *
         * @sample {highcharts} highcharts/plotoptions/series-marker-enabled/
         *         Disabled markers
         * @sample {highcharts} highcharts/plotoptions/series-marker-enabled-false/
         *         Disabled in normal state but enabled on hover
         * @sample {highstock} stock/plotoptions/series-marker/
         *         Enabled markers
         *
         * @type      {boolean}
         * @default   {highcharts} undefined
         * @default   {highstock} false
         * @apioption plotOptions.series.marker.enabled
         */
        /**
         * Image markers only. Set the image width explicitly. When using
         * this option, a `width` must also be set.
         *
         * @sample {highcharts} highcharts/plotoptions/series-marker-width-height/
         *         Fixed width and height
         * @sample {highstock} highcharts/plotoptions/series-marker-width-height/
         *         Fixed width and height
         *
         * @type      {number}
         * @since     4.0.4
         * @apioption plotOptions.series.marker.height
         */
        /**
         * A predefined shape or symbol for the marker. When undefined, the
         * symbol is pulled from options.symbols. Other possible values are
         * "circle", "square", "diamond", "triangle" and "triangle-down".
         *
         * Additionally, the URL to a graphic can be given on this form:
         * "url(graphic.png)". Note that for the image to be applied to
         * exported charts, its URL needs to be accessible by the export
         * server.
         *
         * Custom callbacks for symbol path generation can also be added to
         * `Highcharts.SVGRenderer.prototype.symbols`. The callback is then
         * used by its method name, as shown in the demo.
         *
         * @sample {highcharts} highcharts/plotoptions/series-marker-symbol/
         *         Predefined, graphic and custom markers
         * @sample {highstock} highcharts/plotoptions/series-marker-symbol/
         *         Predefined, graphic and custom markers
         *
         * @type      {string}
         * @apioption plotOptions.series.marker.symbol
         */
        /**
         * The threshold for how dense the point markers should be before
         * they are hidden, given that `enabled` is not defined. The number
         * indicates the horizontal distance between the two closest points
         * in the series, as multiples of the `marker.radius`. In other
         * words, the default value of 2 means points are hidden if
         * overlapping horizontally.
         *
         * @sample highcharts/plotoptions/series-marker-enabledthreshold
         *         A higher threshold
         *
         * @since 6.0.5
         */
        enabledThreshold: 2,
        /**
         * The radius of the point marker.
         *
         * @sample {highcharts} highcharts/plotoptions/series-marker-radius/
         *         Bigger markers
         *
         * @default  {highstock} 2
         */
        radius: 4,
        /**
         * Image markers only. Set the image width explicitly. When using
         * this option, a `height` must also be set.
         *
         * @sample {highcharts} highcharts/plotoptions/series-marker-width-height/
         *         Fixed width and height
         * @sample {highstock} highcharts/plotoptions/series-marker-width-height/
         *         Fixed width and height
         *
         * @type      {number}
         * @since     4.0.4
         * @apioption plotOptions.series.marker.width
         */
        /**
         * States for a single point marker.
         */
        states: {
            /**
             * The normal state of a single point marker. Currently only
             * used for setting animation when returning to normal state
             * from hover.
             */
            normal: {
                /**
                 * Animation when returning to normal state after hovering.
                 *
                 * @type {boolean|Highcharts.AnimationOptionsObject}
                 */
                animation: true
            },
            /**
             * The hover state for a single point marker.
             */
            hover: {
                /**
                 * Animation when hovering over the marker.
                 *
                 * @type {boolean|Highcharts.AnimationOptionsObject}
                 * @default {"duration": 50}
                 */
                animation: {
                    /** @ignore */
                    duration: 50
                },
                /**
                 * Enable or disable the point marker.
                 *
                 * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-enabled/
                 *         Disabled hover state
                 */
                enabled: true,
                /**
                 * The fill color of the marker in hover state. When
                 * `undefined`, the series' or point's fillColor for normal
                 * state is used.
                 *
                 * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
                 * @apioption plotOptions.series.marker.states.hover.fillColor
                 */
                /**
                 * The color of the point marker's outline. When
                 * `undefined`, the series' or point's lineColor for normal
                 * state is used.
                 *
                 * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-linecolor/
                 *         White fill color, black line color
                 *
                 * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
                 * @apioption plotOptions.series.marker.states.hover.lineColor
                 */
                /**
                 * The width of the point marker's outline. When
                 * `undefined`, the series' or point's lineWidth for normal
                 * state is used.
                 *
                 * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-linewidth/
                 *         3px line width
                 *
                 * @type      {number}
                 * @apioption plotOptions.series.marker.states.hover.lineWidth
                 */
                /**
                 * The radius of the point marker. In hover state, it
                 * defaults to the normal state's radius + 2 as per the
                 * [radiusPlus](#plotOptions.series.marker.states.hover.radiusPlus)
                 * option.
                 *
                 * @sample {highcharts} highcharts/plotoptions/series-marker-states-hover-radius/
                 *         10px radius
                 *
                 * @type      {number}
                 * @apioption plotOptions.series.marker.states.hover.radius
                 */
                /**
                 * The number of pixels to increase the radius of the
                 * hovered point.
                 *
                 * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/
                 *         5 pixels greater radius on hover
                 * @sample {highstock} highcharts/plotoptions/series-states-hover-linewidthplus/
                 *         5 pixels greater radius on hover
                 *
                 * @since 4.0.3
                 */
                radiusPlus: 2,
                /**
                 * The additional line width for a hovered point.
                 *
                 * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/
                 *         2 pixels wider on hover
                 * @sample {highstock} highcharts/plotoptions/series-states-hover-linewidthplus/
                 *         2 pixels wider on hover
                 *
                 * @since 4.0.3
                 */
                lineWidthPlus: 1
            },
            /**
             * The appearance of the point marker when selected. In order to
             * allow a point to be selected, set the
             * `series.allowPointSelect` option to true.
             */
            select: {
                /**
                 * The radius of the point marker. In hover state, it
                 * defaults to the normal state's radius + 2.
                 *
                 * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-radius/
                 *         10px radius for selected points
                 *
                 * @type      {number}
                 * @apioption plotOptions.series.marker.states.select.radius
                 */
                /**
                 * Enable or disable visible feedback for selection.
                 *
                 * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-enabled/
                 *         Disabled select state
                 *
                 * @type      {boolean}
                 * @default   true
                 * @apioption plotOptions.series.marker.states.select.enabled
                 */
                /**
                 * The fill color of the point marker.
                 *
                 * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-fillcolor/
                 *         Solid red discs for selected points
                 *
                 * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
                 */
                fillColor: '#cccccc',
                /**
                 * The color of the point marker's outline. When
                 * `undefined`, the series' or point's color is used.
                 *
                 * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-linecolor/
                 *         Red line color for selected points
                 *
                 * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
                 */
                lineColor: '#000000',
                /**
                 * The width of the point marker's outline.
                 *
                 * @sample {highcharts} highcharts/plotoptions/series-marker-states-select-linewidth/
                 *         3px line width for selected points
                 */
                lineWidth: 2
            }
        }
    },
    /**
     * Properties for each single point.
     *
     * @private
     */
    point: {
        /**
         * Fires when a point is clicked. One parameter, `event`, is passed
         * to the function, containing common event information.
         *
         * If the `series.allowPointSelect` option is true, the default
         * action for the point's click event is to toggle the point's
         * select state. Returning `false` cancels this action.
         *
         * @sample {highcharts} highcharts/plotoptions/series-point-events-click/
         *         Click marker to alert values
         * @sample {highcharts} highcharts/plotoptions/series-point-events-click-column/
         *         Click column
         * @sample {highcharts} highcharts/plotoptions/series-point-events-click-url/
         *         Go to URL
         * @sample {highmaps} maps/plotoptions/series-point-events-click/
         *         Click marker to display values
         * @sample {highmaps} maps/plotoptions/series-point-events-click-url/
         *         Go to URL
         *
         * @type      {Highcharts.PointClickCallbackFunction}
         * @context   Highcharts.Point
         * @apioption plotOptions.series.point.events.click
         */
        /**
         * Fires when the mouse leaves the area close to the point. One
         * parameter, `event`, is passed to the function, containing common
         * event information.
         *
         * @sample {highcharts} highcharts/plotoptions/series-point-events-mouseover/
         *         Show values in the chart's corner on mouse over
         *
         * @type      {Highcharts.PointMouseOutCallbackFunction}
         * @context   Highcharts.Point
         * @apioption plotOptions.series.point.events.mouseOut
         */
        /**
         * Fires when the mouse enters the area close to the point. One
         * parameter, `event`, is passed to the function, containing common
         * event information.
         *
         * @sample {highcharts} highcharts/plotoptions/series-point-events-mouseover/
         *         Show values in the chart's corner on mouse over
         *
         * @type      {Highcharts.PointMouseOverCallbackFunction}
         * @context   Highcharts.Point
         * @apioption plotOptions.series.point.events.mouseOver
         */
        /**
         * Fires when the point is removed using the `.remove()` method. One
         * parameter, `event`, is passed to the function. Returning `false`
         * cancels the operation.
         *
         * @sample {highcharts} highcharts/plotoptions/series-point-events-remove/
         *         Remove point and confirm
         *
         * @type      {Highcharts.PointRemoveCallbackFunction}
         * @since     1.2.0
         * @context   Highcharts.Point
         * @apioption plotOptions.series.point.events.remove
         */
        /**
         * Fires when the point is selected either programmatically or
         * following a click on the point. One parameter, `event`, is passed
         * to the function. Returning `false` cancels the operation.
         *
         * @sample {highcharts} highcharts/plotoptions/series-point-events-select/
         *         Report the last selected point
         * @sample {highmaps} maps/plotoptions/series-allowpointselect/
         *         Report select and unselect
         *
         * @type      {Highcharts.PointSelectCallbackFunction}
         * @since     1.2.0
         * @context   Highcharts.Point
         * @apioption plotOptions.series.point.events.select
         */
        /**
         * Fires when the point is unselected either programmatically or
         * following a click on the point. One parameter, `event`, is passed
         * to the function.
         *  Returning `false` cancels the operation.
         *
         * @sample {highcharts} highcharts/plotoptions/series-point-events-unselect/
         *         Report the last unselected point
         * @sample {highmaps} maps/plotoptions/series-allowpointselect/
         *         Report select and unselect
         *
         * @type      {Highcharts.PointUnselectCallbackFunction}
         * @since     1.2.0
         * @context   Highcharts.Point
         * @apioption plotOptions.series.point.events.unselect
         */
        /**
         * Fires when the point is updated programmatically through the
         * `.update()` method. One parameter, `event`, is passed to the
         * function. The new point options can be accessed through
         * `event.options`. Returning `false` cancels the operation.
         *
         * @sample {highcharts} highcharts/plotoptions/series-point-events-update/
         *         Confirm point updating
         *
         * @type      {Highcharts.PointUpdateCallbackFunction}
         * @since     1.2.0
         * @context   Highcharts.Point
         * @apioption plotOptions.series.point.events.update
         */
        /**
         * Events for each single point.
         */
        events: {}
    },
    /**
     * Options for the series data labels, appearing next to each data
     * point.
     *
     * Since v6.2.0, multiple data labels can be applied to each single
     * point by defining them as an array of configs.
     *
     * In styled mode, the data labels can be styled with the
     * `.highcharts-data-label-box` and `.highcharts-data-label` class names
     * ([see example](https://www.highcharts.com/samples/highcharts/css/series-datalabels)).
     *
     * @sample highcharts/plotoptions/series-datalabels-enabled
     *         Data labels enabled
     * @sample highcharts/plotoptions/series-datalabels-multiple
     *         Multiple data labels on a bar series
     *
     * @type    {Highcharts.DataLabelsOptionsObject|Array<Highcharts.DataLabelsOptionsObject>}
     *
     * @private
     */
    dataLabels: {
        /** @internal */
        align: 'center',
        // eslint-disable-next-line valid-jsdoc
        /**
         * @internal
         * @default function () { return H.numberFormat(this.y, -1); }
         */
        formatter: function () {
            return this.y === null ? '' : H.numberFormat(this.y, -1);
        },
        /** @internal */
        padding: 5,
        /**
         * @internal
         * @type {Highcharts.CSSObject}
         */
        style: {
            /** @internal */
            fontSize: '11px',
            /** @internal */
            fontWeight: 'bold',
            /** @internal */
            color: 'contrast',
            /** @internal */
            textOutline: '1px contrast'
        },
        /**
         * above singular point
         * @internal
         */
        verticalAlign: 'bottom',
        /** @internal */
        x: 0,
        /** @internal */
        y: 0
    },
    /**
     * When the series contains less points than the crop threshold, all
     * points are drawn, even if the points fall outside the visible plot
     * area at the current zoom. The advantage of drawing all points
     * (including markers and columns), is that animation is performed on
     * updates. On the other hand, when the series contains more points than
     * the crop threshold, the series data is cropped to only contain points
     * that fall within the plot area. The advantage of cropping away
     * invisible points is to increase performance on large series.
     *
     * @since   2.2
     * @product highcharts highstock
     *
     * @private
     */
    cropThreshold: 300,
    /**
     * Opacity of a series parts: line, fill (e.g. area) and dataLabels.
     *
     * @see [states.inactive.opacity](#plotOptions.series.states.inactive.opacity)
     *
     * @since 7.1.0
     *
     * @private
     */
    opacity: 1,
    /**
     * The width of each point on the x axis. For example in a column chart
     * with one value each day, the pointRange would be 1 day (= 24 * 3600
     * * 1000 milliseconds). This is normally computed automatically, but
     * this option can be used to override the automatic value.
     *
     * @product highstock
     *
     * @private
     */
    pointRange: 0,
    /**
     * When this is true, the series will not cause the Y axis to cross
     * the zero plane (or [threshold](#plotOptions.series.threshold) option)
     * unless the data actually crosses the plane.
     *
     * For example, if `softThreshold` is `false`, a series of 0, 1, 2,
     * 3 will make the Y axis show negative values according to the
     * `minPadding` option. If `softThreshold` is `true`, the Y axis starts
     * at 0.
     *
     * @since   4.1.9
     * @product highcharts highstock
     *
     * @private
     */
    softThreshold: true,
    states: {
        /**
         * The normal state of a series, or for point items in column, pie
         * and similar series. Currently only used for setting animation
         * when returning to normal state from hover.
         */
        normal: {
            /**
             * Animation when returning to normal state after hovering.
             *
             * @type {boolean|Highcharts.AnimationOptionsObject}
             */
            animation: true
        },
        /**
         * Options for the hovered series. These settings override the
         * normal state options when a series is moused over or touched.
         */
        hover: {
            /**
             * Enable separate styles for the hovered series to visualize
             * that the user hovers either the series itself or the legend.
             *
             * @sample {highcharts} highcharts/plotoptions/series-states-hover-enabled/
             *         Line
             * @sample {highcharts} highcharts/plotoptions/series-states-hover-enabled-column/
             *         Column
             * @sample {highcharts} highcharts/plotoptions/series-states-hover-enabled-pie/
             *         Pie
             *
             * @type      {boolean}
             * @default   true
             * @since     1.2
             * @apioption plotOptions.series.states.hover.enabled
             */
            /**
             * Animation setting for hovering the graph in line-type series.
             *
             * @type    {boolean|Highcharts.AnimationOptionsObject}
             * @since   5.0.8
             * @product highcharts highstock
             */
            animation: {
                /**
                 * The duration of the hover animation in milliseconds. By
                 * default the hover state animates quickly in, and slowly
                 * back to normal.
                 */
                duration: 50
            },
            /**
             * Pixel width of the graph line. By default this property is
             * undefined, and the `lineWidthPlus` property dictates how much
             * to increase the linewidth from normal state.
             *
             * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidth/
             *         5px line on hover
             *
             * @type      {number}
             * @product   highcharts highstock
             * @apioption plotOptions.series.states.hover.lineWidth
             */
            /**
             * The additional line width for the graph of a hovered series.
             *
             * @sample {highcharts} highcharts/plotoptions/series-states-hover-linewidthplus/
             *         5 pixels wider
             * @sample {highstock} highcharts/plotoptions/series-states-hover-linewidthplus/
             *         5 pixels wider
             *
             * @since   4.0.3
             * @product highcharts highstock
             */
            lineWidthPlus: 1,
            /**
             * In Highcharts 1.0, the appearance of all markers belonging
             * to the hovered series. For settings on the hover state of the
             * individual point, see
             * [marker.states.hover](#plotOptions.series.marker.states.hover).
             *
             * @deprecated
             *
             * @extends   plotOptions.series.marker
             * @excluding states
             * @product   highcharts highstock
             */
            marker: {
            // lineWidth: base + 1,
            // radius: base + 1
            },
            /**
             * Options for the halo appearing around the hovered point in
             * line-type series as well as outside the hovered slice in pie
             * charts. By default the halo is filled by the current point or
             * series color with an opacity of 0.25\. The halo can be
             * disabled by setting the `halo` option to `null`.
             *
             * In styled mode, the halo is styled with the
             * `.highcharts-halo` class, with colors inherited from
             * `.highcharts-color-{n}`.
             *
             * @sample {highcharts} highcharts/plotoptions/halo/
             *         Halo options
             * @sample {highstock} highcharts/plotoptions/halo/
             *         Halo options
             *
             * @type    {null|*}
             * @since   4.0
             * @product highcharts highstock
             */
            halo: {
                /**
                 * A collection of SVG attributes to override the appearance
                 * of the halo, for example `fill`, `stroke` and
                 * `stroke-width`.
                 *
                 * @type      {Highcharts.SVGAttributes}
                 * @since     4.0
                 * @product   highcharts highstock
                 * @apioption plotOptions.series.states.hover.halo.attributes
                 */
                /**
                 * The pixel size of the halo. For point markers this is the
                 * radius of the halo. For pie slices it is the width of the
                 * halo outside the slice. For bubbles it defaults to 5 and
                 * is the width of the halo outside the bubble.
                 *
                 * @since   4.0
                 * @product highcharts highstock
                 */
                size: 10,
                /**
                 * Opacity for the halo unless a specific fill is overridden
                 * using the `attributes` setting. Note that Highcharts is
                 * only able to apply opacity to colors of hex or rgb(a)
                 * formats.
                 *
                 * @since   4.0
                 * @product highcharts highstock
                 */
                opacity: 0.25
            }
        },
        /**
         * Specific options for point in selected states, after being
         * selected by
         * [allowPointSelect](#plotOptions.series.allowPointSelect)
         * or programmatically.
         *
         * @sample maps/plotoptions/series-allowpointselect/
         *         Allow point select demo
         *
         * @extends   plotOptions.series.states.hover
         * @excluding brightness
         */
        select: {
            animation: {
                duration: 0
            }
        },
        /**
         * The opposite state of a hover for series.
         *
         * @sample highcharts/plotoptions/series-states-inactive-opacity
         *         Disabled inactive state by setting opacity
         */
        inactive: {
            /**
             * The animation for entering the inactive state.
             *
             * @type    {boolean|Highcharts.AnimationOptionsObject}
             */
            animation: {
                duration: 50
            },
            /**
             * Opacity of series elements (dataLabels, line, area). Set to 1
             * to disable inactive state.
             *
             * @apioption plotOptions.series.states.inactive.opacity
             * @type {number}
             * @sample highcharts/plotoptions/series-states-inactive-opacity
             *         Disabled inactive state
             */
            opacity: 0.2
        }
    },
    /**
     * Sticky tracking of mouse events. When true, the `mouseOut` event on a
     * series isn't triggered until the mouse moves over another series, or
     * out of the plot area. When false, the `mouseOut` event on a series is
     * triggered when the mouse leaves the area around the series' graph or
     * markers. This also implies the tooltip when not shared. When
     * `stickyTracking` is false and `tooltip.shared` is false, the tooltip
     * will be hidden when moving the mouse between series. Defaults to true
     * for line and area type series, but to false for columns, pies etc.
     *
     * @sample {highcharts} highcharts/plotoptions/series-stickytracking-true/
     *         True by default
     * @sample {highcharts} highcharts/plotoptions/series-stickytracking-false/
     *         False
     *
     * @default {highcharts} true
     * @default {highstock} true
     * @default {highmaps} false
     * @since   2.0
     *
     * @private
     */
    stickyTracking: true,
    /**
     * A configuration object for the tooltip rendering of each single
     * series. Properties are inherited from [tooltip](#tooltip), but only
     * the following properties can be defined on a series level.
     *
     * @since     2.3
     * @extends   tooltip
     * @excluding animation, backgroundColor, borderColor, borderRadius,
     *            borderWidth, crosshairs, enabled, formatter, positioner,
     *            shadow, shape, shared, snap, style, useHTML
     * @apioption plotOptions.series.tooltip
     */
    /**
     * When a series contains a data array that is longer than this, only
     * one dimensional arrays of numbers, or two dimensional arrays with
     * x and y values are allowed. Also, only the first point is tested,
     * and the rest are assumed to be the same format. This saves expensive
     * data checking and indexing in long series. Set it to `0` disable.
     *
     * @since   2.2
     * @product highcharts highstock gantt
     *
     * @private
     */
    turboThreshold: 1000,
    /**
     * An array defining zones within a series. Zones can be applied to the
     * X axis, Y axis or Z axis for bubbles, according to the `zoneAxis`
     * option. The zone definitions have to be in ascending order regarding
     * to the value.
     *
     * In styled mode, the color zones are styled with the
     * `.highcharts-zone-{n}` class, or custom classed from the `className`
     * option
     * ([view live demo](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/css/color-zones/)).
     *
     * @see [zoneAxis](#plotOptions.series.zoneAxis)
     *
     * @sample {highcharts} highcharts/series/color-zones-simple/
     *         Color zones
     * @sample {highstock} highcharts/series/color-zones-simple/
     *         Color zones
     *
     * @type      {Array<*>}
     * @since     4.1.0
     * @product   highcharts highstock
     * @apioption plotOptions.series.zones
     */
    /**
     * Styled mode only. A custom class name for the zone.
     *
     * @sample highcharts/css/color-zones/
     *         Zones styled by class name
     *
     * @type      {string}
     * @since     5.0.0
     * @apioption plotOptions.series.zones.className
     */
    /**
     * Defines the color of the series.
     *
     * @see [series color](#plotOptions.series.color)
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @since     4.1.0
     * @product   highcharts highstock
     * @apioption plotOptions.series.zones.color
     */
    /**
     * A name for the dash style to use for the graph.
     *
     * @see [series.dashStyle](#plotOptions.series.dashStyle)
     *
     * @sample {highcharts|highstock} highcharts/series/color-zones-dashstyle-dot/
     *         Dashed line indicates prognosis
     *
     * @type      {Highcharts.DashStyleValue}
     * @since     4.1.0
     * @product   highcharts highstock
     * @apioption plotOptions.series.zones.dashStyle
     */
    /**
     * Defines the fill color for the series (in area type series)
     *
     * @see [fillColor](#plotOptions.area.fillColor)
     *
     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
     * @since     4.1.0
     * @product   highcharts highstock
     * @apioption plotOptions.series.zones.fillColor
     */
    /**
     * The value up to where the zone extends, if undefined the zones
     * stretches to the last value in the series.
     *
     * @type      {number}
     * @since     4.1.0
     * @product   highcharts highstock
     * @apioption plotOptions.series.zones.value
     */
    /**
     * Determines whether the series should look for the nearest point
     * in both dimensions or just the x-dimension when hovering the series.
     * Defaults to `'xy'` for scatter series and `'x'` for most other
     * series. If the data has duplicate x-values, it is recommended to
     * set this to `'xy'` to allow hovering over all points.
     *
     * Applies only to series types using nearest neighbor search (not
     * direct hover) for tooltip.
     *
     * @sample {highcharts} highcharts/series/findnearestpointby/
     *         Different hover behaviors
     * @sample {highstock} highcharts/series/findnearestpointby/
     *         Different hover behaviors
     * @sample {highmaps} highcharts/series/findnearestpointby/
     *         Different hover behaviors
     *
     * @since      5.0.10
     * @validvalue ["x", "xy"]
     *
     * @private
     */
    findNearestPointBy: 'x'
}, 
/* eslint-disable no-invalid-this, valid-jsdoc */
/** @lends Highcharts.Series.prototype */
{
    axisTypes: ['xAxis', 'yAxis'],
    coll: 'series',
    colorCounter: 0,
    cropShoulder: 1,
    directTouch: false,
    isCartesian: true,
    // each point's x and y values are stored in this.xData and this.yData
    parallelArrays: ['x', 'y'],
    pointClass: Point,
    requireSorting: true,
    sorted: true,
    init: function (chart, options) {
        fireEvent(this, 'init', { options: options });
        var series = this, events, chartSeries = chart.series, lastSeries;
        // A lookup over those events that are added by _options_ (not
        // programmatically). These are updated through Series.update()
        // (#10861).
        this.eventOptions = this.eventOptions || {};
        /**
         * Read only. The chart that the series belongs to.
         *
         * @name Highcharts.Series#chart
         * @type {Highcharts.Chart}
         */
        series.chart = chart;
        /**
         * Read only. The series' type, like "line", "area", "column" etc.
         * The type in the series options anc can be altered using
         * {@link Series#update}.
         *
         * @name Highcharts.Series#type
         * @type {string}
         */
        /**
         * Read only. The series' current options. To update, use
         * {@link Series#update}.
         *
         * @name Highcharts.Series#options
         * @type {Highcharts.SeriesOptionsType}
         */
        series.options = options = series.setOptions(options);
        series.linkedSeries = [];
        // bind the axes
        series.bindAxes();
        // set some variables
        extend(series, {
            /**
             * The series name as given in the options. Defaults to
             * "Series {n}".
             *
             * @name Highcharts.Series#name
             * @type {string}
             */
            name: options.name,
            state: '',
            /**
             * Read only. The series' visibility state as set by {@link
             * Series#show}, {@link Series#hide}, or in the initial
             * configuration.
             *
             * @name Highcharts.Series#visible
             * @type {boolean}
             */
            visible: options.visible !== false,
            /**
             * Read only. The series' selected state as set by {@link
             * Highcharts.Series#select}.
             *
             * @name Highcharts.Series#selected
             * @type {boolean}
             */
            selected: options.selected === true // false by default
        });
        // Register event listeners
        events = options.events;
        objectEach(events, function (event, eventType) {
            if (H.isFunction(event)) {
                // If event does not exist, or is changed by Series.update
                if (series.eventOptions[eventType] !== event) {
                    // Remove existing if set by option
                    if (H.isFunction(series.eventOptions[eventType])) {
                        removeEvent(series, eventType, series.eventOptions[eventType]);
                    }
                    series.eventOptions[eventType] = event;
                    addEvent(series, eventType, event);
                }
            }
        });
        if ((events && events.click) ||
            (options.point &&
                options.point.events &&
                options.point.events.click) ||
            options.allowPointSelect) {
            chart.runTrackerClick = true;
        }
        series.getColor();
        series.getSymbol();
        // Initialize the parallel data arrays
        series.parallelArrays.forEach(function (key) {
            if (!series[key + 'Data']) {
                series[key + 'Data'] = [];
            }
        });
        if (!series.points && !series.data) {
            series.setData(options.data, false);
        }
        // Mark cartesian
        if (series.isCartesian) {
            chart.hasCartesianSeries = true;
        }
        // Get the index and register the series in the chart. The index is
        // one more than the current latest series index (#5960).
        if (chartSeries.length) {
            lastSeries = chartSeries[chartSeries.length - 1];
        }
        series._i = pick(lastSeries && lastSeries._i, -1) + 1;
        // Insert the series and re-order all series above the insertion
        // point.
        chart.orderSeries(this.insert(chartSeries));
        fireEvent(this, 'afterInit');
    },
    /**
     * Insert the series in a collection with other series, either the chart
     * series or yAxis series, in the correct order according to the index
     * option. Used internally when adding series.
     *
     * @private
     * @function Highcharts.Series#insert
     * @param {Array<Highcharts.Series>} collection
     *        A collection of series, like `chart.series` or `xAxis.series`.
     * @return {number}
     *         The index of the series in the collection.
     */
    insert: function (collection) {
        var indexOption = this.options.index, i;
        // Insert by index option
        if (isNumber(indexOption)) {
            i = collection.length;
            while (i--) {
                // Loop down until the interted element has higher index
                if (indexOption >=
                    pick(collection[i].options.index, collection[i]._i)) {
                    collection.splice(i + 1, 0, this);
                    break;
                }
            }
            if (i === -1) {
                collection.unshift(this);
            }
            i = i + 1;
            // Or just push it to the end
        }
        else {
            collection.push(this);
        }
        return pick(i, collection.length - 1);
    },
    /**
     * Set the xAxis and yAxis properties of cartesian series, and register
     * the series in the `axis.series` array.
     *
     * @private
     * @function Highcharts.Series#bindAxes
     * @return {void}
     * @exception 18
     */
    bindAxes: function () {
        var series = this, seriesOptions = series.options, chart = series.chart, axisOptions;
        fireEvent(this, 'bindAxes', null, function () {
            // repeat for xAxis and yAxis
            (series.axisTypes || []).forEach(function (AXIS) {
                // loop through the chart's axis objects
                chart[AXIS].forEach(function (axis) {
                    axisOptions = axis.options;
                    // apply if the series xAxis or yAxis option mathches
                    // the number of the axis, or if undefined, use the
                    // first axis
                    if (seriesOptions[AXIS] ===
                        axisOptions.index ||
                        (seriesOptions[AXIS] !== undefined &&
                            seriesOptions[AXIS] === axisOptions.id) ||
                        (seriesOptions[AXIS] === undefined &&
                            axisOptions.index === 0)) {
                        // register this series in the axis.series lookup
                        series.insert(axis.series);
                        // set this series.xAxis or series.yAxis reference
                        /**
                         * Read only. The unique xAxis object associated
                         * with the series.
                         *
                         * @name Highcharts.Series#xAxis
                         * @type {Highcharts.Axis}
                         */
                        /**
                         * Read only. The unique yAxis object associated
                         * with the series.
                         *
                         * @name Highcharts.Series#yAxis
                         * @type {Highcharts.Axis}
                         */
                        series[AXIS] = axis;
                        // mark dirty for redraw
                        axis.isDirty = true;
                    }
                });
                // The series needs an X and an Y axis
                if (!series[AXIS] &&
                    series.optionalAxis !== AXIS) {
                    H.error(18, true, chart);
                }
            });
        });
    },
    /**
     * For simple series types like line and column, the data values are
     * held in arrays like xData and yData for quick lookup to find extremes
     * and more. For multidimensional series like bubble and map, this can
     * be extended with arrays like zData and valueData by adding to the
     * `series.parallelArrays` array.
     *
     * @private
     * @function Highcharts.Series#updateParallelArrays
     * @param {Highcharts.Point} point
     * @param {number|string} i
     * @return {void}
     */
    updateParallelArrays: function (point, i) {
        var series = point.series, args = arguments, fn = isNumber(i) ?
            // Insert the value in the given position
            function (key) {
                var val = key === 'y' && series.toYData ?
                    series.toYData(point) :
                    point[key];
                series[key + 'Data'][i] = val;
            } :
            // Apply the method specified in i with the following
            // arguments as arguments
            function (key) {
                Array.prototype[i].apply(series[key + 'Data'], Array.prototype.slice.call(args, 2));
            };
        series.parallelArrays.forEach(fn);
    },
    /**
     * Define hasData functions for series. These return true if there
     * are data points on this series within the plot area.
     *
     * @private
     * @function Highcharts.Series#hasData
     * @return {boolean}
     */
    hasData: function () {
        return ((this.visible &&
            this.dataMax !== undefined &&
            this.dataMin !== undefined) || ( // #3703
        this.visible &&
            this.yData &&
            this.yData.length > 0) // #9758
        );
    },
    /**
     * Return an auto incremented x value based on the pointStart and
     * pointInterval options. This is only used if an x value is not given
     * for the point that calls autoIncrement.
     *
     * @private
     * @function Highcharts.Series#autoIncrement
     * @return {number}
     */
    autoIncrement: function () {
        var options = this.options, xIncrement = this.xIncrement, date, pointInterval, pointIntervalUnit = options.pointIntervalUnit, time = this.chart.time;
        xIncrement = pick(xIncrement, options.pointStart, 0);
        this.pointInterval = pointInterval = pick(this.pointInterval, options.pointInterval, 1);
        // Added code for pointInterval strings
        if (pointIntervalUnit) {
            date = new time.Date(xIncrement);
            if (pointIntervalUnit === 'day') {
                time.set('Date', date, time.get('Date', date) + pointInterval);
            }
            else if (pointIntervalUnit === 'month') {
                time.set('Month', date, time.get('Month', date) + pointInterval);
            }
            else if (pointIntervalUnit === 'year') {
                time.set('FullYear', date, time.get('FullYear', date) + pointInterval);
            }
            pointInterval = date.getTime() - xIncrement;
        }
        this.xIncrement = xIncrement + pointInterval;
        return xIncrement;
    },
    /**
     * Set the series options by merging from the options tree. Called
     * internally on initializing and updating series. This function will
     * not redraw the series. For API usage, use {@link Series#update}.
     * @private
     * @function Highcharts.Series#setOptions
     * @param {Highcharts.SeriesOptionsType} itemOptions
     *        The series options.
     * @return {Highcharts.SeriesOptionsType}
     * @fires Highcharts.Series#event:afterSetOptions
     */
    setOptions: function (itemOptions) {
        var chart = this.chart, chartOptions = chart.options, plotOptions = chartOptions.plotOptions, userOptions = chart.userOptions || {}, seriesUserOptions = merge(itemOptions), options, zones, zone, styledMode = chart.styledMode, e = {
            plotOptions: plotOptions,
            userOptions: seriesUserOptions
        };
        fireEvent(this, 'setOptions', e);
        // These may be modified by the event
        var typeOptions = e.plotOptions[this.type], userPlotOptions = (userOptions.plotOptions || {});
        // use copy to prevent undetected changes (#9762)
        this.userOptions = e.userOptions;
        options = merge(typeOptions, plotOptions.series, 
        // #3881, chart instance plotOptions[type] should trump
        // plotOptions.series
        userOptions.plotOptions &&
            userOptions.plotOptions[this.type], seriesUserOptions);
        // The tooltip options are merged between global and series specific
        // options. Importance order asscendingly:
        // globals: (1)tooltip, (2)plotOptions.series,
        // (3)plotOptions[this.type]
        // init userOptions with possible later updates: 4-6 like 1-3 and
        // (7)this series options
        this.tooltipOptions = merge(defaultOptions.tooltip, // 1
        defaultOptions.plotOptions.series &&
            defaultOptions.plotOptions.series.tooltip, // 2
        defaultOptions.plotOptions[this.type].tooltip, // 3
        chartOptions.tooltip.userOptions, // 4
        plotOptions.series &&
            plotOptions.series.tooltip, // 5
        plotOptions[this.type].tooltip, // 6
        seriesUserOptions.tooltip // 7
        );
        // When shared tooltip, stickyTracking is true by default,
        // unless user says otherwise.
        this.stickyTracking = pick(seriesUserOptions.stickyTracking, userPlotOptions[this.type] &&
            userPlotOptions[this.type].stickyTracking, userPlotOptions.series && userPlotOptions.series.stickyTracking, (this.tooltipOptions.shared && !this.noSharedTooltip ?
            true :
            options.stickyTracking));
        // Delete marker object if not allowed (#1125)
        if (typeOptions.marker === null) {
            delete options.marker;
        }
        // Handle color zones
        this.zoneAxis = options.zoneAxis;
        zones = this.zones = (options.zones || []).slice();
        if ((options.negativeColor || options.negativeFillColor) &&
            !options.zones) {
            zone = {
                value: options[this.zoneAxis + 'Threshold'] ||
                    options.threshold ||
                    0,
                className: 'highcharts-negative'
            };
            if (!styledMode) {
                zone.color = options.negativeColor;
                zone.fillColor = options.negativeFillColor;
            }
            zones.push(zone);
        }
        if (zones.length) { // Push one extra zone for the rest
            if (defined(zones[zones.length - 1].value)) {
                zones.push(styledMode ? {} : {
                    color: this.color,
                    fillColor: this.fillColor
                });
            }
        }
        fireEvent(this, 'afterSetOptions', { options: options });
        return options;
    },
    /**
     * Return series name in "Series {Number}" format or the one defined by
     * a user. This method can be simply overridden as series name format
     * can vary (e.g. technical indicators).
     *
     * @function Highcharts.Series#getName
     * @return {string}
     *         The series name.
     */
    getName: function () {
        // #4119
        return pick(this.options.name, 'Series ' + (this.index + 1));
    },
    /**
     * @private
     * @function Highcharts.Series#getCyclic
     * @param {string} prop
     * @param {*} [value]
     * @param {Highcharts.Dictionary<any>} [defaults]
     * @return {void}
     */
    getCyclic: function (prop, value, defaults) {
        var i, chart = this.chart, userOptions = this.userOptions, indexName = prop + 'Index', counterName = prop + 'Counter', len = defaults ? defaults.length : pick(chart.options.chart[prop + 'Count'], chart[prop + 'Count']), setting;
        if (!value) {
            // Pick up either the colorIndex option, or the _colorIndex
            // after Series.update()
            setting = pick(userOptions[indexName], userOptions['_' + indexName]);
            if (defined(setting)) { // after Series.update()
                i = setting;
            }
            else {
                // #6138
                if (!chart.series.length) {
                    chart[counterName] = 0;
                }
                userOptions['_' + indexName] = i =
                    chart[counterName] % len;
                chart[counterName] += 1;
            }
            if (defaults) {
                value = defaults[i];
            }
        }
        // Set the colorIndex
        if (i !== undefined) {
            this[indexName] = i;
        }
        this[prop] = value;
    },
    /**
     * Get the series' color based on either the options or pulled from
     * global options.
     *
     * @private
     * @function Highcharts.Series#getColor
     * @return {void}
     */
    getColor: function () {
        if (this.chart.styledMode) {
            this.getCyclic('color');
        }
        else if (this.options.colorByPoint) {
            // #4359, selected slice got series.color even when colorByPoint
            // was set.
            this.options.color = null;
        }
        else {
            this.getCyclic('color', this.options.color ||
                defaultPlotOptions[this.type].color, this.chart.options.colors);
        }
    },
    /**
     * Get the series' symbol based on either the options or pulled from
     * global options.
     *
     * @private
     * @function Highcharts.Series#getSymbol
     * @return {void}
     */
    getSymbol: function () {
        var seriesMarkerOption = this.options.marker;
        this.getCyclic('symbol', seriesMarkerOption.symbol, this.chart.options.symbols);
    },
    /**
     * Finds the index of an existing point that matches the given point
     * options.
     *
     * @private
     * @function Highcharts.Series#findPointIndex
     * @param    {Highcharts.PointOptionsObject} optionsObject
     *           The options of the point.
     * @param    {number} fromIndex
     *           The index to start searching from, used for optimizing
     *           series with required sorting.
     * @returns  {number|undefined}
     *           Returns the index of a matching point, or undefined if no
     *           match is found.
     */
    findPointIndex: function (optionsObject, fromIndex) {
        var id = optionsObject.id, x = optionsObject.x, oldData = this.points, matchingPoint, matchedById, pointIndex;
        if (id) {
            matchingPoint = this.chart.get(id);
            pointIndex = matchingPoint && matchingPoint.index;
            if (pointIndex !== undefined) {
                matchedById = true;
            }
        }
        // Search for the same X in the existing data set
        if (pointIndex === undefined && isNumber(x)) {
            pointIndex = this.xData.indexOf(x, fromIndex);
        }
        // Reduce pointIndex if data is cropped
        if (pointIndex !== -1 &&
            pointIndex !== undefined &&
            this.cropped) {
            pointIndex = (pointIndex >= this.cropStart) ?
                pointIndex - this.cropStart : pointIndex;
        }
        if (!matchedById &&
            oldData[pointIndex] && oldData[pointIndex].touched) {
            pointIndex = undefined;
        }
        return pointIndex;
    },
    /**
     * @private
     * @borrows LegendSymbolMixin.drawLineMarker as Highcharts.Series#drawLegendSymbol
     */
    drawLegendSymbol: LegendSymbolMixin.drawLineMarker,
    /**
     * Internal function called from setData. If the point count is the same
     * as is was, or if there are overlapping X values, just run
     * Point.update which is cheaper, allows animation, and keeps references
     * to points. This also allows adding or removing points if the X-es
     * don't match.
     *
     * @private
     * @function Highcharts.Series#updateData
     *
     * @param {Array<Highcharts.PointOptionsType>} data
     *
     * @return {boolean}
     */
    updateData: function (data) {
        var options = this.options, oldData = this.points, pointsToAdd = [], hasUpdatedByKey, i, point, lastIndex, requireSorting = this.requireSorting, equalLength = data.length === oldData.length, succeeded = true;
        this.xIncrement = null;
        // Iterate the new data
        data.forEach(function (pointOptions, i) {
            var id, x, pointIndex, optionsObject = (defined(pointOptions) &&
                this.pointClass.prototype.optionsToObject.call({ series: this }, pointOptions)) || {};
            // Get the x of the new data point
            x = optionsObject.x;
            id = optionsObject.id;
            if (id || isNumber(x)) {
                pointIndex = this.findPointIndex(optionsObject, lastIndex);
                // Matching X not found
                // or used already due to ununique x values (#8995),
                // add point (but later)
                if (pointIndex === -1 ||
                    pointIndex === undefined) {
                    pointsToAdd.push(pointOptions);
                    // Matching X found, update
                }
                else if (oldData[pointIndex] &&
                    pointOptions !== options.data[pointIndex]) {
                    oldData[pointIndex].update(pointOptions, false, null, false);
                    // Mark it touched, below we will remove all points that
                    // are not touched.
                    oldData[pointIndex].touched = true;
                    // Speed optimize by only searching after last known
                    // index. Performs ~20% bettor on large data sets.
                    if (requireSorting) {
                        lastIndex = pointIndex + 1;
                    }
                    // Point exists, no changes, don't remove it
                }
                else if (oldData[pointIndex]) {
                    oldData[pointIndex].touched = true;
                }
                // If the length is equal and some of the nodes had a
                // match in the same position, we don't want to remove
                // non-matches.
                if (!equalLength ||
                    i !== pointIndex ||
                    this.hasDerivedData) {
                    hasUpdatedByKey = true;
                }
            }
        }, this);
        // Remove points that don't exist in the updated data set
        if (hasUpdatedByKey) {
            i = oldData.length;
            while (i--) {
                point = oldData[i];
                if (point && !point.touched) {
                    point.remove(false);
                }
            }
            // If we did not find keys (ids or x-values), and the length is the
            // same, update one-to-one
        }
        else if (equalLength) {
            data.forEach(function (point, i) {
                // .update doesn't exist on a linked, hidden series (#3709)
                // (#10187)
                if (oldData[i].update && point !== oldData[i].y) {
                    oldData[i].update(point, false, null, false);
                }
            });
            // Did not succeed in updating data
        }
        else {
            succeeded = false;
        }
        oldData.forEach(function (point) {
            if (point) {
                point.touched = false;
            }
        });
        if (!succeeded) {
            return false;
        }
        // Add new points
        pointsToAdd.forEach(function (point) {
            this.addPoint(point, false, null, null, false);
        }, this);
        return true;
    },
    /**
     * Apply a new set of data to the series and optionally redraw it. The
     * new data array is passed by reference (except in case of
     * `updatePoints`), and may later be mutated when updating the chart
     * data.
     *
     * Note the difference in behaviour when setting the same amount of
     * points, or a different amount of points, as handled by the
     * `updatePoints` parameter.
     *
     * @sample highcharts/members/series-setdata/
     *         Set new data from a button
     * @sample highcharts/members/series-setdata-pie/
     *         Set data in a pie
     * @sample stock/members/series-setdata/
     *         Set new data in Highstock
     * @sample maps/members/series-setdata/
     *         Set new data in Highmaps
     *
     * @function Highcharts.Series#setData
     *
     * @param {Array<Highcharts.PointOptionsType>} data
     *        Takes an array of data in the same format as described under
     *        `series.{type}.data` for the given series type, for example a
     *        line series would take data in the form described under
     *        [series.line.data](https://api.highcharts.com/highcharts/series.line.data).
     *
     * @param {boolean} [redraw=true]
     *        Whether to redraw the chart after the series is altered. If
     *        doing more operations on the chart, it is a good idea to set
     *        redraw to false and call {@link Chart#redraw} after.
     *
     * @param {boolean|Highcharts.AnimationOptionsObject} [animation]
     *        When the updated data is the same length as the existing data,
     *        points will be updated by default, and animation visualizes
     *        how the points are changed. Set false to disable animation, or
     *        a configuration object to set duration or easing.
     *
     * @param {boolean} [updatePoints=true]
     *        When this is true, points will be updated instead of replaced
     *        whenever possible. This occurs a) when the updated data is the
     *        same length as the existing data, b) when points are matched
     *        by their id's, or c) when points can be matched by X values.
     *        This allows updating with animation and performs better. In
     *        this case, the original array is not passed by reference. Set
     *        `false` to prevent.
     *
     * @return {void}
     */
    setData: function (data, redraw, animation, updatePoints) {
        var series = this, oldData = series.points, oldDataLength = (oldData && oldData.length) || 0, dataLength, options = series.options, chart = series.chart, firstPoint = null, xAxis = series.xAxis, i, turboThreshold = options.turboThreshold, pt, xData = this.xData, yData = this.yData, pointArrayMap = series.pointArrayMap, valueCount = pointArrayMap && pointArrayMap.length, keys = options.keys, indexOfX = 0, indexOfY = 1, updatedData;
        data = data || [];
        dataLength = data.length;
        redraw = pick(redraw, true);
        // First try to run Point.update which is cheaper, allows animation,
        // and keeps references to points.
        if (updatePoints !== false &&
            dataLength &&
            oldDataLength &&
            !series.cropped &&
            !series.hasGroupedData &&
            series.visible &&
            // Soft updating has no benefit in boost, and causes JS error
            // (#8355)
            !series.isSeriesBoosting) {
            updatedData = this.updateData(data);
        }
        if (!updatedData) {
            // Reset properties
            series.xIncrement = null;
            series.colorCounter = 0; // for series with colorByPoint (#1547)
            // Update parallel arrays
            this.parallelArrays.forEach(function (key) {
                series[key + 'Data'].length = 0;
            });
            // In turbo mode, only one- or twodimensional arrays of numbers
            // are allowed. The first value is tested, and we assume that
            // all the rest are defined the same way. Although the 'for'
            // loops are similar, they are repeated inside each if-else
            // conditional for max performance.
            if (turboThreshold && dataLength > turboThreshold) {
                // find the first non-null point
                i = 0;
                while (firstPoint === null && i < dataLength) {
                    firstPoint = data[i];
                    i++;
                }
                if (isNumber(firstPoint)) { // assume all points are numbers
                    for (i = 0; i < dataLength; i++) {
                        xData[i] = this.autoIncrement();
                        yData[i] = data[i];
                    }
                    // Assume all points are arrays when first point is
                }
                else if (isArray(firstPoint)) {
                    if (valueCount) { // [x, low, high] or [x, o, h, l, c]
                        for (i = 0; i < dataLength; i++) {
                            pt = data[i];
                            xData[i] = pt[0];
                            yData[i] =
                                pt.slice(1, valueCount + 1);
                        }
                    }
                    else { // [x, y]
                        if (keys) {
                            indexOfX = keys.indexOf('x');
                            indexOfY = keys.indexOf('y');
                            indexOfX = indexOfX >= 0 ? indexOfX : 0;
                            indexOfY = indexOfY >= 0 ? indexOfY : 1;
                        }
                        for (i = 0; i < dataLength; i++) {
                            pt = data[i];
                            xData[i] = pt[indexOfX];
                            yData[i] = pt[indexOfY];
                        }
                    }
                }
                else {
                    // Highcharts expects configs to be numbers or arrays in
                    // turbo mode
                    H.error(12, false, chart);
                }
            }
            else {
                for (i = 0; i < dataLength; i++) {
                    if (data[i] !== undefined) { // stray commas in oldIE
                        pt = { series: series };
                        series.pointClass.prototype.applyOptions.apply(pt, [data[i]]);
                        series.updateParallelArrays(pt, i);
                    }
                }
            }
            // Forgetting to cast strings to numbers is a common caveat when
            // handling CSV or JSON
            if (yData && isString(yData[0])) {
                H.error(14, true, chart);
            }
            series.data = [];
            series.options.data = series.userOptions.data = data;
            // destroy old points
            i = oldDataLength;
            while (i--) {
                if (oldData[i] && oldData[i].destroy) {
                    oldData[i].destroy();
                }
            }
            // reset minRange (#878)
            if (xAxis) {
                xAxis.minRange = xAxis.userMinRange;
            }
            // redraw
            series.isDirty = chart.isDirtyBox = true;
            series.isDirtyData = !!oldData;
            animation = false;
        }
        // Typically for pie series, points need to be processed and
        // generated prior to rendering the legend
        if (options.legendType === 'point') {
            this.processData();
            this.generatePoints();
        }
        if (redraw) {
            chart.redraw(animation);
        }
    },
    /**
     * Internal function to process the data by cropping away unused data
     * points if the series is longer than the crop threshold. This saves
     * computing time for large series. In Highstock, this function is
     * extended to provide data grouping.
     *
     * @private
     * @function Highcharts.Series#processData
     * @param {boolean} [force]
     *        Force data grouping.
     * @return {boolean|undefined}
     */
    processData: function (force) {
        var series = this, 
        // copied during slice operation:
        processedXData = series.xData, processedYData = series.yData, dataLength = processedXData.length, croppedData, cropStart = 0, cropped, distance, closestPointRange, xAxis = series.xAxis, i, // loop variable
        options = series.options, cropThreshold = options.cropThreshold, getExtremesFromAll = series.getExtremesFromAll ||
            options.getExtremesFromAll, // #4599
        isCartesian = series.isCartesian, xExtremes, val2lin = xAxis && xAxis.val2lin, isLog = xAxis && xAxis.isLog, throwOnUnsorted = series.requireSorting, min, max;
        // If the series data or axes haven't changed, don't go through
        // this. Return false to pass the message on to override methods
        // like in data grouping.
        if (isCartesian &&
            !series.isDirty &&
            !xAxis.isDirty &&
            !series.yAxis.isDirty &&
            !force) {
            return false;
        }
        if (xAxis) {
            // corrected for log axis (#3053)
            xExtremes = xAxis.getExtremes();
            min = xExtremes.min;
            max = xExtremes.max;
        }
        // optionally filter out points outside the plot area
        if (isCartesian &&
            series.sorted &&
            !getExtremesFromAll &&
            (!cropThreshold ||
                dataLength > cropThreshold ||
                series.forceCrop)) {
            // it's outside current extremes
            if (processedXData[dataLength - 1] < min ||
                processedXData[0] > max) {
                processedXData = [];
                processedYData = [];
                // only crop if it's actually spilling out
            }
            else if (series.yData && (processedXData[0] < min ||
                processedXData[dataLength - 1] > max)) {
                croppedData = this.cropData(series.xData, series.yData, min, max);
                processedXData = croppedData.xData;
                processedYData = croppedData.yData;
                cropStart = croppedData.start;
                cropped = true;
            }
        }
        // Find the closest distance between processed points
        i = processedXData.length || 1;
        while (--i) {
            distance = (isLog ?
                (val2lin(processedXData[i]) -
                    val2lin(processedXData[i - 1])) :
                (processedXData[i] -
                    processedXData[i - 1]));
            if (distance > 0 &&
                (closestPointRange === undefined ||
                    distance < closestPointRange)) {
                closestPointRange = distance;
                // Unsorted data is not supported by the line tooltip, as well
                // as data grouping and navigation in Stock charts (#725) and
                // width calculation of columns (#1900)
            }
            else if (distance < 0 && throwOnUnsorted) {
                H.error(15, false, series.chart);
                throwOnUnsorted = false; // Only once
            }
        }
        // Record the properties
        series.cropped = cropped; // undefined or true
        series.cropStart = cropStart;
        series.processedXData = processedXData;
        series.processedYData = processedYData;
        series.closestPointRange =
            series.basePointRange = closestPointRange;
    },
    /**
     * Iterate over xData and crop values between min and max. Returns
     * object containing crop start/end cropped xData with corresponding
     * part of yData, dataMin and dataMax within the cropped range.
     *
     * @private
     * @function Highcharts.Series#cropData
     * @param {Array<number>} xData
     * @param {Array<number>} yData
     * @param {number} min
     * @param {number} max
     * @param {number} [cropShoulder]
     * @return {Highcharts.SeriesCropDataObject}
     */
    cropData: function (xData, yData, min, max, cropShoulder) {
        var dataLength = xData.length, cropStart = 0, cropEnd = dataLength, i, j;
        // line-type series need one point outside
        cropShoulder = pick(cropShoulder, this.cropShoulder);
        // iterate up to find slice start
        for (i = 0; i < dataLength; i++) {
            if (xData[i] >= min) {
                cropStart = Math.max(0, i - cropShoulder);
                break;
            }
        }
        // proceed to find slice end
        for (j = i; j < dataLength; j++) {
            if (xData[j] > max) {
                cropEnd = j + cropShoulder;
                break;
            }
        }
        return {
            xData: xData.slice(cropStart, cropEnd),
            yData: yData.slice(cropStart, cropEnd),
            start: cropStart,
            end: cropEnd
        };
    },
    /**
     * Generate the data point after the data has been processed by cropping
     * away unused points and optionally grouped in Highcharts Stock.
     *
     * @private
     * @function Highcharts.Series#generatePoints
     * @return {void}
     */
    generatePoints: function () {
        var series = this, options = series.options, dataOptions = options.data, data = series.data, dataLength, processedXData = series.processedXData, processedYData = series.processedYData, PointClass = series.pointClass, processedDataLength = processedXData.length, cropStart = series.cropStart || 0, cursor, hasGroupedData = series.hasGroupedData, keys = options.keys, point, points = [], i;
        if (!data && !hasGroupedData) {
            var arr = [];
            arr.length = dataOptions.length;
            data = series.data = arr;
        }
        if (keys && hasGroupedData) {
            // grouped data has already applied keys (#6590)
            series.options.keys = false;
        }
        for (i = 0; i < processedDataLength; i++) {
            cursor = cropStart + i;
            if (!hasGroupedData) {
                point = data[cursor];
                // #970:
                if (!point && dataOptions[cursor] !== undefined) {
                    data[cursor] = point = (new PointClass()).init(series, dataOptions[cursor], processedXData[i]);
                }
            }
            else {
                // splat the y data in case of ohlc data array
                point = (new PointClass()).init(series, [processedXData[i]].concat(splat(processedYData[i])));
                /**
                 * Highstock only. If a point object is created by data
                 * grouping, it doesn't reflect actual points in the raw
                 * data. In this case, the `dataGroup` property holds
                 * information that points back to the raw data.
                 *
                 * - `dataGroup.start` is the index of the first raw data
                 *   point in the group.
                 *
                 * - `dataGroup.length` is the amount of points in the
                 *   group.
                 *
                 * @product highstock
                 *
                 * @name Highcharts.Point#dataGroup
                 * @type {Highcharts.DataGroupingInfoObject|undefined}
                 */
                point.dataGroup = series.groupMap[i];
                if (point.dataGroup.options) {
                    point.options = point.dataGroup.options;
                    extend(point, point.dataGroup.options);
                    // Collision of props and options (#9770)
                    delete point.dataLabels;
                }
            }
            if (point) { // #6279
                point.index = cursor; // For faster access in Point.update
                points[i] = point;
            }
        }
        // restore keys options (#6590)
        series.options.keys = keys;
        // Hide cropped-away points - this only runs when the number of
        // points is above cropThreshold, or when swithching view from
        // non-grouped data to grouped data (#637)
        if (data &&
            (processedDataLength !== (dataLength = data.length) ||
                hasGroupedData)) {
            for (i = 0; i < dataLength; i++) {
                // when has grouped data, clear all points
                if (i === cropStart && !hasGroupedData) {
                    i += processedDataLength;
                }
                if (data[i]) {
                    data[i].destroyElements();
                    data[i].plotX = undefined; // #1003
                }
            }
        }
        /**
         * Read only. An array containing those values converted to points.
         * In case the series data length exceeds the `cropThreshold`, or if
         * the data is grouped, `series.data` doesn't contain all the
         * points. Also, in case a series is hidden, the `data` array may be
         * empty. To access raw values, `series.options.data` will always be
         * up to date. `Series.data` only contains the points that have been
         * created on demand. To modify the data, use
         * {@link Highcharts.Series#setData} or
         * {@link Highcharts.Point#update}.
         *
         * @see Series.points
         *
         * @name Highcharts.Series#data
         * @type {Array<Highcharts.Point>}
         */
        series.data = data;
        /**
         * An array containing all currently visible point objects. In case
         * of cropping, the cropped-away points are not part of this array.
         * The `series.points` array starts at `series.cropStart` compared
         * to `series.data` and `series.options.data`. If however the series
         * data is grouped, these can't be correlated one to one. To modify
         * the data, use {@link Highcharts.Series#setData} or
         * {@link Highcharts.Point#update}.
         *
         * @name Highcharts.Series#points
         * @type {Array<Highcharts.Point>}
         */
        series.points = points;
        fireEvent(this, 'afterGeneratePoints');
    },
    /**
     * Get current X extremes for the visible data.
     *
     * @private
     * @function Highcharts.Series#getExtremes
     *
     * @param {Array<number>} xData
     *        The data to inspect. Defaults to the current data within the
     *        visible range.
     * @return {Highcharts.RangeObject}
     */
    getXExtremes: function (xData) {
        return {
            min: arrayMin(xData),
            max: arrayMax(xData)
        };
    },
    /**
     * Calculate Y extremes for the visible data. The result is set as
     * `dataMin` and `dataMax` on the Series item.
     *
     * @private
     * @function Highcharts.Series#getExtremes
     * @param {Array<number>} [yData]
     *        The data to inspect. Defaults to the current data within the
     *        visible range.
     * @return {void}
     */
    getExtremes: function (yData) {
        var xAxis = this.xAxis, yAxis = this.yAxis, xData = this.processedXData, yDataLength, activeYData = [], activeCounter = 0, 
        // #2117, need to compensate for log X axis
        xExtremes = xAxis.getExtremes(), xMin = xExtremes.min, xMax = xExtremes.max, validValue, withinRange, 
        // Handle X outside the viewed area. This does not work with
        // non-sorted data like scatter (#7639).
        shoulder = this.requireSorting ? this.cropShoulder : 0, x, y, i, j;
        yData = yData || this.stackedYData || this.processedYData || [];
        yDataLength = yData.length;
        for (i = 0; i < yDataLength; i++) {
            x = xData[i];
            y = yData[i];
            // For points within the visible range, including the first
            // point outside the visible range (#7061), consider y extremes.
            validValue = ((isNumber(y) || isArray(y)) &&
                (!yAxis.positiveValuesOnly || (y.length || y > 0)));
            withinRange = (this.getExtremesFromAll ||
                this.options.getExtremesFromAll ||
                this.cropped ||
                ((xData[i + shoulder] || x) >= xMin &&
                    (xData[i - shoulder] || x) <= xMax));
            if (validValue && withinRange) {
                j = y.length;
                if (j) { // array, like ohlc or range data
                    while (j--) {
                        if (isNumber(y[j])) { // #7380, #11513
                            activeYData[activeCounter++] = y[j];
                        }
                    }
                }
                else {
                    activeYData[activeCounter++] = y;
                }
            }
        }
        this.dataMin = arrayMin(activeYData);
        this.dataMax = arrayMax(activeYData);
        fireEvent(this, 'afterGetExtremes');
    },
    /**
     * Translate data points from raw data values to chart specific
     * positioning data needed later in the `drawPoints` and `drawGraph`
     * functions. This function can be overridden in plugins and custom
     * series type implementations.
     *
     * @function Highcharts.Series#translate
     * @return {void}
     * @fires Highcharts.Series#events:translate
     */
    translate: function () {
        if (!this.processedXData) { // hidden series
            this.processData();
        }
        this.generatePoints();
        var series = this, options = series.options, stacking = options.stacking, xAxis = series.xAxis, categories = xAxis.categories, yAxis = series.yAxis, points = series.points, dataLength = points.length, hasModifyValue = !!series.modifyValue, i, pointPlacement = series.pointPlacementToXValue(), // #7860
        dynamicallyPlaced = isNumber(pointPlacement), threshold = options.threshold, stackThreshold = options.startFromThreshold ? threshold : 0, plotX, plotY, lastPlotX, stackIndicator, zoneAxis = this.zoneAxis || 'y', closestPointRangePx = Number.MAX_VALUE;
        /**
         * Plotted coordinates need to be within a limited range. Drawing
         * too far outside the viewport causes various rendering issues
         * (#3201, #3923, #7555).
         * @private
         */
        function limitedRange(val) {
            return Math.min(Math.max(-1e5, val), 1e5);
        }
        // Translate each point
        for (i = 0; i < dataLength; i++) {
            var point = points[i], xValue = point.x, yValue = point.y, yBottom = point.low, stack = stacking && yAxis.stacks[(series.negStacks &&
                yValue <
                    (stackThreshold ? 0 : threshold) ?
                '-' :
                '') + series.stackKey], pointStack, stackValues;
            // Discard disallowed y values for log axes (#3434)
            if (yAxis.positiveValuesOnly &&
                yValue !== null &&
                yValue <= 0) {
                point.isNull = true;
            }
            // Get the plotX translation
            point.plotX = plotX = correctFloat(// #5236
            limitedRange(xAxis.translate(// #3923
            xValue, 0, 0, 0, 1, pointPlacement, this.type === 'flags')) // #3923
            );
            // Calculate the bottom y value for stacked series
            if (stacking &&
                series.visible &&
                stack &&
                stack[xValue]) {
                stackIndicator = series.getStackIndicator(stackIndicator, xValue, series.index);
                if (!point.isNull) {
                    pointStack = stack[xValue];
                    stackValues =
                        pointStack.points[stackIndicator.key];
                }
            }
            if (isArray(stackValues)) {
                yBottom = stackValues[0];
                yValue = stackValues[1];
                if (yBottom === stackThreshold &&
                    stackIndicator.key ===
                        stack[xValue].base) {
                    yBottom = (pick((isNumber(threshold) && threshold), yAxis.min));
                }
                // #1200, #1232
                if (yAxis.positiveValuesOnly && yBottom <= 0) {
                    yBottom = null;
                }
                point.total = point.stackTotal = pointStack.total;
                point.percentage =
                    pointStack.total &&
                        (point.y / pointStack.total * 100);
                point.stackY = yValue;
                // Place the stack label
                pointStack.setOffset(series.pointXOffset || 0, series.barW || 0);
            }
            // Set translated yBottom or remove it
            point.yBottom = defined(yBottom) ?
                limitedRange(yAxis.translate(yBottom, 0, 1, 0, 1)) :
                null;
            // general hook, used for Highstock compare mode
            if (hasModifyValue) {
                yValue = series.modifyValue(yValue, point);
            }
            // Set the the plotY value, reset it for redraws
            // #3201
            point.plotY = plotY = ((typeof yValue === 'number' && yValue !== Infinity) ?
                limitedRange(yAxis.translate(yValue, 0, 1, 0, 1)) :
                undefined);
            point.isInside =
                plotY !== undefined &&
                    plotY >= 0 &&
                    plotY <= yAxis.len && // #3519
                    plotX >= 0 &&
                    plotX <= xAxis.len;
            // Set client related positions for mouse tracking
            point.clientX = dynamicallyPlaced ?
                correctFloat(xAxis.translate(xValue, 0, 0, 0, 1, pointPlacement)) :
                plotX; // #1514, #5383, #5518
            // Negative points. For bubble charts, this means negative z
            // values (#9728)
            point.negative = point[zoneAxis] < (options[zoneAxis + 'Threshold'] ||
                threshold ||
                0);
            // some API data
            point.category = (categories &&
                categories[point.x] !== undefined ?
                categories[point.x] :
                point.x);
            // Determine auto enabling of markers (#3635, #5099)
            if (!point.isNull) {
                if (lastPlotX !== undefined) {
                    closestPointRangePx = Math.min(closestPointRangePx, Math.abs(plotX - lastPlotX));
                }
                lastPlotX = plotX;
            }
            // Find point zone
            point.zone = (this.zones.length && point.getZone());
        }
        series.closestPointRangePx = closestPointRangePx;
        fireEvent(this, 'afterTranslate');
    },
    /**
     * Return the series points with null points filtered out.
     *
     * @function Highcharts.Series#getValidPoints
     *
     * @param {Array<Highcharts.Point>} [points]
     *        The points to inspect, defaults to {@link Series.points}.
     *
     * @param {boolean} [insideOnly=false]
     *        Whether to inspect only the points that are inside the visible
     *        view.
     *
     * @param {boolean} [allowNull=false]
     *        Whether to allow null points to pass as valid points.
     *
     * @return {Array<Highcharts.Point>}
     *         The valid points.
     */
    getValidPoints: function (points, insideOnly, allowNull) {
        var chart = this.chart;
        // #3916, #5029, #5085
        return (points || this.points || []).filter(function isValidPoint(point) {
            if (insideOnly && !chart.isInsidePlot(point.plotX, point.plotY, chart.inverted)) {
                return false;
            }
            return allowNull || !point.isNull;
        });
    },
    /**
     * Get the clipping for the series. Could be called for a series to
     * initiate animating the clip or to set the final clip (only width
     * and x).
     *
     * @private
     * @function Highcharts.Series#getClip
     * @param  {boolean|Highcharts.AnimationOptionsObject} [animation]
     *         Initialize the animation.
     * @param  {boolean} [finalBox]
     *         Final size for the clip - end state for the animation.
     * @return {Highcharts.Dictionary<number>}
     */
    getClipBox: function (animation, finalBox) {
        var series = this, options = series.options, chart = series.chart, inverted = chart.inverted, xAxis = series.xAxis, yAxis = xAxis && series.yAxis, clipBox;
        if (animation && options.clip === false && yAxis) {
            // support for not clipped series animation (#10450)
            clipBox = inverted ? {
                y: -chart.chartWidth + yAxis.len + yAxis.pos,
                height: chart.chartWidth,
                width: chart.chartHeight,
                x: -chart.chartHeight + xAxis.len + xAxis.pos
            } : {
                y: -yAxis.pos,
                height: chart.chartHeight,
                width: chart.chartWidth,
                x: -xAxis.pos
            };
            // x and width will be changed later when setting for animation
            // initial state in Series.setClip
        }
        else {
            clipBox = series.clipBox || chart.clipBox;
            if (finalBox) {
                clipBox.width = chart.plotSizeX;
                clipBox.x = 0;
            }
        }
        return !finalBox ? clipBox : {
            width: clipBox.width,
            x: clipBox.x
        };
    },
    /**
     * Set the clipping for the series. For animated series it is called
     * twice, first to initiate animating the clip then the second time
     * without the animation to set the final clip.
     *
     * @private
     * @function Highcharts.Series#setClip
     * @param {boolean|Highcharts.AnimationOptionsObject} [animation]
     * @return {void}
     */
    setClip: function (animation) {
        var chart = this.chart, options = this.options, renderer = chart.renderer, inverted = chart.inverted, seriesClipBox = this.clipBox, clipBox = this.getClipBox(animation), sharedClipKey = this.sharedClipKey ||
            [
                '_sharedClip',
                animation && animation.duration,
                animation && animation.easing,
                clipBox.height,
                options.xAxis,
                options.yAxis
            ].join(','), // #4526
        clipRect = chart[sharedClipKey], markerClipRect = chart[sharedClipKey + 'm'];
        // If a clipping rectangle with the same properties is currently
        // present in the chart, use that.
        if (!clipRect) {
            // When animation is set, prepare the initial positions
            if (animation) {
                clipBox.width = 0;
                if (inverted) {
                    clipBox.x = chart.plotSizeX +
                        (options.clip !== false ? 0 : chart.plotTop);
                }
                chart[sharedClipKey + 'm'] = markerClipRect =
                    renderer.clipRect(
                    // include the width of the first marker
                    inverted ? chart.plotSizeX + 99 : -99, inverted ? -chart.plotLeft : -chart.plotTop, 99, inverted ? chart.chartWidth : chart.chartHeight);
            }
            chart[sharedClipKey] = clipRect =
                renderer.clipRect(clipBox);
            // Create hashmap for series indexes
            clipRect.count = { length: 0 };
        }
        if (animation) {
            if (!clipRect.count[this.index]) {
                clipRect.count[this.index] = true;
                clipRect.count.length += 1;
            }
        }
        if (options.clip !== false || animation) {
            this.group.clip(animation || seriesClipBox ? clipRect : chart.clipRect);
            this.markerGroup.clip(markerClipRect);
            this.sharedClipKey = sharedClipKey;
        }
        // Remove the shared clipping rectangle when all series are shown
        if (!animation) {
            if (clipRect.count[this.index]) {
                delete clipRect.count[this.index];
                clipRect.count.length -= 1;
            }
            if (clipRect.count.length === 0 &&
                sharedClipKey &&
                chart[sharedClipKey]) {
                if (!seriesClipBox) {
                    chart[sharedClipKey] =
                        chart[sharedClipKey].destroy();
                }
                if (chart[sharedClipKey + 'm']) {
                    chart[sharedClipKey + 'm'] =
                        chart[sharedClipKey + 'm'].destroy();
                }
            }
        }
    },
    /**
     * Animate in the series. Called internally twice. First with the `init`
     * parameter set to true, which sets up the initial state of the
     * animation. Then when ready, it is called with the `init` parameter
     * undefined, in order to perform the actual animation. After the
     * second run, the function is removed.
     *
     * @function Highcharts.Series#animate
     *
     * @param {boolean} [init]
     *        Initialize the animation.
     *
     * @return {void}
     */
    animate: function (init) {
        var series = this, chart = series.chart, animation = animObject(series.options.animation), clipRect, sharedClipKey, finalBox;
        // Initialize the animation. Set up the clipping rectangle.
        if (init) {
            series.setClip(animation);
            // Run the animation
        }
        else {
            sharedClipKey = this.sharedClipKey;
            clipRect = chart[sharedClipKey];
            finalBox = series.getClipBox(animation, true);
            if (clipRect) {
                clipRect.animate(finalBox, animation);
            }
            if (chart[sharedClipKey + 'm']) {
                chart[sharedClipKey + 'm'].animate({
                    width: finalBox.width + 99,
                    x: finalBox.x - (chart.inverted ? 0 : 99)
                }, animation);
            }
            // Delete this function to allow it only once
            series.animate = null;
        }
    },
    /**
     * This runs after animation to land on the final plot clipping.
     *
     * @private
     * @function Highcharts.Series#afterAnimate
     * @return {void}
     * @fires Highcharts.Series#event:afterAnimate
     */
    afterAnimate: function () {
        this.setClip();
        fireEvent(this, 'afterAnimate');
        this.finishedAnimating = true;
    },
    /**
     * Draw the markers for line-like series types, and columns or other
     * graphical representation for {@link Point} objects for other series
     * types. The resulting element is typically stored as
     * {@link Point.graphic}, and is created on the first call and updated
     * and moved on subsequent calls.
     *
     * @function Highcharts.Series#drawPoints
     */
    drawPoints: function () {
        var series = this, points = series.points, chart = series.chart, i, point, symbol, graphic, verb, options = series.options, seriesMarkerOptions = options.marker, pointMarkerOptions, hasPointMarker, enabled, isInside, markerGroup = (series[series.specialGroup] ||
            series.markerGroup), xAxis = series.xAxis, markerAttribs, globallyEnabled = pick(seriesMarkerOptions.enabled, !xAxis || xAxis.isRadial ? true : null, 
        // Use larger or equal as radius is null in bubbles (#6321)
        series.closestPointRangePx >= (seriesMarkerOptions.enabledThreshold *
            seriesMarkerOptions.radius));
        if (seriesMarkerOptions.enabled !== false ||
            series._hasPointMarkers) {
            for (i = 0; i < points.length; i++) {
                point = points[i];
                graphic = point.graphic;
                verb = graphic ? 'animate' : 'attr';
                pointMarkerOptions = point.marker || {};
                hasPointMarker = !!point.marker;
                enabled = (globallyEnabled &&
                    pointMarkerOptions.enabled === undefined) || pointMarkerOptions.enabled;
                isInside = point.isInside !== false;
                // only draw the point if y is defined
                if (enabled && !point.isNull) {
                    // Shortcuts
                    symbol = pick(pointMarkerOptions.symbol, series.symbol);
                    markerAttribs = series.markerAttribs(point, (point.selected && 'select'));
                    if (graphic) { // update
                        // Since the marker group isn't clipped, each
                        // individual marker must be toggled
                        graphic[isInside ? 'show' : 'hide'](isInside)
                            .animate(markerAttribs);
                    }
                    else if (isInside &&
                        (markerAttribs.width > 0 || point.hasImage)) {
                        /**
                         * The graphic representation of the point.
                         * Typically this is a simple shape, like a `rect`
                         * for column charts or `path` for line markers, but
                         * for some complex series types like boxplot or 3D
                         * charts, the graphic may be a `g` element
                         * containing other shapes. The graphic is generated
                         * the first time {@link Series#drawPoints} runs,
                         * and updated and moved on subsequent runs.
                         *
                         * @name Point#graphic
                         * @type {SVGElement}
                         */
                        point.graphic = graphic = chart.renderer
                            .symbol(symbol, markerAttribs.x, markerAttribs.y, markerAttribs.width, markerAttribs.height, hasPointMarker ?
                            pointMarkerOptions :
                            seriesMarkerOptions)
                            .add(markerGroup);
                    }
                    // Presentational attributes
                    if (graphic && !chart.styledMode) {
                        graphic[verb](series.pointAttribs(point, (point.selected && 'select')));
                    }
                    if (graphic) {
                        graphic.addClass(point.getClassName(), true);
                    }
                }
                else if (graphic) {
                    point.graphic = graphic.destroy(); // #1269
                }
            }
        }
    },
    /**
     * Get non-presentational attributes for a point. Used internally for
     * both styled mode and classic. Can be overridden for different series
     * types.
     *
     * @see Series#pointAttribs
     *
     * @function Highcharts.Series#markerAttribs
     *
     * @param {Highcharts.Point} point
     *        The Point to inspect.
     *
     * @param {string} [state]
     *        The state, can be either `hover`, `select` or undefined.
     *
     * @return {Highcharts.SVGAttributes}
     *         A hash containing those attributes that are not settable from
     *         CSS.
     */
    markerAttribs: function (point, state) {
        var seriesMarkerOptions = this.options.marker, seriesStateOptions, pointMarkerOptions = point.marker || {}, symbol = (pointMarkerOptions.symbol ||
            seriesMarkerOptions.symbol), pointStateOptions, radius = pick(pointMarkerOptions.radius, seriesMarkerOptions.radius), attribs;
        // Handle hover and select states
        if (state) {
            seriesStateOptions = seriesMarkerOptions.states[state];
            pointStateOptions = pointMarkerOptions.states &&
                pointMarkerOptions.states[state];
            radius = pick(pointStateOptions && pointStateOptions.radius, seriesStateOptions && seriesStateOptions.radius, radius + (seriesStateOptions && seriesStateOptions.radiusPlus ||
                0));
        }
        point.hasImage = symbol && symbol.indexOf('url') === 0;
        if (point.hasImage) {
            radius = 0; // and subsequently width and height is not set
        }
        attribs = {
            // Math.floor for #1843:
            x: Math.floor(point.plotX) - radius,
            y: point.plotY - radius
        };
        if (radius) {
            attribs.width = attribs.height = 2 * radius;
        }
        return attribs;
    },
    /**
     * Internal function to get presentational attributes for each point.
     * Unlike {@link Series#markerAttribs}, this function should return
     * those attributes that can also be set in CSS. In styled mode,
     * `pointAttribs` won't be called.
     *
     * @private
     * @function Highcharts.Series#pointAttribs
     *
     * @param {Highcharts.Point} point
     *        The point instance to inspect.
     *
     * @param {string} [state]
     *        The point state, can be either `hover`, `select` or 'normal'.
     *        If undefined, normal state is assumed.
     *
     * @return {Highcharts.SVGAttributes}
     *         The presentational attributes to be set on the point.
     */
    pointAttribs: function (point, state) {
        var seriesMarkerOptions = this.options.marker, seriesStateOptions, pointOptions = point && point.options, pointMarkerOptions = ((pointOptions && pointOptions.marker) || {}), pointStateOptions, color = this.color, pointColorOption = pointOptions && pointOptions.color, pointColor = point && point.color, strokeWidth = pick(pointMarkerOptions.lineWidth, seriesMarkerOptions.lineWidth), zoneColor = point && point.zone && point.zone.color, fill, stroke, opacity = 1;
        color = (pointColorOption ||
            zoneColor ||
            pointColor ||
            color);
        fill = (pointMarkerOptions.fillColor ||
            seriesMarkerOptions.fillColor ||
            color);
        stroke = (pointMarkerOptions.lineColor ||
            seriesMarkerOptions.lineColor ||
            color);
        // Handle hover and select states
        state = state || 'normal';
        if (state) {
            seriesStateOptions = seriesMarkerOptions.states[state];
            pointStateOptions = (pointMarkerOptions.states &&
                pointMarkerOptions.states[state]) || {};
            strokeWidth = pick(pointStateOptions.lineWidth, seriesStateOptions.lineWidth, strokeWidth + pick(pointStateOptions.lineWidthPlus, seriesStateOptions.lineWidthPlus, 0));
            fill = (pointStateOptions.fillColor ||
                seriesStateOptions.fillColor ||
                fill);
            stroke = (pointStateOptions.lineColor ||
                seriesStateOptions.lineColor ||
                stroke);
            opacity = pick(pointStateOptions.opacity, seriesStateOptions.opacity, opacity);
        }
        return {
            'stroke': stroke,
            'stroke-width': strokeWidth,
            'fill': fill,
            'opacity': opacity
        };
    },
    /**
     * Clear DOM objects and free up memory.
     *
     * @private
     * @function Highcharts.Series#destroy
     * @param {boolean} [keepEvents]
     * @return {void}
     * @fires Highcharts.Series#event:destroy
     */
    destroy: function (keepEvents) {
        var series = this, chart = series.chart, issue134 = /AppleWebKit\/533/.test(win.navigator.userAgent), destroy, i, data = series.data || [], point, axis;
        // add event hook
        fireEvent(series, 'destroy');
        // remove all events
        if (!keepEvents) {
            removeEvent(series);
        }
        // erase from axes
        (series.axisTypes || []).forEach(function (AXIS) {
            axis = series[AXIS];
            if (axis && axis.series) {
                erase(axis.series, series);
                axis.isDirty = axis.forceRedraw = true;
            }
        });
        // remove legend items
        if (series.legendItem) {
            series.chart.legend.destroyItem(series);
        }
        // destroy all points with their elements
        i = data.length;
        while (i--) {
            point = data[i];
            if (point && point.destroy) {
                point.destroy();
            }
        }
        series.points = null;
        // Clear the animation timeout if we are destroying the series
        // during initial animation
        H.clearTimeout(series.animationTimeout);
        // Destroy all SVGElements associated to the series
        objectEach(series, function (val, prop) {
            // Survive provides a hook for not destroying
            if (val instanceof SVGElement && !val.survive) {
                // issue 134 workaround
                destroy = issue134 && prop === 'group' ?
                    'hide' :
                    'destroy';
                val[destroy]();
            }
        });
        // remove from hoverSeries
        if (chart.hoverSeries === series) {
            chart.hoverSeries = null;
        }
        erase(chart.series, series);
        chart.orderSeries();
        // clear all members
        objectEach(series, function (val, prop) {
            if (!keepEvents || prop !== 'hcEvents') {
                delete series[prop];
            }
        });
    },
    /**
     * Get the graph path.
     *
     * @private
     * @function Highcharts.Series#getGraphPath
     * @param {Array<Highcharts.Point>} points
     * @param {boolean} [nullsAsZeroes]
     * @param {boolean} [connectCliffs]
     * @return {Highcharts.SVGPathArray}
     */
    getGraphPath: function (points, nullsAsZeroes, connectCliffs) {
        var series = this, options = series.options, step = options.step, reversed, graphPath = [], xMap = [], gap;
        points = points || series.points;
        // Bottom of a stack is reversed
        reversed = points.reversed;
        if (reversed) {
            points.reverse();
        }
        // Reverse the steps (#5004)
        step = {
            right: 1,
            center: 2
        }[step] || (step && 3);
        if (step && reversed) {
            step = 4 - step;
        }
        // Remove invalid points, especially in spline (#5015)
        if (options.connectNulls && !nullsAsZeroes && !connectCliffs) {
            points = this.getValidPoints(points);
        }
        // Build the line
        points.forEach(function (point, i) {
            var plotX = point.plotX, plotY = point.plotY, lastPoint = points[i - 1], 
            // the path to this point from the previous
            pathToPoint;
            if ((point.leftCliff || (lastPoint && lastPoint.rightCliff)) &&
                !connectCliffs) {
                gap = true; // ... and continue
            }
            // Line series, nullsAsZeroes is not handled
            if (point.isNull && !defined(nullsAsZeroes) && i > 0) {
                gap = !options.connectNulls;
                // Area series, nullsAsZeroes is set
            }
            else if (point.isNull && !nullsAsZeroes) {
                gap = true;
            }
            else {
                if (i === 0 || gap) {
                    pathToPoint = [
                        'M',
                        point.plotX,
                        point.plotY
                    ];
                    // Generate the spline as defined in the SplineSeries object
                }
                else if (series.getPointSpline) {
                    pathToPoint = series.getPointSpline(points, point, i);
                }
                else if (step) {
                    if (step === 1) { // right
                        pathToPoint = [
                            'L',
                            lastPoint.plotX,
                            plotY
                        ];
                    }
                    else if (step === 2) { // center
                        pathToPoint = [
                            'L',
                            (lastPoint.plotX + plotX) / 2,
                            lastPoint.plotY,
                            'L',
                            (lastPoint.plotX + plotX) / 2,
                            plotY
                        ];
                    }
                    else {
                        pathToPoint = [
                            'L',
                            plotX,
                            lastPoint.plotY
                        ];
                    }
                    pathToPoint.push('L', plotX, plotY);
                }
                else {
                    // normal line to next point
                    pathToPoint = [
                        'L',
                        plotX,
                        plotY
                    ];
                }
                // Prepare for animation. When step is enabled, there are
                // two path nodes for each x value.
                xMap.push(point.x);
                if (step) {
                    xMap.push(point.x);
                    if (step === 2) { // step = center (#8073)
                        xMap.push(point.x);
                    }
                }
                graphPath.push.apply(graphPath, pathToPoint);
                gap = false;
            }
        });
        graphPath.xMap = xMap;
        series.graphPath = graphPath;
        return graphPath;
    },
    /**
     * Draw the graph. Called internally when rendering line-like series
     * types. The first time it generates the `series.graph` item and
     * optionally other series-wide items like `series.area` for area
     * charts. On subsequent calls these items are updated with new
     * positions and attributes.
     *
     * @function Highcharts.Series#drawGraph
     *
     * @return {void}
     */
    drawGraph: function () {
        var series = this, options = this.options, graphPath = (this.gappedPath || this.getGraphPath).call(this), styledMode = this.chart.styledMode, props = [[
                'graph',
                'highcharts-graph'
            ]];
        // Presentational properties
        if (!styledMode) {
            props[0].push((options.lineColor ||
                this.color ||
                '#cccccc' // when colorByPoint = true
            ), options.dashStyle);
        }
        props = series.getZonesGraphs(props);
        // Draw the graph
        props.forEach(function (prop, i) {
            var graphKey = prop[0], graph = series[graphKey], verb = graph ? 'animate' : 'attr', attribs;
            if (graph) {
                graph.endX = series.preventGraphAnimation ?
                    null :
                    graphPath.xMap;
                graph.animate({ d: graphPath });
            }
            else if (graphPath.length) { // #1487
                /**
                 * SVG element of area-based charts. Can be used for styling
                 * purposes. If zones are configured, this element will be
                 * hidden and replaced by multiple zone areas, accessible
                 * via `series['zone-area-x']` (where x is a number,
                 * starting with 0).
                 *
                 * @name Highcharts.Series#area
                 * @type {Highcharts.SVGElement|undefined}
                 */
                /**
                 * SVG element of line-based charts. Can be used for styling
                 * purposes. If zones are configured, this element will be
                 * hidden and replaced by multiple zone lines, accessible
                 * via `series['zone-graph-x']` (where x is a number,
                 * starting with 0).
                 *
                 * @name Highcharts.Series#graph
                 * @type {Highcharts.SVGElement|undefined}
                 */
                series[graphKey] = graph = series.chart.renderer
                    .path(graphPath)
                    .addClass(prop[1])
                    .attr({ zIndex: 1 }) // #1069
                    .add(series.group);
            }
            if (graph && !styledMode) {
                attribs = {
                    'stroke': prop[2],
                    'stroke-width': options.lineWidth,
                    // Polygon series use filled graph
                    'fill': (series.fillGraph && series.color) || 'none'
                };
                if (prop[3]) {
                    attribs.dashstyle = prop[3];
                }
                else if (options.linecap !== 'square') {
                    attribs['stroke-linecap'] =
                        attribs['stroke-linejoin'] = 'round';
                }
                graph[verb](attribs)
                    // Add shadow to normal series (0) or to first
                    // zone (1) #3932
                    .shadow((i < 2) && options.shadow);
            }
            // Helpers for animation
            if (graph) {
                graph.startX = graphPath.xMap;
                graph.isArea = graphPath.isArea; // For arearange animation
            }
        });
    },
    /**
     * Get zones properties for building graphs. Extendable by series with
     * multiple lines within one series.
     *
     * @private
     * @function Highcharts.Series#getZonesGraphs
     *
     * @param {Array<Array<string>>} props
     *
     * @return {Array<Array<string>>}
     */
    getZonesGraphs: function (props) {
        // Add the zone properties if any
        this.zones.forEach(function (zone, i) {
            var propset = [
                'zone-graph-' + i,
                'highcharts-graph highcharts-zone-graph-' + i + ' ' +
                    (zone.className || '')
            ];
            if (!this.chart.styledMode) {
                propset.push((zone.color || this.color), (zone.dashStyle || this.options.dashStyle));
            }
            props.push(propset);
        }, this);
        return props;
    },
    /**
     * Clip the graphs into zones for colors and styling.
     *
     * @private
     * @function Highcharts.Series#applyZones
     * @return {void}
     */
    applyZones: function () {
        var series = this, chart = this.chart, renderer = chart.renderer, zones = this.zones, translatedFrom, translatedTo, clips = (this.clips || []), clipAttr, graph = this.graph, area = this.area, chartSizeMax = Math.max(chart.chartWidth, chart.chartHeight), axis = this[(this.zoneAxis || 'y') + 'Axis'], extremes, reversed, inverted = chart.inverted, horiz, pxRange, pxPosMin, pxPosMax, ignoreZones = false;
        if (zones.length &&
            (graph || area) &&
            axis &&
            axis.min !== undefined) {
            reversed = axis.reversed;
            horiz = axis.horiz;
            // The use of the Color Threshold assumes there are no gaps
            // so it is safe to hide the original graph and area
            // unless it is not waterfall series, then use showLine property
            // to set lines between columns to be visible (#7862)
            if (graph && !this.showLine) {
                graph.hide();
            }
            if (area) {
                area.hide();
            }
            // Create the clips
            extremes = axis.getExtremes();
            zones.forEach(function (threshold, i) {
                translatedFrom = reversed ?
                    (horiz ? chart.plotWidth : 0) :
                    (horiz ? 0 : (axis.toPixels(extremes.min) || 0));
                translatedFrom = Math.min(Math.max(pick(translatedTo, translatedFrom), 0), chartSizeMax);
                translatedTo = Math.min(Math.max(Math.round(axis.toPixels(pick(threshold.value, extremes.max), true) || 0), 0), chartSizeMax);
                if (ignoreZones) {
                    translatedFrom = translatedTo =
                        axis.toPixels(extremes.max);
                }
                pxRange = Math.abs(translatedFrom - translatedTo);
                pxPosMin = Math.min(translatedFrom, translatedTo);
                pxPosMax = Math.max(translatedFrom, translatedTo);
                if (axis.isXAxis) {
                    clipAttr = {
                        x: inverted ? pxPosMax : pxPosMin,
                        y: 0,
                        width: pxRange,
                        height: chartSizeMax
                    };
                    if (!horiz) {
                        clipAttr.x = chart.plotHeight - clipAttr.x;
                    }
                }
                else {
                    clipAttr = {
                        x: 0,
                        y: inverted ? pxPosMax : pxPosMin,
                        width: chartSizeMax,
                        height: pxRange
                    };
                    if (horiz) {
                        clipAttr.y = chart.plotWidth - clipAttr.y;
                    }
                }
                // VML SUPPPORT
                if (inverted && renderer.isVML) {
                    if (axis.isXAxis) {
                        clipAttr = {
                            x: 0,
                            y: reversed ? pxPosMin : pxPosMax,
                            height: clipAttr.width,
                            width: chart.chartWidth
                        };
                    }
                    else {
                        clipAttr = {
                            x: (clipAttr.y -
                                chart.plotLeft -
                                chart.spacingBox.x),
                            y: 0,
                            width: clipAttr.height,
                            height: chart.chartHeight
                        };
                    }
                }
                // END OF VML SUPPORT
                if (clips[i]) {
                    clips[i].animate(clipAttr);
                }
                else {
                    clips[i] = renderer.clipRect(clipAttr);
                }
                // when no data, graph zone is not applied and after setData
                // clip was ignored. As a result, it should be applied each
                // time.
                if (graph) {
                    series['zone-graph-' + i].clip(clips[i]);
                }
                if (area) {
                    series['zone-area-' + i].clip(clips[i]);
                }
                // if this zone extends out of the axis, ignore the others
                ignoreZones = threshold.value > extremes.max;
                // Clear translatedTo for indicators
                if (series.resetZones && translatedTo === 0) {
                    translatedTo = undefined;
                }
            });
            this.clips = clips;
        }
        else if (series.visible) {
            // If zones were removed, restore graph and area
            if (graph) {
                graph.show(true);
            }
            if (area) {
                area.show(true);
            }
        }
    },
    /**
     * Initialize and perform group inversion on series.group and
     * series.markerGroup.
     *
     * @private
     * @function Highcharts.Series#invertGroups
     * @param {boolean} [inverted]
     * @return {void}
     */
    invertGroups: function (inverted) {
        var series = this, chart = series.chart, remover;
        /**
         * @private
         */
        function setInvert() {
            ['group', 'markerGroup'].forEach(function (groupName) {
                if (series[groupName]) {
                    // VML/HTML needs explicit attributes for flipping
                    if (chart.renderer.isVML) {
                        series[groupName].attr({
                            width: series.yAxis.len,
                            height: series.xAxis.len
                        });
                    }
                    series[groupName].width = series.yAxis.len;
                    series[groupName].height = series.xAxis.len;
                    series[groupName].invert(inverted);
                }
            });
        }
        // Pie, go away (#1736)
        if (!series.xAxis) {
            return;
        }
        // A fixed size is needed for inversion to work
        remover = addEvent(chart, 'resize', setInvert);
        addEvent(series, 'destroy', remover);
        // Do it now
        setInvert(inverted); // do it now
        // On subsequent render and redraw, just do setInvert without
        // setting up events again
        series.invertGroups = setInvert;
    },
    /**
     * General abstraction for creating plot groups like series.group,
     * series.dataLabelsGroup and series.markerGroup. On subsequent calls,
     * the group will only be adjusted to the updated plot size.
     *
     * @private
     * @function Highcharts.Series#plotGroup
     * @param {string} prop
     * @param {string} name
     * @param {string} visibility
     * @param {number} [zIndex]
     * @param {Highcharts.SVGElement} [parent]
     * @return {Highcharts.SVGElement}
     */
    plotGroup: function (prop, name, visibility, zIndex, parent) {
        var group = this[prop], isNew = !group;
        // Generate it on first call
        if (isNew) {
            this[prop] = group = this.chart.renderer
                .g()
                .attr({
                zIndex: zIndex || 0.1 // IE8 and pointer logic use this
            })
                .add(parent);
        }
        // Add the class names, and replace existing ones as response to
        // Series.update (#6660)
        group.addClass(('highcharts-' + name +
            ' highcharts-series-' + this.index +
            ' highcharts-' + this.type + '-series ' +
            (defined(this.colorIndex) ?
                'highcharts-color-' + this.colorIndex + ' ' :
                '') +
            (this.options.className || '') +
            (group.hasClass('highcharts-tracker') ?
                ' highcharts-tracker' :
                '')), true);
        // Place it on first and subsequent (redraw) calls
        group.attr({ visibility: visibility })[isNew ? 'attr' : 'animate'](this.getPlotBox());
        return group;
    },
    /**
     * Get the translation and scale for the plot area of this series.
     *
     * @function Highcharts.Series#getPlotBox
     *
     * @return {Highcharts.SeriesPlotBoxObject}
     */
    getPlotBox: function () {
        var chart = this.chart, xAxis = this.xAxis, yAxis = this.yAxis;
        // Swap axes for inverted (#2339)
        if (chart.inverted) {
            xAxis = yAxis;
            yAxis = this.xAxis;
        }
        return {
            translateX: xAxis ? xAxis.left : chart.plotLeft,
            translateY: yAxis ? yAxis.top : chart.plotTop,
            scaleX: 1,
            scaleY: 1
        };
    },
    /**
     * Render the graph and markers. Called internally when first rendering
     * and later when redrawing the chart. This function can be extended in
     * plugins, but normally shouldn't be called directly.
     *
     * @function Highcharts.Series#render
     *
     * @return {void}
     *
     * @fires Highcharts.Series#event:afterRender
     */
    render: function () {
        var series = this, chart = series.chart, group, options = series.options, 
        // Animation doesn't work in IE8 quirks when the group div is
        // hidden, and looks bad in other oldIE
        animDuration = (!!series.animate &&
            chart.renderer.isSVG &&
            animObject(options.animation).duration), visibility = series.visible ? 'inherit' : 'hidden', // #2597
        zIndex = options.zIndex, hasRendered = series.hasRendered, chartSeriesGroup = chart.seriesGroup, inverted = chart.inverted;
        fireEvent(this, 'render');
        // the group
        group = series.plotGroup('group', 'series', visibility, zIndex, chartSeriesGroup);
        series.markerGroup = series.plotGroup('markerGroup', 'markers', visibility, zIndex, chartSeriesGroup);
        // initiate the animation
        if (animDuration) {
            series.animate(true);
        }
        // SVGRenderer needs to know this before drawing elements (#1089,
        // #1795)
        group.inverted = series.isCartesian || series.invertable ?
            inverted : false;
        // Draw the graph if any
        if (series.drawGraph) {
            series.drawGraph();
            series.applyZones();
        }
        // Draw the points
        if (series.visible) {
            series.drawPoints();
        }
        /* series.points.forEach(function (point) {
            if (point.redraw) {
                point.redraw();
            }
        }); */
        // Draw the data labels
        if (series.drawDataLabels) {
            series.drawDataLabels();
        }
        // In pie charts, slices are added to the DOM, but actual rendering
        // is postponed until labels reserved their space
        if (series.redrawPoints) {
            series.redrawPoints();
        }
        // draw the mouse tracking area
        if (series.drawTracker &&
            series.options.enableMouseTracking !== false) {
            series.drawTracker();
        }
        // Handle inverted series and tracker groups
        series.invertGroups(inverted);
        // Initial clipping, must be defined after inverting groups for VML.
        // Applies to columns etc. (#3839).
        if (options.clip !== false &&
            !series.sharedClipKey &&
            !hasRendered) {
            group.clip(chart.clipRect);
        }
        // Run the animation
        if (animDuration) {
            series.animate();
        }
        // Call the afterAnimate function on animation complete (but don't
        // overwrite the animation.complete option which should be available
        // to the user).
        if (!hasRendered) {
            series.animationTimeout = syncTimeout(function () {
                series.afterAnimate();
            }, animDuration);
        }
        // Means data is in accordance with what you see
        series.isDirty = false;
        // (See #322) series.isDirty = series.isDirtyData = false; // means
        // data is in accordance with what you see
        series.hasRendered = true;
        fireEvent(series, 'afterRender');
    },
    /**
     * Redraw the series. This function is called internally from
     * `chart.redraw` and normally shouldn't be called directly.
     *
     * @private
     * @function Highcharts.Series#redraw
     * @return {void}
     */
    redraw: function () {
        var series = this, chart = series.chart, 
        // cache it here as it is set to false in render, but used after
        wasDirty = series.isDirty || series.isDirtyData, group = series.group, xAxis = series.xAxis, yAxis = series.yAxis;
        // reposition on resize
        if (group) {
            if (chart.inverted) {
                group.attr({
                    width: chart.plotWidth,
                    height: chart.plotHeight
                });
            }
            group.animate({
                translateX: pick(xAxis && xAxis.left, chart.plotLeft),
                translateY: pick(yAxis && yAxis.top, chart.plotTop)
            });
        }
        series.translate();
        series.render();
        if (wasDirty) { // #3868, #3945
            delete this.kdTree;
        }
    },
    kdAxisArray: ['clientX', 'plotY'],
    /**
     * @private
     * @function Highcharts.Series#searchPoint
     * @param {Highcharts.PointerEventObject} e
     * @param {boolean} [compareX]
     * @return {Highcharts.Point}
     */
    searchPoint: function (e, compareX) {
        var series = this, xAxis = series.xAxis, yAxis = series.yAxis, inverted = series.chart.inverted;
        return this.searchKDTree({
            clientX: inverted ?
                xAxis.len - e.chartY + xAxis.pos :
                e.chartX - xAxis.pos,
            plotY: inverted ?
                yAxis.len - e.chartX + yAxis.pos :
                e.chartY - yAxis.pos
        }, compareX, e);
    },
    /**
     * Build the k-d-tree that is used by mouse and touch interaction to get
     * the closest point. Line-like series typically have a one-dimensional
     * tree where points are searched along the X axis, while scatter-like
     * series typically search in two dimensions, X and Y.
     *
     * @private
     * @function Highcharts.Series#buildKDTree
     * @param {Highcharts.PointerEventObject} [e]
     * @return {void}
     */
    buildKDTree: function (e) {
        // Prevent multiple k-d-trees from being built simultaneously
        // (#6235)
        this.buildingKdTree = true;
        var series = this, dimensions = series.options.findNearestPointBy
            .indexOf('y') > -1 ? 2 : 1;
        /**
         * Internal function
         * @private
         */
        function _kdtree(points, depth, dimensions) {
            var axis, median, length = points && points.length;
            if (length) {
                // alternate between the axis
                axis = series.kdAxisArray[depth % dimensions];
                // sort point array
                points.sort(function (a, b) {
                    return a[axis] - b[axis];
                });
                median = Math.floor(length / 2);
                // build and return nod
                return {
                    point: points[median],
                    left: _kdtree(points.slice(0, median), depth + 1, dimensions),
                    right: _kdtree(points.slice(median + 1), depth + 1, dimensions)
                };
            }
        }
        /**
         * Start the recursive build process with a clone of the points
         * array and null points filtered out. (#3873)
         * @private
         */
        function startRecursive() {
            series.kdTree = _kdtree(series.getValidPoints(null, 
            // For line-type series restrict to plot area, but
            // column-type series not (#3916, #4511)
            !series.directTouch), dimensions, dimensions);
            series.buildingKdTree = false;
        }
        delete series.kdTree;
        // For testing tooltips, don't build async. Also if touchstart, we
        // may be dealing with click events on mobile, so don't delay
        // (#6817).
        syncTimeout(startRecursive, series.options.kdNow || (e && e.type === 'touchstart') ? 0 : 1);
    },
    /**
     * @private
     * @function Highcharts.Series#searchKDTree
     * @param {Highcharts.KDPointSearchObject} point
     * @param {boolean} [compareX]
     * @param {Highcharts.PointerEventObject} [e]
     * @return {Highcharts.Point|undefined}
     */
    searchKDTree: function (point, compareX, e) {
        var series = this, kdX = this.kdAxisArray[0], kdY = this.kdAxisArray[1], kdComparer = compareX ? 'distX' : 'dist', kdDimensions = series.options.findNearestPointBy
            .indexOf('y') > -1 ? 2 : 1;
        /**
         * Set the one and two dimensional distance on the point object.
         * @private
         */
        function setDistance(p1, p2) {
            var x = (defined(p1[kdX]) &&
                defined(p2[kdX])) ?
                Math.pow(p1[kdX] - p2[kdX], 2) :
                null, y = (defined(p1[kdY]) &&
                defined(p2[kdY])) ?
                Math.pow(p1[kdY] - p2[kdY], 2) :
                null, r = (x || 0) + (y || 0);
            p2.dist = defined(r) ? Math.sqrt(r) : Number.MAX_VALUE;
            p2.distX = defined(x) ? Math.sqrt(x) : Number.MAX_VALUE;
        }
        /**
         * @private
         */
        function _search(search, tree, depth, dimensions) {
            var point = tree.point, axis = series.kdAxisArray[depth % dimensions], tdist, sideA, sideB, ret = point, nPoint1, nPoint2;
            setDistance(search, point);
            // Pick side based on distance to splitting point
            tdist = search[axis] - point[axis];
            sideA = tdist < 0 ? 'left' : 'right';
            sideB = tdist < 0 ? 'right' : 'left';
            // End of tree
            if (tree[sideA]) {
                nPoint1 = _search(search, tree[sideA], depth + 1, dimensions);
                ret = (nPoint1[kdComparer] <
                    ret[kdComparer] ?
                    nPoint1 :
                    point);
            }
            if (tree[sideB]) {
                // compare distance to current best to splitting point to
                // decide wether to check side B or not
                if (Math.sqrt(tdist * tdist) < ret[kdComparer]) {
                    nPoint2 = _search(search, tree[sideB], depth + 1, dimensions);
                    ret = (nPoint2[kdComparer] <
                        ret[kdComparer] ?
                        nPoint2 :
                        ret);
                }
            }
            return ret;
        }
        if (!this.kdTree && !this.buildingKdTree) {
            this.buildKDTree(e);
        }
        if (this.kdTree) {
            return _search(point, this.kdTree, kdDimensions, kdDimensions);
        }
    },
    /**
     * @private
     * @function Highcharts.Series#pointPlacementToXValue
     * @return {number}
     */
    pointPlacementToXValue: function () {
        var series = this, pointPlacement = series.options.pointPlacement;
        // Point placement is relative to each series pointRange (#5889)
        if (pointPlacement === 'between') {
            pointPlacement = 0.5;
        }
        if (isNumber(pointPlacement)) {
            pointPlacement *=
                pick(series.options.pointRange || series.xAxis.pointRange);
        }
        return pointPlacement;
    }
}); // end Series prototype
/**
 * A line series displays information as a series of data points connected by
 * straight line segments.
 *
 * @sample {highcharts} highcharts/demo/line-basic/
 *         Line chart
 * @sample {highstock} stock/demo/basic-line/
 *         Line chart
 *
 * @extends   plotOptions.series
 * @product   highcharts highstock
 * @apioption plotOptions.line
 */
/**
 * The SVG value used for the `stroke-linecap` and `stroke-linejoin`
 * of a line graph. Round means that lines are rounded in the ends and
 * bends.
 *
 * @type       {Highcharts.SeriesLinecapValue}
 * @default    round
 * @since      3.0.7
 * @apioption  plotOptions.line.linecap
 */
/**
 * A `line` series. If the [type](#series.line.type) option is not
 * specified, it is inherited from [chart.type](#chart.type).
 *
 * In TypeScript instead the `type` option must always be set.
 *
 * @extends   series,plotOptions.line
 * @excluding dataParser,dataURL
 * @product   highcharts highstock
 * @apioption series.line
 */
/**
 * An array of data points for the series. For the `line` series type,
 * points can be given in the following ways:
 *
 * 1. An array of numerical values. In this case, the numerical values will be
 *    interpreted as `y` options. The `x` values will be automatically
 *    calculated, either starting at 0 and incremented by 1, or from
 *    `pointStart` and `pointInterval` given in the series options. If the axis
 *    has categories, these will be used. Example:
 *    ```js
 *    data: [0, 5, 3, 5]
 *    ```
 *
 * 2. An array of arrays with 2 values. In this case, the values correspond to
 *    `x,y`. If the first value is a string, it is applied as the name of the
 *    point, and the `x` value is inferred.
 *    ```js
 *    data: [
 *        [0, 1],
 *        [1, 2],
 *        [2, 8]
 *    ]
 *    ```
 *
 * 3. An array of objects with named values. The following snippet shows only a
 *    few settings, see the complete options set below. If the total number of
 *    data points exceeds the series'
 *    [turboThreshold](#series.line.turboThreshold),
 *    this option is not available.
 *    ```js
 *    data: [{
 *        x: 1,
 *        y: 9,
 *        name: "Point2",
 *        color: "#00FF00"
 *    }, {
 *        x: 1,
 *        y: 6,
 *        name: "Point1",
 *        color: "#FF00FF"
 *    }]
 *    ```
 *
 * @sample {highcharts} highcharts/chart/reflow-true/
 *         Numerical values
 * @sample {highcharts} highcharts/series/data-array-of-arrays/
 *         Arrays of numeric x and y
 * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
 *         Arrays of datetime x and y
 * @sample {highcharts} highcharts/series/data-array-of-name-value/
 *         Arrays of point.name and y
 * @sample {highcharts} highcharts/series/data-array-of-objects/
 *         Config objects
 *
 * @type      {Array<number|Array<(number|string),(number|null)>|null|*>}
 * @apioption series.line.data
 */
/**
 * An additional, individual class name for the data point's graphic
 * representation.
 *
 * @type      {string}
 * @since     5.0.0
 * @product   highcharts gantt
 * @apioption series.line.data.className
 */
/**
 * Individual color for the point. By default the color is pulled from
 * the global `colors` array.
 *
 * In styled mode, the `color` option doesn't take effect. Instead, use
 * `colorIndex`.
 *
 * @sample {highcharts} highcharts/point/color/
 *         Mark the highest point
 *
 * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
 * @product   highcharts highstock gantt
 * @apioption series.line.data.color
 */
/**
 * A specific color index to use for the point, so its graphic representations
 * are given the class name `highcharts-color-{n}`. In styled mode this will
 * change the color of the graphic. In non-styled mode, the color by is set by
 * the `fill` attribute, so the change in class name won't have a visual effect
 * by default.
 *
 * @type      {number}
 * @since     5.0.0
 * @product   highcharts gantt
 * @apioption series.line.data.colorIndex
 */
/**
 * Individual data label for each point. The options are the same as
 * the ones for [plotOptions.series.dataLabels](
 * #plotOptions.series.dataLabels).
 *
 * @sample highcharts/point/datalabels/
 *         Show a label for the last value
 *
 * @type      {Highcharts.DataLabelsOptionsObject|Array<Highcharts.DataLabelsOptionsObject>}
 * @product   highcharts highstock gantt
 * @apioption series.line.data.dataLabels
 */
/**
 * A description of the point to add to the screen reader information
 * about the point. Requires the Accessibility module.
 *
 * @type      {string}
 * @since     5.0.0
 * @apioption series.line.data.description
 */
/**
 * An id for the point. This can be used after render time to get a
 * pointer to the point object through `chart.get()`.
 *
 * @sample {highcharts} highcharts/point/id/
 *         Remove an id'd point
 *
 * @type      {string}
 * @since     1.2.0
 * @product   highcharts highstock gantt
 * @apioption series.line.data.id
 */
/**
 * The rank for this point's data label in case of collision. If two
 * data labels are about to overlap, only the one with the highest `labelrank`
 * will be drawn.
 *
 * @type      {number}
 * @apioption series.line.data.labelrank
 */
/**
 * The name of the point as shown in the legend, tooltip, dataLabels
 * etc.
 *
 * @see [xAxis.uniqueNames](#xAxis.uniqueNames)
 *
 * @sample {highcharts} highcharts/series/data-array-of-objects/
 *         Point names
 *
 * @type      {string}
 * @apioption series.line.data.name
 */
/**
 * Whether the data point is selected initially.
 *
 * @type      {boolean}
 * @default   false
 * @product   highcharts highstock gantt
 * @apioption series.line.data.selected
 */
/**
 * The x value of the point. For datetime axes, the X value is the timestamp
 * in milliseconds since 1970.
 *
 * @type      {number}
 * @product   highcharts highstock
 * @apioption series.line.data.x
 */
/**
 * The y value of the point.
 *
 * @type      {number|null}
 * @product   highcharts highstock
 * @apioption series.line.data.y
 */
/**
 * Individual point events
 *
 * @extends   plotOptions.series.point.events
 * @product   highcharts highstock gantt
 * @apioption series.line.data.events
 */
/**
 * @extends   plotOptions.series.marker
 * @product   highcharts highstock
 * @apioption series.line.data.marker
 */
''; // include precedent doclets in transpilat
