'use strict' ; import type AnimationOptions from '../Animation/AnimationOptions' ; import type Axis from '../Axis/Axis' ; import type AxisType from '../Axis/AxisType' ; import type BBoxObject from '../Renderer/BBoxObject' ; import type Chart from '../Chart/Chart' ; import type ColorType from '../Color/ColorType' ; import type DataExtremesObject from './DataExtremesObject' ; import type { EventCallback } from '../Callback' ; import type MapSeries from '../../Series/Map/MapSeries' ; import type PointerEvent from '../PointerEvent' ; import type { PointOptions , PointShortOptions , PointStateHoverOptions } from './PointOptions' ; import type RangeSelector from '../../Extensions/RangeSelector' ; import type SeriesLike from './SeriesLike' ; import type { SeriesDataSortingOptions , SeriesOptions , SeriesStateHoverOptions , SeriesZonesOptions } from './SeriesOptions' ; import type { SeriesTypeOptions , SeriesTypePlotOptions } from './SeriesType' ; import type { StatesOptionsKey } from './StatesOptions' ; import type SVGAttributes from '../Renderer/SVG/SVGAttributes' ; import type SVGPath from '../Renderer/SVG/SVGPath' ; import type { SymbolKey } from '../Renderer/SVG/SymbolType' ; import type TooltipOptions from '../TooltipOptions' ; import A from '../Animation/AnimationUtilities.js' ; const { animObject , setAnimation } = A ; import D from '../DefaultOptions.js' ; const { defaultOptions } = D ; import F from '../Foundation.js' ; const { registerEventOptions } = F ; import H from '../Globals.js' ; const { hasTouch , svg , win } = H ; import LegendSymbol from '../Legend/LegendSymbol.js' ; import { Palette } from '../Color/Palettes.js' ; import Point from './Point.js' ; import SeriesDefaults from './SeriesDefaults.js' ; import SeriesRegistry from './SeriesRegistry.js' ; const { seriesTypes } = SeriesRegistry ; import SVGElement from '../Renderer/SVG/SVGElement.js' ; import U from '../Utilities.js' ; const { addEvent , arrayMax , arrayMin , clamp , cleanRecursively , correctFloat , defined , erase , error , extend , find , fireEvent , getNestedProperty , isArray , isNumber , isString , merge , objectEach , pick , removeEvent , splat , syncTimeout } = U ; declare module '../Chart/ChartLike' { interface ChartLike { runTrackerClick ? : boolean ; } } declare module '../Renderer/SVG/SVGElementLike' { interface SVGElementLike { survive ? : boolean ; } } declare module './PointLike' { interface PointLike { plotX ? : number ; plotY ? : number ; } } declare module './SeriesLike' { interface SeriesLike { _hasPointMarkers ? : boolean ; invertible ? : boolean ; pointArrayMap ? : Array < string > ; pointValKey ? : string ; } } interface KDNode { [ side ] : ( KDNode | Point | undefined ) ; left ? : KDNode ; point : Point ; right ? : KDNode ; } interface KDPointSearchObject { clientX : number ; plotY ? : number ; } /**
 * 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
 *  Highcharts . Chart .
 *
 * 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
 *  Highcharts . Chart 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
 *  Highcharts . Chart .
 *
 * 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 param { Highcharts . Chart } chart param { Highcharts . SeriesOptionsType | object } options class Series { public static defaultOptions = SeriesDefaults ; public _hasTracking ? : boolean ; public _i : number = void 0 as any ; public animationTimeout ? : number ; public area ? : SVGElement ; public basePointRange ? : number ; public buildingKdTree ? : boolean ; public chart : Chart = void 0 as any ; public clips ? : Array < SVGElement > ; public closestPointRange ? : number ; public closestPointRangePx ? : number ; public color ? : ( ColorType ) ; public colorIndex ? : number ; public cropped ? : boolean ; public data : Array < Point > = void 0 as any ; public dataMax ? : number ; public dataMin ? : number ; public enabledDataSorting ? : boolean ; public fillColor ? : ColorType ; public finishedAnimating ? : boolean ; public getExtremesFromAll ? : boolean ; public graph ? : SVGElement ; public graphPath ? : SVGPath ; public group ? : SVGElement ; public eventOptions : Record < string , EventCallback < Series , Event > > = void 0 as any ; public eventsToUnbind : Array < Function > = void 0 as any ; public halo ? : SVGElement ; public hasCartesianSeries ? : Chart [ 'hasCartesianSeries' ] ; public hasRendered ? : boolean ; public id ? : string ; public index : number = void 0 as any ; public initialType ? : string ; public isDirty ? : boolean ; public isDirtyData ? : boolean ; public isRadialSeries ? : boolean ; public kdTree ? : KDNode ; public linkedParent ? : Series ; public linkedSeries : Array < Series > = void 0 as any ; public options : SeriesOptions = void 0 as any ; public markerGroup ? : SVGElement ; public opacity ? : number ; public optionalAxis ? : string ; public pointInterval ? : number ; public points : Array < Point > = void 0 as any ; public pointValKey ? : string ; public processedXData : Array < number > = void 0 as any ; public processedYData : ( Array < ( number | null ) > | Array < Array < ( number | null ) > > ) = void 0 as any ; public selected ? : boolean ; public sharedClipKey ? : string ; public stateMarkerGraphic ? : SVGElement ; public stickyTracking ? : boolean ; public symbol ? : SymbolKey ; public tooltipOptions : TooltipOptions = void 0 as any ; public tracker ? : SVGElement ; public trackerGroups ? : Array < string > ; public userOptions : DeepPartial < SeriesTypeOptions > = void 0 as any ; public xAxis : AxisType = void 0 as any ; public xData ? : Array < number > ; public xIncrement ? : ( number | null ) ; public yAxis : AxisType = void 0 as any ; public yData ? : ( Array < ( number | null ) > | Array < Array < ( number | null ) > > ) ; public zoneAxis ? : string ; public zones : Array < SeriesZonesOptions > = void 0 as any ; public init ( chart , userOptions ) { fireEvent ( this , 'init' , { options : userOptions } ) ; const series = this , chartSeries = chart . series ; this . eventsToUnbind = [ ] ; name 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
         *  Series .
         *
         *  name type { string } /**
         * Read only. The series' current options. To update, use
         *  Series .
         *
         *  name type { Highcharts . SeriesOptionsType } series . options = series . setOptions ( userOptions ) ; const options = series . options ; series . linkedSeries = [ ] ; series . bindAxes ( ) ; extend < Series > ( series , { name type { string } name : options . name , state : '' , /**
             * Read only. The series' visibility state as set by  {@link
             * Series#show} ,  Series , or in the initial
             * configuration.
             *
             *  name type { boolean } visible : options . visible !== false , /**
             * Read only. The series' selected state as set by  {@link
             * Highcharts.Series#select} .
             *
             *  name type { boolean } selected : options . selected === true } ) ; registerEventOptions ( this , options ) ; const events = options . events ; if ( ( events && events . click ) || ( options . point && options . point . events && options . point . events . click ) || options . allowPointSelect ) { chart . runTrackerClick = true ; } series . getColor ( ) ; series . getSymbol ( ) ; series . parallelArrays . forEach ( function ( key ) : void { if ( ! ( series as any ) [ key + 'Data' ] ) { ( series as any ) [ key + 'Data' ] = [ ] ; } } ) ; if ( series . isCartesian ) { chart . hasCartesianSeries = true ; } let lastSeries ; if ( chartSeries . length ) { lastSeries = chartSeries [ chartSeries . length - 1 ] ; } series . _i = pick ( lastSeries && lastSeries . _i , - 1 ) + 1 ; series . opacity = series . options . opacity ; chart . orderSeries ( this . insert ( chartSeries ) ) ; if ( options . dataSorting && options . dataSorting . enabled ) { series . setDataSortingOptions ( ) ; } else if ( ! series . points && ! series . data ) { series . setData ( options . data as any , false ) ; } fireEvent ( this , 'afterInit' ) ; } function param { string } type return { boolean } public is ( type ) { return seriesTypes [ type ] && this instanceof seriesTypes [ type ] ; } private function param { Array < Highcharts . Series > } collection return { number } public insert ( collection ) { const indexOption = this . options . index ; let i ; if ( isNumber ( indexOption ) ) { i = collection . length ; while ( i -- ) { if ( ( indexOption as any ) >= pick ( collection [ i ] . options . index , collection [ i ] . _i ) ) { collection . splice ( i + 1 , 0 , this ) ; break ; } } if ( i === - 1 ) { collection . unshift ( this ) ; } i = i + 1 ; } else { collection . push ( this ) ; } return pick ( i , collection . length - 1 ) ; } private function public bindAxes ( ) { const series = this , seriesOptions = series . options , chart = series . chart ; let axisOptions ; fireEvent ( this , 'bindAxes' , null as any , function ( ) : void { ( series . axisTypes || [ ] ) . forEach ( function ( AXIS ) : void { let index = 0 ; ( chart as any ) [ AXIS ] . forEach ( function ( axis ) : void { axisOptions = axis . options ; if ( ( ( seriesOptions as any ) [ AXIS ] === index && ! axisOptions . isInternal ) || ( typeof ( seriesOptions as any ) [ AXIS ] !== 'undefined' && ( seriesOptions as any ) [ AXIS ] === axisOptions . id ) || ( typeof ( seriesOptions as any ) [ AXIS ] === 'undefined' && axisOptions . index === 0 ) ) { series . insert ( axis . series ) ; name type { Highcharts . Axis } name type { Highcharts . Axis } ( series as any ) [ AXIS ] = axis ; axis . isDirty = true ; } if ( ! axisOptions . isInternal ) { index ++ ; } } ) ; if ( ! ( series as any ) [ AXIS ] && series . optionalAxis !== AXIS ) { error ( 18 , true , chart ) ; } } ) ; } ) ; fireEvent ( this , 'afterBindAxes' ) ; } private function public updateParallelArrays ( point , i ) { const series = point . series , args = arguments , fn = isNumber ( i ) ? function ( key ) : void { const val = key === 'y' && series . toYData ? series . toYData ( point ) : ( point as any ) [ key ] ; ( series as any ) [ key + 'Data' ] [ i ] = val ; } : function ( key ) : void { ( Array . prototype as any ) [ i ] . apply ( ( series as any ) [ key + 'Data' ] , Array . prototype . slice . call ( args , 2 ) ) ; } ; series . parallelArrays . forEach ( fn ) ; } private function public hasData ( ) { return ( ( this . visible && typeof this . dataMax !== 'undefined' && typeof this . dataMin !== 'undefined' ) || ( this . visible && ( this . yData as any ) && ( this . yData as any ) . length > 0 ) ) ; } private function public autoIncrement ( x ? ) { const options = this . options , pointIntervalUnit = options . pointIntervalUnit , relativeXValue = options . relativeXValue , time = this . chart . time ; let xIncrement = this . xIncrement , date , pointInterval ; xIncrement = pick ( xIncrement , options . pointStart , 0 ) ; this . pointInterval = pointInterval = pick ( this . pointInterval , options . pointInterval , 1 ) ; if ( relativeXValue && isNumber ( x ) ) { pointInterval *= x ; } 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 ; } if ( relativeXValue && isNumber ( x ) ) { return xIncrement + pointInterval ; } this . xIncrement = xIncrement + pointInterval ; return xIncrement ; } private function public setDataSortingOptions ( ) { const options = this . options ; extend < Series > ( this , { requireSorting : false , sorted : false , enabledDataSorting : true , allowDG : false } ) ; if ( ! defined ( options . pointRange ) ) { options . pointRange = 1 ; } } /**
     * 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  Series .
     *  private function param { Highcharts . SeriesOptionsType } itemOptions emits public setOptions ( itemOptions ) { const chart = this . chart , chartOptions = chart . options , plotOptions = chartOptions . plotOptions , userOptions = chart . userOptions || { } , seriesUserOptions = merge ( itemOptions ) , styledMode = chart . styledMode , e = { plotOptions : plotOptions , userOptions : seriesUserOptions } ; let zone ; fireEvent ( this , 'setOptions' , e ) ; const typeOptions = ( e . plotOptions as any ) [ this . type ] , userPlotOptions = ( userOptions . plotOptions || { } as SeriesTypePlotOptions ) ; name type { Highcharts . SeriesOptionsType } this . userOptions = e . userOptions ; const options = merge ( typeOptions , ( plotOptions as any ) . series , userOptions . plotOptions && ( userOptions . plotOptions as any ) [ this . type ] , seriesUserOptions ) ; this . tooltipOptions = merge ( defaultOptions . tooltip , ( defaultOptions . plotOptions as any ) . series && ( defaultOptions . plotOptions as any ) . series . tooltip , ( defaultOptions . plotOptions as any ) [ this . type ] . tooltip , ( chartOptions . tooltip as any ) . userOptions , ( plotOptions as any ) . series && ( plotOptions as any ) . series . tooltip , ( plotOptions as any ) [ this . type ] . tooltip , ( seriesUserOptions . tooltip as any ) ) as any ; this . stickyTracking = pick ( seriesUserOptions . stickyTracking , ( userPlotOptions as any ) [ this . type ] && ( userPlotOptions as any ) [ this . type ] . stickyTracking , userPlotOptions . series && userPlotOptions . series . stickyTracking , ( this . tooltipOptions . shared && ! this . noSharedTooltip ? true : options . stickyTracking ) ) ; if ( typeOptions . marker === null ) { delete options . marker ; } this . zoneAxis = options . zoneAxis ; const zones = this . zones = ( options . zones || [ ] ) . slice ( ) ; if ( ( options . negativeColor || options . negativeFillColor ) && ! options . zones ) { zone = { value : ( options as any ) [ this . zoneAxis + 'Threshold' ] || options . threshold || 0 , className : 'highcharts-negative' } as SeriesZonesOptions ; if ( ! styledMode ) { zone . color = options . negativeColor ; zone . fillColor = options . negativeFillColor ; } zones . push ( zone ) ; } if ( zones . length ) { if ( defined ( zones [ zones . length - 1 ] . value ) ) { zones . push ( styledMode ? { } : { color : this . color , fillColor : this . fillColor } ) ; } } fireEvent ( this , 'afterSetOptions' , { options : options } ) ; return options ; } function return { string } public getName ( ) { return pick ( this . options . name , 'Series ' + ( ( this . index as any ) + 1 ) ) ; } private function public getCyclic ( prop , value ? , defaults ? ) { const chart = this . chart , userOptions = this . userOptions , indexName = prop + 'Index' , counterName = prop + 'Counter' , len = defaults ? defaults . length : pick ( ( chart . options . chart as any ) [ prop + 'Count' ] , ( chart as any ) [ prop + 'Count' ] ) ; let i , setting ; if ( ! value ) { setting = pick ( ( userOptions as any ) [ indexName ] , ( userOptions as any ) [ '_' + indexName ] ) ; if ( defined ( setting ) ) { i = setting ; } else { if ( ! chart . series . length ) { ( chart as any ) [ counterName ] = 0 ; } ( userOptions as any ) [ '_' + indexName ] = i = ( chart as any ) [ counterName ] % len ; ( chart as any ) [ counterName ] += 1 ; } if ( defaults ) { value = defaults [ i ] ; } } if ( typeof i !== 'undefined' ) { ( this as any ) [ indexName ] = i ; } ( this as any ) [ prop ] = value ; } private function public getColor ( ) { if ( this . chart . styledMode ) { this . getCyclic ( 'color' ) ; } else if ( this . options . colorByPoint ) { this . color = Palette . neutralColor20 ; } else { this . getCyclic ( 'color' , this . options . color || ( defaultOptions . plotOptions as any ) [ this . type ] . color , this . chart . options . colors ) ; } } private function public getPointsCollection ( ) { return ( this . hasGroupedData ? this . points : this . data ) || [ ] ; } private function public getSymbol ( ) { const seriesMarkerOption = this . options . marker ; this . getCyclic ( 'symbol' , ( seriesMarkerOption as any ) . symbol , this . chart . options . symbols ) ; } private function param { Highcharts . PointOptionsObject } optionsObject param { number } fromIndex return { number | undefined } public findPointIndex ( optionsObject , fromIndex ) { const id = optionsObject . id , x = optionsObject . x , oldData = this . points , dataSorting = this . options . dataSorting ; let matchingPoint , matchedById , pointIndex ; if ( id ) { const item = this . chart . get ( id ) ; if ( item instanceof Point ) { matchingPoint = item ; } } else if ( this . linkedParent || this . enabledDataSorting || this . options . relativeXValue ) { let matcher = ( oldPoint ) : boolean => ! oldPoint . touched && oldPoint . index === optionsObject . index ; if ( dataSorting && dataSorting . matchByName ) { matcher = ( oldPoint ) : boolean => ! oldPoint . touched && oldPoint . name === optionsObject . name ; } else if ( this . options . relativeXValue ) { matcher = ( oldPoint ) : boolean => ! oldPoint . touched && oldPoint . options . x === optionsObject . x ; } matchingPoint = find ( oldData , matcher ) ; if ( ! matchingPoint ) { return void 0 ; } } if ( matchingPoint ) { pointIndex = matchingPoint && matchingPoint . index ; if ( typeof pointIndex !== 'undefined' ) { matchedById = true ; } } if ( typeof pointIndex === 'undefined' && isNumber ( x ) ) { pointIndex = ( this . xData as any ) . indexOf ( x as any , fromIndex ) ; } if ( pointIndex !== - 1 && typeof pointIndex !== 'undefined' && this . cropped ) { pointIndex = ( pointIndex >= ( this . cropStart as any ) ) ? pointIndex - ( this . cropStart as any ) : pointIndex ; } if ( ! matchedById && isNumber ( pointIndex ) && oldData [ pointIndex ] && oldData [ pointIndex ] . touched ) { pointIndex = void 0 ; } return pointIndex ; } private function public updateData ( data , animation ? ) { const options = this . options , dataSorting = options . dataSorting , oldData = this . points , pointsToAdd = [ ] as Array < ( PointOptions | PointShortOptions ) > , requireSorting = this . requireSorting , equalLength = data . length === oldData . length ; let hasUpdatedByKey , i , point , lastIndex , succeeded = true ; this . xIncrement = null ; data . forEach ( function ( pointOptions , i ) : void { const optionsObject = ( defined ( pointOptions ) && this . pointClass . prototype . optionsToObject . call ( { series : this } , pointOptions ) ) || { } ; let pointIndex ; const x = optionsObject . x , id = optionsObject . id ; if ( id || isNumber ( x ) ) { pointIndex = this . findPointIndex ( optionsObject , lastIndex ) ; if ( pointIndex === - 1 || typeof pointIndex === 'undefined' ) { pointsToAdd . push ( pointOptions ) ; } else if ( oldData [ pointIndex ] && pointOptions !== ( options . data as any ) [ pointIndex ] ) { oldData [ pointIndex ] . update ( pointOptions , false , null as any , false ) ; oldData [ pointIndex ] . touched = true ; if ( requireSorting ) { lastIndex = pointIndex + 1 ; } } else if ( oldData [ pointIndex ] ) { oldData [ pointIndex ] . touched = true ; } if ( ! equalLength || i !== pointIndex || ( dataSorting && dataSorting . enabled ) || this . hasDerivedData ) { hasUpdatedByKey = true ; } } else { pointsToAdd . push ( pointOptions ) ; } } , this ) ; if ( hasUpdatedByKey ) { i = oldData . length ; while ( i -- ) { point = oldData [ i ] ; if ( point && ! point . touched && point . remove ) { point . remove ( false , animation ) ; } } } else if ( equalLength && ( ! dataSorting || ! dataSorting . enabled ) ) { data . forEach ( function ( point , i ) : void { if ( point !== oldData [ i ] . y && oldData [ i ] . update ) { oldData [ i ] . update ( point , false , null as any , false ) ; } } ) ; pointsToAdd . length = 0 ; } else { succeeded = false ; } oldData . forEach ( function ( point ) : void { if ( point ) { point . touched = false ; } } ) ; if ( ! succeeded ) { return false ; } pointsToAdd . forEach ( function ( point ) : void { this . addPoint ( point , false , null as any , null as any , false ) ; } , this ) ; if ( this . xIncrement === null && this . xData && this . xData . length ) { this . xIncrement = arrayMax ( this . xData ) ; this . autoIncrement ( ) ; } return true ; } sample sample sample sample function param { Array < Highcharts . PointOptionsType > } data param { boolean } redraw 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  Chart after.
     *
     *  param { boolean | Partial < Highcharts . AnimationOptionsObject > } animation param { boolean } updatePoints public setData ( data , redraw ? , animation ? , updatePoints ? ) { const series = this , oldData = series . points , oldDataLength = ( oldData && oldData . length ) || 0 , options = series . options , chart = series . chart , dataSorting = options . dataSorting , xAxis = series . xAxis , turboThreshold = options . turboThreshold , xData = this . xData , yData = this . yData , pointArrayMap = series . pointArrayMap , valueCount = pointArrayMap && pointArrayMap . length , keys = options . keys ; let i , pt , updatedData , indexOfX = 0 , indexOfY = 1 , firstPoint = null ; data = data || [ ] ; const dataLength = data . length ; redraw = pick ( redraw , true ) ; if ( dataSorting && dataSorting . enabled ) { data = this . sortData ( data ) ; } if ( updatePoints !== false && dataLength && oldDataLength && ! series . cropped && ! series . hasGroupedData && series . visible && ! series . isSeriesBoosting ) { updatedData = this . updateData ( data , animation ) ; } if ( ! updatedData ) { series . xIncrement = null ; series . colorCounter = 0 ; this . parallelArrays . forEach ( function ( key ) : void { ( series as any ) [ key + 'Data' ] . length = 0 ; } ) ; if ( turboThreshold && dataLength > turboThreshold ) { firstPoint = series . getFirstValidPoint ( data ) ; if ( isNumber ( firstPoint ) ) { for ( i = 0 ; i < dataLength ; i ++ ) { ( xData as any ) [ i ] = this . autoIncrement ( ) ; ( yData as any ) [ i ] = data [ i ] ; } } else if ( isArray ( firstPoint ) ) { if ( valueCount ) { if ( firstPoint . length === valueCount ) { for ( i = 0 ; i < dataLength ; i ++ ) { ( xData as any ) [ i ] = this . autoIncrement ( ) ; ( yData as any ) [ i ] = data [ i ] ; } } else { for ( i = 0 ; i < dataLength ; i ++ ) { pt = data [ i ] ; ( xData as any ) [ i ] = ( pt as any ) [ 0 ] ; ( yData as any ) [ i ] = ( pt as any ) . slice ( 1 , valueCount + 1 ) ; } } } else { if ( keys ) { indexOfX = keys . indexOf ( 'x' ) ; indexOfY = keys . indexOf ( 'y' ) ; indexOfX = indexOfX >= 0 ? indexOfX : 0 ; indexOfY = indexOfY >= 0 ? indexOfY : 1 ; } if ( firstPoint . length === 1 ) { indexOfY = 0 ; } if ( indexOfX === indexOfY ) { for ( i = 0 ; i < dataLength ; i ++ ) { ( xData as any ) [ i ] = this . autoIncrement ( ) ; ( yData as any ) [ i ] = ( data [ i ] as any ) [ indexOfY ] ; } } else { for ( i = 0 ; i < dataLength ; i ++ ) { pt = data [ i ] ; ( xData as any ) [ i ] = ( pt as any ) [ indexOfX ] ; ( yData as any ) [ i ] = ( pt as any ) [ indexOfY ] ; } } } } else { error ( 12 , false , chart ) ; } } else { for ( i = 0 ; i < dataLength ; i ++ ) { if ( typeof data [ i ] !== 'undefined' ) { pt = { series : series } ; series . pointClass . prototype . applyOptions . apply ( pt , [ data [ i ] ] ) ; series . updateParallelArrays ( pt as any , i ) ; } } } if ( yData && isString ( yData [ 0 ] ) ) { error ( 14 , true , chart ) ; } series . data = [ ] ; series . options . data = series . userOptions . data = data ; i = oldDataLength ; while ( i -- ) { if ( oldData [ i ] && oldData [ i ] . destroy ) { oldData [ i ] . destroy ( ) ; } } if ( xAxis ) { xAxis . minRange = xAxis . userMinRange ; } series . isDirty = chart . isDirtyBox = true ; series . isDirtyData = ! ! oldData ; animation = false ; } if ( options . legendType === 'point' ) { this . processData ( ) ; this . generatePoints ( ) ; } if ( redraw ) { chart . redraw ( animation ) ; } } private function param { Array < Highcharts . PointOptionsType > } data public sortData ( data ) { const series = this , options = series . options , dataSorting = options . dataSorting as any , sortKey = dataSorting . sortKey || 'y' , getPointOptionsObject = function ( series , pointOptions ) : PointOptions { return ( defined ( pointOptions ) && series . pointClass . prototype . optionsToObject . call ( { series : series } , pointOptions ) ) || { } ; } ; data . forEach ( function ( pointOptions , i ) : void { data [ i ] = getPointOptionsObject ( series , pointOptions ) ; ( data [ i ] as any ) . index = i ; } , this ) ; const sortedData = data . concat ( ) . sort ( ( a , b ) : number => { const aValue = getNestedProperty ( sortKey , a ) as ( boolean | number | string ) ; const bValue = getNestedProperty ( sortKey , b ) as ( boolean | number | string ) ; return bValue < aValue ? - 1 : bValue > aValue ? 1 : 0 ; } ) as Array < Point > ; sortedData . forEach ( function ( point , i ) : void { point . x = i ; } , this ) ; if ( series . linkedSeries ) { series . linkedSeries . forEach ( function ( linkedSeries ) : void { const options = linkedSeries . options , seriesData = options . data as Array < PointOptions > ; if ( ( ! options . dataSorting || ! options . dataSorting . enabled ) && seriesData ) { seriesData . forEach ( function ( pointOptions , i ) : void { seriesData [ i ] = getPointOptionsObject ( linkedSeries , pointOptions ) ; if ( data [ i ] ) { seriesData [ i ] . x = ( data [ i ] as any ) . x ; seriesData [ i ] . index = i ; } } ) ; linkedSeries . setData ( seriesData , false ) ; } } ) ; } return data as any ; } private function param { boolean } forceExtremesFromAll public getProcessedData ( forceExtremesFromAll ? ) { const series = this , xAxis = series . xAxis , options = series . options , cropThreshold = options . cropThreshold , getExtremesFromAll = forceExtremesFromAll || series . getExtremesFromAll || options . getExtremesFromAll , isCartesian = series . isCartesian , val2lin = xAxis && xAxis . val2lin , isLog = ! ! ( xAxis && xAxis . logarithmic ) ; let croppedData , cropped , cropStart = 0 , distance , closestPointRange , i , xExtremes , min , max , processedXData = series . xData as any , processedYData = ( series . yData as any ) , throwOnUnsorted = series . requireSorting , updatingNames = false ; const dataLength = ( processedXData as any ) . length ; if ( xAxis ) { xExtremes = xAxis . getExtremes ( ) ; min = xExtremes . min ; max = xExtremes . max ; updatingNames = ! ! ( xAxis . categories && ! xAxis . names . length ) ; } if ( isCartesian && series . sorted && ! getExtremesFromAll && ( ! cropThreshold || dataLength > cropThreshold || series . forceCrop ) ) { if ( ( processedXData as any ) [ dataLength - 1 ] < ( min as any ) || ( processedXData as any ) [ 0 ] > ( max as any ) ) { processedXData = [ ] ; processedYData = [ ] ; } else if ( series . yData && ( ( processedXData as any ) [ 0 ] < ( min as any ) || ( processedXData as any ) [ dataLength - 1 ] > ( max as any ) ) ) { croppedData = this . cropData ( series . xData as any , series . yData as any , min as any , max as any ) ; processedXData = croppedData . xData ; processedYData = croppedData . yData ; cropStart = croppedData . start ; cropped = true ; } } i = ( processedXData as any ) . length || 1 ; while ( -- i ) { distance = ( isLog ? ( val2lin ( ( processedXData as any ) [ i ] ) - val2lin ( ( processedXData as any ) [ i - 1 ] ) ) : ( ( processedXData as any ) [ i ] - ( processedXData as any ) [ i - 1 ] ) ) ; if ( distance > 0 && ( typeof closestPointRange === 'undefined' || distance < closestPointRange ) ) { closestPointRange = distance ; } else if ( distance < 0 && throwOnUnsorted && ! updatingNames ) { error ( 15 , false , series . chart ) ; throwOnUnsorted = false ; } } return { xData : processedXData , yData : processedYData , cropped : cropped , cropStart : cropStart , closestPointRange : closestPointRange } ; } private function param { boolean } force public processData ( force ? ) { const series = this , xAxis = series . xAxis ; if ( series . isCartesian && ! series . isDirty && ! xAxis . isDirty && ! series . yAxis . isDirty && ! force ) { return false ; } const processedData = series . getProcessedData ( ) ; series . cropped = processedData . cropped ; series . cropStart = processedData . cropStart ; series . processedXData = processedData . xData ; series . processedYData = processedData . yData ; series . closestPointRange = ( series . basePointRange = processedData . closestPointRange ) ; fireEvent ( series , 'afterProcessData' ) ; } private function public cropData ( xData , yData , min , max , cropShoulder ? ) { const dataLength = xData . length ; let i , j , cropStart = 0 , cropEnd = dataLength ; cropShoulder = pick ( cropShoulder , this . cropShoulder ) ; for ( i = 0 ; i < dataLength ; i ++ ) { if ( xData [ i ] >= min ) { cropStart = Math . max ( 0 , i - ( cropShoulder as any ) ) ; break ; } } for ( j = i ; j < dataLength ; j ++ ) { if ( xData [ j ] > max ) { cropEnd = j + ( cropShoulder as any ) ; break ; } } return { xData : xData . slice ( cropStart , cropEnd ) , yData : yData . slice ( cropStart , cropEnd ) , start : cropStart , end : cropEnd } ; } private function public generatePoints ( ) { const series = this , options = series . options , dataOptions = ( ( series as unknown as MapSeries ) . processedData || options . data ) , processedXData = series . processedXData , processedYData = series . processedYData , PointClass = series . pointClass , processedDataLength = ( processedXData as any ) . length , cropStart = series . cropStart || 0 , hasGroupedData = series . hasGroupedData , keys = options . keys , points = [ ] , groupCropStartIndex = ( options . dataGrouping && options . dataGrouping . groupAll ? cropStart : 0 ) ; let dataLength , cursor , point , i , data = series . data ; if ( ! data && ! hasGroupedData ) { const arr = [ ] as Array < Point > ; arr . length = ( dataOptions as any ) . length ; data = series . data = arr ; } if ( keys && hasGroupedData ) { series . options . keys = false as any ; } for ( i = 0 ; i < processedDataLength ; i ++ ) { cursor = cropStart + i ; if ( ! hasGroupedData ) { point = data [ cursor ] ; if ( ! point && typeof ( dataOptions as any ) [ cursor ] !== 'undefined' ) { data [ cursor ] = point = ( new PointClass ( ) ) . init ( series , ( dataOptions as any ) [ cursor ] , ( processedXData as any ) [ i ] ) ; } } else { point = ( new PointClass ( ) ) . init ( series , [ ( processedXData as any ) [ i ] ] . concat ( splat ( ( processedYData as any ) [ i ] ) ) ) ; product name type { Highcharts . DataGroupingInfoObject | undefined } sample point . dataGroup = ( series . groupMap as any ) [ groupCropStartIndex + i ] ; if ( ( point . dataGroup as any ) . options ) { point . options = ( point . dataGroup as any ) . options ; extend ( point , ( point . dataGroup as any ) . options ) ; delete point . dataLabels ; } } if ( point ) { name type { number } readonly point . index = hasGroupedData ? ( groupCropStartIndex + i ) : cursor ; points [ i ] = point ; } } series . options . keys = keys ; if ( data && ( processedDataLength !== ( dataLength = data . length ) || hasGroupedData ) ) { for ( i = 0 ; i < dataLength ; i ++ ) { if ( i === cropStart && ! hasGroupedData ) { i += processedDataLength ; } if ( data [ i ] ) { data [ i ] . destroyElements ( ) ; data [ i ] . plotX = void 0 ; } } } /**
         * 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
         *  Highcharts . Series or
         *  Highcharts . Point .
         *
         *  see Series . points name 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  Highcharts . Series or
         *  Highcharts . Point .
         *
         *  name type { Array < Highcharts . Point > } series . points = points ; fireEvent ( this , 'afterGeneratePoints' ) ; } private function param { Array < number > } xData public getXExtremes ( xData ) { return { min : arrayMin ( xData ) , max : arrayMax ( xData ) } ; } private function param { Array < number > } yData param { boolean } forceExtremesFromAll public getExtremes ( yData ? , forceExtremesFromAll ? ) { const xAxis = this . xAxis , yAxis = this . yAxis , xData = this . processedXData || this . xData , activeYData = [ ] , shoulder = this . requireSorting ? this . cropShoulder : 0 , positiveValuesOnly = yAxis ? yAxis . positiveValuesOnly : false ; let xExtremes , validValue , withinRange , x , y , i , j , xMin = 0 , xMax = 0 , activeCounter = 0 ; yData = yData || this . stackedYData || this . processedYData || [ ] ; const yDataLength = yData . length ; if ( xAxis ) { xExtremes = xAxis . getExtremes ( ) ; xMin = xExtremes . min ; xMax = xExtremes . max ; } for ( i = 0 ; i < yDataLength ; i ++ ) { x = ( xData as any ) [ i ] ; y = yData [ i ] ; validValue = ( ( isNumber ( y ) || isArray ( y ) ) && ( ( ( y as any ) . length || y > 0 ) || ! positiveValuesOnly ) ) ; withinRange = ( forceExtremesFromAll || this . getExtremesFromAll || this . options . getExtremesFromAll || this . cropped || ! xAxis || ( ( ( xData as any ) [ i + shoulder ] || x ) >= xMin && ( ( xData as any ) [ i - shoulder ] || x ) <= xMax ) ) ; if ( validValue && withinRange ) { j = ( y as any ) . length ; if ( j ) { while ( j -- ) { if ( isNumber ( ( y as any ) [ j ] ) ) { activeYData [ activeCounter ++ ] = ( y as any ) [ j ] ; } } } else { activeYData [ activeCounter ++ ] = y ; } } } const dataExtremes = { activeYData , dataMin : arrayMin ( activeYData ) , dataMax : arrayMax ( activeYData ) } ; fireEvent ( this , 'afterGetExtremes' , { dataExtremes } ) ; return dataExtremes ; } private function public applyExtremes ( ) { const dataExtremes = this . getExtremes ( ) ; name type { number | undefined } readonly this . dataMin = dataExtremes . dataMin ; name type { number | undefined } readonly this . dataMax = dataExtremes . dataMax ; return dataExtremes ; } private function param { Array < Highcharts . PointOptionsType > } data public getFirstValidPoint ( data ) { const dataLength = data . length ; let i = 0 , firstPoint = null ; while ( firstPoint === null && i < dataLength ) { firstPoint = data [ i ] ; i ++ ; } return firstPoint ; } function emits public translate ( ) { if ( ! this . processedXData ) { this . processData ( ) ; } this . generatePoints ( ) ; const series = this , options = series . options , stacking = options . stacking , xAxis = series . xAxis , categories = xAxis . categories , enabledDataSorting = series . enabledDataSorting , yAxis = series . yAxis , points = series . points , dataLength = points . length , pointPlacement = series . pointPlacementToXValue ( ) , dynamicallyPlaced = Boolean ( pointPlacement ) , threshold = options . threshold , stackThreshold = options . startFromThreshold ? threshold : 0 , zoneAxis = this . zoneAxis || 'y' ; let i , plotX , lastPlotX , stackIndicator , closestPointRangePx = Number . MAX_VALUE ; private function limitedRange ( val ) { return clamp ( val , - 1e5 , 1e5 ) ; } for ( i = 0 ; i < dataLength ; i ++ ) { const point = points [ i ] , xValue = point . x ; let pointStack , stackValues , yValue = point . y , yBottom = point . low ; const stack = stacking && yAxis . stacking && yAxis . stacking . stacks [ ( series . negStacks && ( yValue as any ) < ( stackThreshold ? 0 : ( threshold as any ) ) ? '-' : '' ) + series . stackKey ] ; if ( yAxis . positiveValuesOnly && ! yAxis . validatePositiveValue ( yValue ) || xAxis . positiveValuesOnly && ! xAxis . validatePositiveValue ( xValue ) ) { point . isNull = true ; } name type { number | undefined } point . plotX = plotX = correctFloat ( limitedRange ( ( xAxis . translate as any ) ( xValue , 0 , 0 , 0 , 1 , pointPlacement , this . type === 'flags' ) ) ) ; if ( stacking && series . visible && stack && stack [ xValue as any ] ) { stackIndicator = series . getStackIndicator ( stackIndicator , xValue as any , series . index as any ) ; if ( ! point . isNull ) { pointStack = stack [ xValue as any ] ; stackValues = pointStack . points [ stackIndicator . key as any ] ; } } if ( isArray ( stackValues ) ) { yBottom = stackValues [ 0 ] ; yValue = stackValues [ 1 ] ; if ( yBottom === stackThreshold && ( stackIndicator as any ) . key === ( stack as any ) [ xValue as any ] . base ) { yBottom = pick < number | undefined , number > ( ( isNumber ( threshold ) && threshold ) as any , yAxis . min as any ) ; } if ( yAxis . positiveValuesOnly && yBottom <= 0 ) { yBottom = null as any ; } point . total = point . stackTotal = ( pointStack as any ) . total ; point . percentage = ( pointStack as any ) . total && ( ( point . y as any ) / ( pointStack as any ) . total * 100 ) ; point . stackY = yValue ; if ( ! ( series as any ) . irregularWidths ) { ( pointStack as any ) . setOffset ( series . pointXOffset || 0 , series . barW || 0 ) ; } } point . yBottom = defined ( yBottom ) ? limitedRange ( yAxis . translate ( ( yBottom as any ) , 0 as any , 1 as any , 0 as any , 1 as any ) as any ) : null as any ; if ( series . dataModify ) { yValue = series . dataModify . modifyValue ( yValue , i ) ; } point . plotY = void 0 ; if ( isNumber ( yValue ) ) { const translated = yAxis . translate ( yValue , false , true , false , true ) ; if ( typeof translated !== 'undefined' ) { name type { number | undefined } point . plotY = limitedRange ( translated ) ; } } point . isInside = this . isPointInside ( point ) ; point . clientX = dynamicallyPlaced ? correctFloat ( xAxis . translate ( xValue as any , 0 as any , 0 as any , 0 as any , 1 as any , pointPlacement ) as any ) : plotX ; point . negative = ( point as any ) [ zoneAxis ] < ( ( options as any ) [ zoneAxis + 'Threshold' ] || threshold || 0 ) ; point . category = pick ( categories && categories [ point . x ] , point . x as any ) ; if ( ! point . isNull && point . visible !== false ) { if ( typeof lastPlotX !== 'undefined' ) { closestPointRangePx = Math . min ( closestPointRangePx , Math . abs ( plotX - lastPlotX ) ) ; } lastPlotX = plotX ; } point . zone = this . zones . length ? point . getZone ( ) : void 0 ; if ( ! point . graphic && series . group && enabledDataSorting ) { point . isNew = true ; } } series . closestPointRangePx = closestPointRangePx ; fireEvent ( this , 'afterTranslate' ) ; } function param { Array < Highcharts . Point > } points The points to inspect, defaults to  Series . points .
     *
     *  param { boolean } insideOnly param { boolean } allowNull return { Array < Highcharts . Point > } public getValidPoints ( points ? , insideOnly ? , allowNull ? ) { const chart = this . chart ; return ( points || this . points || [ ] ) . filter ( function ( point ) : boolean { if ( insideOnly && ! chart . isInsidePlot ( point . plotX as any , point . plotY as any , { inverted : chart . inverted } ) ) { return false ; } return point . visible !== false && ( allowNull || ! point . isNull ) ; } ) ; } private function public getClipBox ( ) { const { chart , xAxis , yAxis } = this ; const seriesBox = merge ( chart . clipBox ) ; if ( xAxis && xAxis . len !== chart . plotSizeX ) { seriesBox . width = xAxis . len ; } if ( yAxis && yAxis . len !== chart . plotSizeY ) { seriesBox . height = yAxis . len ; } return seriesBox ; } private function public getSharedClipKey ( ) { this . sharedClipKey = ( this . options . xAxis || 0 ) + ',' + ( this . options . yAxis || 0 ) ; return this . sharedClipKey ; } private function public setClip ( ) { const { chart , group , markerGroup } = this , sharedClips = chart . sharedClips , renderer = chart . renderer , clipBox = this . getClipBox ( ) , sharedClipKey = this . getSharedClipKey ( ) ; let clipRect = sharedClips [ sharedClipKey ] ; if ( ! clipRect ) { sharedClips [ sharedClipKey ] = clipRect = renderer . clipRect ( clipBox ) ; } else { clipRect . animate ( clipBox ) ; } if ( group ) { group . clip ( this . options . clip === false ? void 0 : clipRect ) ; } if ( markerGroup ) { markerGroup . clip ( ) ; } } function param { boolean } init public animate ( init ? ) { const { chart , group , markerGroup } = this , inverted = chart . inverted , animation = animObject ( this . options . animation ) , animationClipKey = [ this . getSharedClipKey ( ) , animation . duration , animation . easing , animation . defer ] . join ( ',' ) ; let animationClipRect = chart . sharedClips [ animationClipKey ] , markerAnimationClipRect = chart . sharedClips [ animationClipKey + 'm' ] ; if ( init && group ) { const clipBox = this . getClipBox ( ) ; if ( ! animationClipRect ) { clipBox . width = 0 ; if ( inverted ) { clipBox . x = chart . plotHeight ; } animationClipRect = chart . renderer . clipRect ( clipBox ) ; chart . sharedClips [ animationClipKey ] = animationClipRect ; const markerClipBox = { x : inverted ? ( chart . plotSizeX || 0 ) + 99 : - 99 , y : inverted ? - chart . plotLeft : - chart . plotTop , width : 99 , height : inverted ? chart . chartWidth : chart . chartHeight } ; markerAnimationClipRect = chart . renderer . clipRect ( markerClipBox ) ; chart . sharedClips [ animationClipKey + 'm' ] = markerAnimationClipRect ; } else { animationClipRect . attr ( 'height' , clipBox . height ) ; } group . clip ( animationClipRect ) ; if ( markerGroup ) { markerGroup . clip ( markerAnimationClipRect ) ; } } else if ( animationClipRect && ! animationClipRect . hasClass ( 'highcharts-animating' ) ) { const finalBox = this . getClipBox ( ) , step = animation . step ; if ( markerGroup && markerGroup . element . childNodes . length ) { animation . step = function ( val , fx ) : void { if ( step ) { step . apply ( fx , arguments ) ; } if ( markerAnimationClipRect && markerAnimationClipRect . element ) { markerAnimationClipRect . attr ( fx . prop , fx . prop === 'width' ? val + 99 : val ) ; } } ; } animationClipRect . addClass ( 'highcharts-animating' ) . animate ( finalBox , animation ) ; } } private function emits public afterAnimate ( ) { this . setClip ( ) ; objectEach ( this . chart . sharedClips , ( clip , key , sharedClips ) : void => { if ( clip && ! this . chart . container . querySelector ( `[clip-path="url(#${ clip . id })"]` ) ) { clip . destroy ( ) ; delete sharedClips [ key ] ; } } ) ; this . finishedAnimating = true ; fireEvent ( this , 'afterAnimate' ) ; } /**
     * Draw the markers for line-like series types, and columns or other
     * graphical representation for  Point objects for other series
     * types. The resulting element is typically stored as
     *  Point . graphic , and is created on the first call and updated
     * and moved on subsequent calls.
     *
     *  function public drawPoints ( ) { const series = this , points = series . points , chart = series . chart , options = series . options , seriesMarkerOptions = options . marker , markerGroup = ( ( series as any ) [ series . specialGroup as any ] || series . markerGroup ) , xAxis = series . xAxis , globallyEnabled = pick ( ( seriesMarkerOptions as any ) . enabled , ! xAxis || xAxis . isRadial ? true : null , ( series . closestPointRangePx as any ) >= ( ( seriesMarkerOptions as any ) . enabledThreshold * ( seriesMarkerOptions as any ) . radius ) ) ; let i , point , graphic , verb , pointMarkerOptions , hasPointMarker , markerAttribs ; if ( ( seriesMarkerOptions as any ) . 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 ; const shouldDrawMarker = ( ( globallyEnabled && typeof pointMarkerOptions . enabled === 'undefined' ) || pointMarkerOptions . enabled ) && ! point . isNull && point . visible !== false ; if ( shouldDrawMarker ) { const symbol = pick ( pointMarkerOptions . symbol , series . symbol , 'rect' as SymbolKey ) ; markerAttribs = series . markerAttribs ( point , ( point . selected && 'select' ) as any ) ; if ( series . enabledDataSorting ) { point . startXPos = xAxis . reversed ? - ( markerAttribs . width || 0 ) : xAxis . width ; } const isInside = point . isInside !== false ; if ( graphic ) { graphic [ isInside ? 'show' : 'hide' ] ( isInside ) . animate ( markerAttribs ) ; } else if ( isInside && ( ( markerAttribs . width || 0 ) > 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  Series runs,
                         * and updated and moved on subsequent runs.
                         *
                         *  name type { SVGElement } point . graphic = graphic = chart . renderer . symbol ( symbol , markerAttribs . x , markerAttribs . y , markerAttribs . width , markerAttribs . height , hasPointMarker ? pointMarkerOptions : seriesMarkerOptions ) . add ( markerGroup ) ; if ( series . enabledDataSorting && chart . hasRendered ) { graphic . attr ( { x : point . startXPos } ) ; verb = 'animate' ; } } if ( graphic && verb === 'animate' ) { graphic [ isInside ? 'show' : 'hide' ] ( isInside ) . animate ( markerAttribs ) ; } if ( graphic && ! chart . styledMode ) { graphic [ verb ] ( series . pointAttribs ( point , ( point . selected && 'select' ) as any ) ) ; } if ( graphic ) { graphic . addClass ( point . getClassName ( ) , true ) ; } } else if ( graphic ) { point . graphic = graphic . destroy ( ) ; } } } } see Series function param { Highcharts . Point } point param { string } state return { Highcharts . SVGAttributes } public markerAttribs ( point , state ? ) { const seriesOptions = this . options , seriesMarkerOptions = seriesOptions . marker , pointMarkerOptions = point . marker || { } , symbol = ( pointMarkerOptions . symbol || ( seriesMarkerOptions as any ) . symbol ) ; let seriesStateOptions , pointStateOptions , radius = pick ( pointMarkerOptions . radius , ( seriesMarkerOptions as any ) . radius ) ; if ( state ) { seriesStateOptions = ( seriesMarkerOptions as any ) . states [ state ] ; pointStateOptions = pointMarkerOptions . states && ( pointMarkerOptions . states as any ) [ 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 ; } const attribs = { x : seriesOptions . crisp ? Math . floor ( point . plotX as any - radius ) : ( point . plotX as any ) - radius , y : ( point . plotY as any ) - radius } ; if ( radius ) { attribs . width = attribs . height = 2 * radius ; } return attribs ; } /**
     * Internal function to get presentational attributes for each point.
     * Unlike  Series , this function should return
     * those attributes that can also be set in CSS. In styled mode,
     * `pointAttribs` won't be called.
     *
     *  private function param { Highcharts . Point } point param { string } state return { Highcharts . SVGAttributes } public pointAttribs ( point ? , state ? ) { const seriesMarkerOptions = this . options . marker , pointOptions = point && point . options , pointMarkerOptions = ( ( pointOptions && pointOptions . marker ) || { } ) , pointColorOption = pointOptions && pointOptions . color , pointColor = point && point . color , zoneColor = point && point . zone && point . zone . color ; let seriesStateOptions , pointStateOptions , color = this . color , fill , stroke , strokeWidth = pick ( pointMarkerOptions . lineWidth , ( seriesMarkerOptions as any ) . lineWidth ) , opacity = 1 ; color = ( pointColorOption || zoneColor || pointColor || color ) ; fill = ( pointMarkerOptions . fillColor || ( seriesMarkerOptions as any ) . fillColor || color ) ; stroke = ( pointMarkerOptions . lineColor || ( seriesMarkerOptions as any ) . lineColor || color ) ; state = state || 'normal' ; if ( state ) { seriesStateOptions = ( ( seriesMarkerOptions as any ) . states [ state ] || { } ) ; pointStateOptions = ( pointMarkerOptions . states && ( pointMarkerOptions . states as any ) [ 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 } ; } private function emits public destroy ( keepEventsForUpdate ? ) { const series = this , chart = series . chart , issue134 = /AppleWebKit\/533/ . test ( win . navigator . userAgent ) , data = series . data || [ ] ; let destroy , i , point , axis ; fireEvent ( series , 'destroy' , { keepEventsForUpdate } ) ; this . removeEvents ( keepEventsForUpdate ) ; ( series . axisTypes || [ ] ) . forEach ( function ( AXIS ) : void { axis = ( series as any ) [ AXIS ] ; if ( axis && axis . series ) { erase ( axis . series , series ) ; axis . isDirty = axis . forceRedraw = true ; } } ) ; if ( series . legendItem ) { series . chart . legend . destroyItem ( series ) ; } i = data . length ; while ( i -- ) { point = data [ i ] ; if ( point && point . destroy ) { point . destroy ( ) ; } } if ( series . clips ) { series . clips . forEach ( ( clip ) : void => clip . destroy ( ) ) ; } U . clearTimeout ( series . animationTimeout as any ) ; objectEach ( series , function ( val , prop ) : void { if ( val instanceof SVGElement && ! val . survive ) { destroy = issue134 && prop === 'group' ? 'hide' : 'destroy' ; val [ destroy ] ( ) ; } } ) ; if ( chart . hoverSeries === series ) { chart . hoverSeries = void 0 ; } erase ( chart . series , series ) ; chart . orderSeries ( ) ; objectEach ( series , function ( val , prop ) : void { if ( ! keepEventsForUpdate || prop !== 'hcEvents' ) { delete ( series as any ) [ prop ] ; } } ) ; } private function public applyZones ( ) { const series = this , chart = this . chart , renderer = chart . renderer , zones = this . zones , clips = ( this . clips || [ ] ) as Array < SVGElement > , graph = this . graph , area = this . area , chartSizeMax = Math . max ( chart . chartWidth , chart . chartHeight ) , axis = ( this as any ) [ ( this . zoneAxis || 'y' ) + 'Axis' ] , inverted = chart . inverted ; let translatedFrom , translatedTo , clipAttr , extremes , reversed , horiz , pxRange , pxPosMin , pxPosMax , zoneArea , zoneGraph , ignoreZones = false ; if ( zones . length && ( graph || area ) && axis && typeof axis . min !== 'undefined' ) { reversed = axis . reversed ; horiz = axis . horiz ; if ( graph && ! this . showLine ) { graph . hide ( ) ; } if ( area ) { area . hide ( ) ; } extremes = axis . getExtremes ( ) ; zones . forEach ( function ( threshold , i ) : void { translatedFrom = reversed ? ( horiz ? chart . plotWidth : 0 ) : ( horiz ? 0 : ( axis . toPixels ( extremes . min ) || 0 ) ) ; translatedFrom = clamp ( pick ( translatedTo , translatedFrom ) , 0 , chartSizeMax ) ; translatedTo = clamp ( 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 ; } } 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 } ; } } if ( clips [ i ] ) { clips [ i ] . animate ( clipAttr ) ; } else { clips [ i ] = ( renderer . clipRect as any ) ( clipAttr ) ; } zoneArea = ( series as any ) [ 'zone-area-' + i ] ; zoneGraph = ( series as any ) [ 'zone-graph-' + i ] ; if ( graph && zoneGraph ) { zoneGraph . clip ( clips [ i ] ) ; } if ( area && zoneArea ) { zoneArea . clip ( clips [ i ] ) ; } ignoreZones = ( threshold . value as any ) > extremes . max ; if ( series . resetZones && translatedTo === 0 ) { translatedTo = void 0 ; } } ) ; this . clips = clips ; } else if ( series . visible ) { if ( graph ) { graph . show ( true ) ; } if ( area ) { area . show ( true ) ; } } } private function public invertGroups ( inverted ? ) { const series = this , chart = series . chart ; private function setInvert ( ) { [ 'group' , 'markerGroup' ] . forEach ( function ( groupName ) : void { if ( ( series as any ) [ groupName ] ) { if ( chart . renderer . isVML ) { ( series as any ) [ groupName ] . attr ( { width : series . yAxis . len , height : series . xAxis . len } ) ; } ( series as any ) [ groupName ] . width = series . yAxis . len ; ( series as any ) [ groupName ] . height = series . xAxis . len ; ( series as any ) [ groupName ] . invert ( series . isRadialSeries ? false : inverted ) ; } } ) ; } if ( ! series . xAxis ) { return ; } series . eventsToUnbind . push ( addEvent ( chart , 'resize' , setInvert ) ) ; ( setInvert as any ) ( ) ; series . invertGroups = setInvert ; } private function public plotGroup ( prop , name , visibility , zIndex ? , parent ? ) { let group = ( this as any ) [ prop ] ; const isNew = ! group , attrs = { visibility , zIndex : zIndex || 0.1 } ; if ( typeof this . opacity !== 'undefined' && ! this . chart . styledMode && this . state !== 'inactive' ) { attrs . opacity = this . opacity ; } if ( isNew ) { ( this as any ) [ prop ] = group = this . chart . renderer . g ( ) . add ( parent ) ; } 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 ) ; group . attr ( attrs ) [ isNew ? 'attr' : 'animate' ] ( this . getPlotBox ( ) ) ; return group ; } function public getPlotBox ( ) { const chart = this . chart ; let xAxis = this . xAxis , yAxis = this . yAxis ; 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 } ; } private function public removeEvents ( keepEventsForUpdate ? ) { const series = this ; if ( ! keepEventsForUpdate ) { removeEvent ( series ) ; } if ( series . eventsToUnbind . length ) { series . eventsToUnbind . forEach ( function ( unbind ) : void { unbind ( ) ; } ) ; series . eventsToUnbind . length = 0 ; } } function emits public render ( ) { const series = this , chart = series . chart , options = series . options , animOptions = animObject ( options . animation ) , visibility = series . visible ? 'inherit' : 'hidden' , zIndex = options . zIndex , hasRendered = series . hasRendered , chartSeriesGroup = chart . seriesGroup , inverted = chart . inverted ; let animDuration = ( ! series . finishedAnimating && chart . renderer . isSVG ) ? animOptions . duration : 0 ; fireEvent ( this , 'render' ) ; const group = series . plotGroup ( 'group' , 'series' , visibility , zIndex as any , chartSeriesGroup as any ) ; series . markerGroup = series . plotGroup ( 'markerGroup' , 'markers' , visibility , zIndex as any , chartSeriesGroup as any ) ; if ( options . clip !== false ) { series . setClip ( ) ; } if ( series . animate && animDuration ) { series . animate ( true ) ; } group . inverted = pick ( series . invertible , series . isCartesian ) ? inverted : false ; if ( ( series as any ) . drawGraph ) { ( series as any ) . drawGraph ( ) ; series . applyZones ( ) ; } if ( series . visible ) { series . drawPoints ( ) ; } if ( series . drawDataLabels ) { series . drawDataLabels ( ) ; } if ( series . redrawPoints ) { series . redrawPoints ( ) ; } if ( series . drawTracker && series . options . enableMouseTracking !== false ) { series . drawTracker ( ) ; } series . invertGroups ( inverted ) ; if ( series . animate && animDuration ) { series . animate ( ) ; } if ( ! hasRendered ) { if ( animDuration && animOptions . defer ) { animDuration += animOptions . defer ; } series . animationTimeout = syncTimeout ( function ( ) : void { series . afterAnimate ( ) ; } , animDuration || 0 ) ; } series . isDirty = false ; series . hasRendered = true ; fireEvent ( series , 'afterRender' ) ; } private function public redraw ( ) { const series = this , chart = series . chart , wasDirty = series . isDirty || series . isDirtyData , group = series . group , xAxis = series . xAxis , yAxis = series . yAxis ; 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 ) { delete this . kdTree ; } } sample function param { Highcharts . PointerEvent } e param { boolean } compareX return { Point | undefined } public searchPoint ( e , compareX ? ) { const series = this , xAxis = series . xAxis , yAxis = series . yAxis , inverted = series . chart . inverted ; return this . searchKDTree ( { clientX : inverted ? xAxis . len - e . chartY + ( xAxis . pos as any ) : e . chartX - ( xAxis . pos as any ) , plotY : inverted ? yAxis . len - e . chartX + ( yAxis . pos as any ) : e . chartY - ( yAxis . pos as any ) } , compareX , e ) ; } private function public buildKDTree ( e ? ) { this . buildingKdTree = true ; const series = this , dimensions = ( series . options . findNearestPointBy as any ) . indexOf ( 'y' ) > - 1 ? 2 : 1 ; private function _kdtree ( points , depth , dimensions ) { const length = points && points . length ; let axis , median ; if ( length ) { axis = series . kdAxisArray [ depth % dimensions ] ; points . sort ( function ( a , b ) : number { return ( a as any ) [ axis ] - ( b as any ) [ axis ] ; } ) ; median = Math . floor ( length / 2 ) ; return { point : points [ median ] , left : _kdtree ( points . slice ( 0 , median ) , depth + 1 , dimensions ) , right : _kdtree ( points . slice ( median + 1 ) , depth + 1 , dimensions ) } ; } } private function startRecursive ( ) { series . kdTree = _kdtree ( series . getValidPoints ( null as any , ! series . directTouch ) , dimensions , dimensions ) ; series . buildingKdTree = false ; } delete series . kdTree ; syncTimeout ( startRecursive , series . options . kdNow || ( e && e . type === 'touchstart' ) ? 0 : 1 ) ; } private function public searchKDTree ( point , compareX ? , e ? ) { const series = this , kdX = this . kdAxisArray [ 0 ] , kdY = this . kdAxisArray [ 1 ] , kdComparer = compareX ? 'distX' : 'dist' , kdDimensions = ( series . options . findNearestPointBy as any ) . indexOf ( 'y' ) > - 1 ? 2 : 1 ; private function setDistance ( p1 , p2 ) { const x = ( defined ( ( p1 as any ) [ kdX ] ) && defined ( ( p2 as any ) [ kdX ] ) ) ? Math . pow ( ( p1 as any ) [ kdX ] - ( p2 as any ) [ kdX ] , 2 ) : null , y = ( defined ( ( p1 as any ) [ kdY ] ) && defined ( ( p2 as any ) [ kdY ] ) ) ? Math . pow ( ( p1 as any ) [ kdY ] - ( p2 as any ) [ 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 as any ) : Number . MAX_VALUE ; } private function _search ( search , tree , depth , dimensions ) { const point = tree . point , axis = series . kdAxisArray [ depth % dimensions ] ; let nPoint1 , nPoint2 , ret = point ; setDistance ( search , point ) ; const tdist = ( search as any ) [ axis ] - ( point as any ) [ axis ] , sideA = tdist < 0 ? 'left' : 'right' , sideB = tdist < 0 ? 'right' : 'left' ; if ( tree [ sideA ] ) { nPoint1 = _search ( search , tree [ sideA ] as any , depth + 1 , dimensions ) ; ret = ( ( nPoint1 as any ) [ kdComparer ] < ( ret as any ) [ kdComparer ] ? nPoint1 : point ) ; } if ( tree [ sideB ] ) { if ( Math . sqrt ( tdist * tdist ) < ( ret as any ) [ kdComparer ] ) { nPoint2 = _search ( search , tree [ sideB ] as any , depth + 1 , dimensions ) ; ret = ( ( nPoint2 as any ) [ kdComparer ] < ( ret as any ) [ 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 public pointPlacementToXValue ( ) { const { options : { pointPlacement , pointRange } , xAxis : axis } = this ; let factor = pointPlacement ; if ( factor === 'between' ) { factor = axis . reversed ? - 0.5 : 0.5 ; } return isNumber ( factor ) ? factor * ( pointRange || axis . pointRange ) : 0 ; } private function public isPointInside ( point ) { const { chart , xAxis , yAxis } = this , isInside = ( typeof point . plotY !== 'undefined' && typeof point . plotX !== 'undefined' && point . plotY >= 0 && point . plotY <= ( yAxis ? yAxis . len : chart . plotHeight ) && point . plotX >= 0 && point . plotX <= ( xAxis ? xAxis . len : chart . plotWidth ) ) ; return isInside ; } private public drawTracker ( ) { const series = this , options = series . options , trackByArea = options . trackByArea , trackerPath = ( [ ] as SVGPath ) . concat ( trackByArea ? ( series . areaPath as any ) : ( series . graphPath as any ) ) , chart = series . chart , pointer = chart . pointer , renderer = chart . renderer , snap = ( chart . options . tooltip as any ) . snap , tracker = series . tracker , onMouseOver = function ( e ) : void { if ( chart . hoverSeries !== series ) { series . onMouseOver ( ) ; } } , TRACKER_FILL = 'rgba(192,192,192,' + ( svg ? 0.0001 : 0.002 ) + ')' ; let i ; if ( tracker ) { tracker . attr ( { d : trackerPath } ) ; } else if ( series . graph ) { series . tracker = renderer . path ( trackerPath ) . attr ( { visibility : series . visible ? 'visible' : 'hidden' , zIndex : 2 } ) . addClass ( trackByArea ? 'highcharts-tracker-area' : 'highcharts-tracker-line' ) . add ( series . group ) ; if ( ! chart . styledMode ) { ( series . tracker as any ) . attr ( { 'stroke-linecap' : 'round' , 'stroke-linejoin' : 'round' , stroke : TRACKER_FILL , fill : trackByArea ? TRACKER_FILL : 'none' , 'stroke-width' : series . graph . strokeWidth ( ) + ( trackByArea ? 0 : 2 * snap ) } ) ; } [ series . tracker , series . markerGroup , series . dataLabelsGroup ] . forEach ( function ( tracker ? ) : void { if ( tracker ) { tracker . addClass ( 'highcharts-tracker' ) . on ( 'mouseover' , onMouseOver ) . on ( 'mouseout' , function ( e ) : void { pointer . onTrackerMouseOut ( e ) ; } ) ; if ( options . cursor && ! chart . styledMode ) { tracker . css ( { cursor : options . cursor } ) ; } if ( hasTouch ) { tracker . on ( 'touchstart' , onMouseOver ) ; } } } ) ; } fireEvent ( this , 'afterDrawTracker' ) ; } sample sample sample sample sample sample sample function param { Highcharts . PointOptionsType } options param { boolean } redraw Whether to redraw the chart after the point is added. When adding
     *        more than one point, it is highly recommended that the redraw
     *        option be set to false, and instead  Chart is
     *        explicitly called after the adding of points is finished.
     *        Otherwise, the chart will redraw after adding each point.
     *
     *  param { boolean } shift param { boolean | Partial < Highcharts . AnimationOptionsObject > } animation param { boolean } withEvent emits public addPoint ( options , redraw ? , shift ? , animation ? , withEvent ? ) { const series = this , seriesOptions = series . options , data = series . data , chart = series . chart , xAxis = series . xAxis , names = xAxis && xAxis . hasNames && xAxis . names , dataOptions = seriesOptions . data , xData = series . xData as any ; let isInTheMiddle , i ; redraw = pick ( redraw , true ) ; const point = { series : series } as any ; series . pointClass . prototype . applyOptions . apply ( point , [ options ] ) ; const x = point . x ; i = xData . length ; if ( series . requireSorting && ( x as any ) < xData [ i - 1 ] ) { isInTheMiddle = true ; while ( i && xData [ i - 1 ] > ( x as any ) ) { i -- ; } } ( series . updateParallelArrays as any ) ( point , 'splice' , i , 0 , 0 ) ; series . updateParallelArrays ( point as any , i ) ; if ( names && point . name ) { names [ x as any ] = point . name ; } ( dataOptions as any ) . splice ( i , 0 , options ) ; if ( isInTheMiddle || ( series as unknown as MapSeries ) . processedData ) { series . data . splice ( i , 0 , null as any ) ; series . processData ( ) ; } if ( seriesOptions . legendType === 'point' ) { series . generatePoints ( ) ; } if ( shift ) { if ( data [ 0 ] && data [ 0 ] . remove ) { data [ 0 ] . remove ( false ) ; } else { data . shift ( ) ; series . updateParallelArrays ( point as any , 'shift' ) ; ( dataOptions as any ) . shift ( ) ; } } if ( withEvent !== false ) { fireEvent ( series , 'addPoint' , { point : point } ) ; } series . isDirty = true ; series . isDirtyData = true ; if ( redraw ) { chart . redraw ( animation ) ; } } /**
     * Remove a point from the series. Unlike the
     *  Highcharts . Point method, this can also be done on a point
     * that is not instanciated because it is outside the view or subject to
     * Highcharts Stock data grouping.
     *
     *  sample function param { number } i The index of the point in the  Highcharts . Series . data *        array.
     *
     *  param { boolean } redraw Whether to redraw the chart after the point is added. When
     *        removing more than one point, it is highly recommended that the
     *        `redraw` option be set to `false`, and instead  {@link
     *        Highcharts.Chart#redraw} is explicitly called after the adding of
     *        points is finished.
     *
     *  param { boolean | Partial < Highcharts . AnimationOptionsObject > } animation emits public removePoint ( i , redraw ? , animation ? ) { const series = this , data = series . data , point = data [ i ] , points = series . points , chart = series . chart , remove = function ( ) : void { if ( points && points . length === data . length ) { points . splice ( i , 1 ) ; } data . splice ( i , 1 ) ; ( series . options . data as any ) . splice ( i , 1 ) ; ( series . updateParallelArrays as any ) ( point || { series : series } , 'splice' , i , 1 ) ; if ( point ) { point . destroy ( ) ; } series . isDirty = true ; series . isDirtyData = true ; if ( redraw ) { chart . redraw ( ) ; } } ; setAnimation ( animation , chart ) ; redraw = pick ( redraw , true ) ; if ( point ) { point . firePointEvent ( 'remove' , null as any , remove ) ; } else { remove ( ) ; } } sample function param { boolean } redraw Whether to redraw the chart or wait for an explicit call to
     *         Highcharts . Chart .
     *
     *  param { boolean | Partial < Highcharts . AnimationOptionsObject > } animation param { boolean } withEvent emits public remove ( redraw ? , animation ? , withEvent ? , keepEvents ? ) { const series = this , chart = series . chart ; private function remove ( ) { series . destroy ( keepEvents ) ; chart . isDirtyLegend = chart . isDirtyBox = true ; chart . linkSeries ( ) ; if ( pick ( redraw , true ) ) { chart . redraw ( animation ) ; } } if ( withEvent !== false ) { fireEvent ( series , 'remove' , null as any , remove ) ; } else { remove ( ) ; } } /**
     * Update the series with a new set of options. For a clean and precise
     * handling of new options, all methods and elements from the series are
     * removed, and it is initialized from scratch. Therefore, this method is
     * more performance expensive than some other utility methods like  {@link
     * Series#setData} or  Series .
     *
     * Note that `Series.update` may mutate the passed `data` options.
     *
     *  sample sample function param { Highcharts . SeriesOptionsType } options param { boolean } redraw 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  Chart after.
     *
     *  emits emits public update ( options , redraw ? ) { options = cleanRecursively ( options , this . userOptions ) ; fireEvent ( this , 'update' , { options : options } ) ; const series = this , chart = series . chart , oldOptions = series . userOptions , initialType = series . initialType || series . type , plotOptions = chart . options . plotOptions , initialSeriesProto = seriesTypes [ initialType ] . prototype , groups = [ 'group' , 'markerGroup' , 'dataLabelsGroup' , 'transformGroup' ] , animation = series . finishedAnimating && { animation : false } , kinds = { } as Record < string , number > ; let seriesOptions , n , preserve = [ 'eventOptions' , 'navigatorSeries' , 'baseSeries' ] , newType = ( options . type || oldOptions . type || chart . options . chart . type ) ; const keepPoints = ! ( this . hasDerivedData || ( newType && newType !== this . type ) || typeof options . pointStart !== 'undefined' || typeof options . pointInterval !== 'undefined' || typeof options . relativeXValue !== 'undefined' || options . joinBy || options . mapData || series . hasOptionChanged ( 'dataGrouping' ) || series . hasOptionChanged ( 'pointStart' ) || series . hasOptionChanged ( 'pointInterval' ) || series . hasOptionChanged ( 'pointIntervalUnit' ) || series . hasOptionChanged ( 'keys' ) ) ; newType = newType || initialType ; if ( keepPoints ) { preserve . push ( 'data' , 'isDirtyData' , 'points' , 'processedXData' , 'processedYData' , 'xIncrement' , 'cropped' , '_hasPointMarkers' , '_hasPointLabels' , 'clips' , 'nodes' , 'layout' , 'level' , 'mapMap' , 'mapData' , 'minY' , 'maxY' , 'minX' , 'maxX' ) ; if ( options . visible !== false ) { preserve . push ( 'area' , 'graph' ) ; } series . parallelArrays . forEach ( function ( key ) : void { preserve . push ( key + 'Data' ) ; } ) ; if ( options . data ) { if ( options . dataSorting ) { extend ( series . options . dataSorting , options . dataSorting ) ; } this . setData ( options . data as any , false ) ; } } options = merge ( oldOptions , animation as any , { index : typeof oldOptions . index === 'undefined' ? series . index : oldOptions . index , pointStart : pick ( ( plotOptions && plotOptions . series && plotOptions . series . pointStart ) , oldOptions . pointStart , ( series . xData as any ) [ 0 ] ) } , ( ! keepPoints && { data : series . options . data } ) as any , options ) ; if ( keepPoints && options . data ) { options . data = series . options . data ; } preserve = groups . concat ( preserve ) ; preserve . forEach ( function ( prop ) : void { ( preserve as any ) [ prop ] = ( series as any ) [ prop ] ; delete ( series as any ) [ prop ] ; } ) ; let casting = false ; if ( seriesTypes [ newType ] ) { casting = newType !== series . type ; series . remove ( false , false , false , true ) ; if ( casting ) { if ( Object . setPrototypeOf ) { Object . setPrototypeOf ( series , seriesTypes [ newType ] . prototype ) ; } else { const ownEvents = Object . hasOwnProperty . call ( series , 'hcEvents' ) && series . hcEvents ; for ( n in initialSeriesProto ) { ( series as any ) [ n ] = void 0 ; } extend < Series > ( series , seriesTypes [ newType ] . prototype ) ; if ( ownEvents ) { series . hcEvents = ownEvents ; } else { delete series . hcEvents ; } } } } else { error ( 17 , true , chart , { missingModuleFor : newType } ) ; } preserve . forEach ( function ( prop ) : void { ( series as any ) [ prop ] = ( preserve as any ) [ prop ] ; } ) ; series . init ( chart , options ) ; if ( keepPoints && this . points ) { seriesOptions = series . options ; if ( seriesOptions . visible === false ) { kinds . graphic = 1 ; kinds . dataLabel = 1 ; } else if ( ! series . _hasPointLabels ) { const { marker , dataLabels } = seriesOptions ; if ( marker && ( marker . enabled === false || ( oldOptions . marker && oldOptions . marker . symbol ) !== marker . symbol ) ) { kinds . graphic = 1 ; } if ( dataLabels && ( dataLabels as any ) . enabled === false ) { kinds . dataLabel = 1 ; } } this . points . forEach ( function ( point ) : void { if ( point && point . series ) { point . resolveColor ( ) ; if ( Object . keys ( kinds ) . length ) { point . destroyElements ( kinds ) ; } if ( seriesOptions . showInLegend === false && point . legendItem ) { chart . legend . destroyItem ( point ) ; } } } , this ) ; } series . initialType = initialType ; chart . linkSeries ( ) ; if ( casting && series . linkedSeries . length ) { series . isDirtyData = true ; } fireEvent ( this , 'afterUpdate' ) ; if ( pick ( redraw , true ) ) { chart . redraw ( keepPoints ? void 0 : false ) ; } } private public setName ( name ) { this . name = this . options . name = this . userOptions . name = name ; this . chart . isDirtyLegend = true ; } private public hasOptionChanged ( optionName ) { const chart = this . chart , option = ( this . options as any ) [ optionName ] , plotOptions = chart . options . plotOptions , oldOption = ( this . userOptions as any ) [ optionName ] ; if ( oldOption ) { return option !== oldOption ; } return option !== pick ( plotOptions && plotOptions [ this . type ] && ( plotOptions [ this . type ] as any ) [ optionName ] , plotOptions && plotOptions . series && ( plotOptions as any ) . series [ optionName ] , option ) ; } function emits public onMouseOver ( ) { const series = this , chart = series . chart , hoverSeries = chart . hoverSeries , pointer = chart . pointer ; pointer . setHoverChartIndex ( ) ; if ( hoverSeries && hoverSeries !== series ) { hoverSeries . onMouseOut ( ) ; } if ( ( series . options . events as any ) . mouseOver ) { fireEvent ( series , 'mouseOver' ) ; } series . setState ( 'hover' ) ; name type { Highcharts . Series | null } chart . hoverSeries = series ; } function emits public onMouseOut ( ) { const series = this , options = series . options , chart = series . chart , tooltip = chart . tooltip , hoverPoint = chart . hoverPoint ; chart . hoverSeries = null as any ; if ( hoverPoint ) { hoverPoint . onMouseOut ( ) ; } if ( series && ( options . events as any ) . mouseOut ) { fireEvent ( series , 'mouseOut' ) ; } if ( tooltip && ! series . stickyTracking && ( ! tooltip . shared || series . noSharedTooltip ) ) { tooltip . hide ( ) ; } chart . series . forEach ( function ( s ) : void { s . setState ( '' , true ) ; } ) ; } function param { Highcharts . SeriesStateValue | "" } state param { boolean } inherit public setState ( state ? , inherit ? ) { const series = this , options = series . options , graph = series . graph , inactiveOtherPoints = options . inactiveOtherPoints , stateOptions = options . states , stateAnimation = pick ( ( ( stateOptions as any ) [ state || 'normal' ] && ( stateOptions as any ) [ state || 'normal' ] . animation ) , series . chart . options . chart . animation ) ; let attribs , lineWidth = options . lineWidth , i = 0 , opacity = options . opacity ; state = state || '' ; if ( series . state !== state ) { [ series . group , series . markerGroup , series . dataLabelsGroup ] . forEach ( function ( group ) : void { if ( group ) { if ( series . state ) { group . removeClass ( 'highcharts-series-' + series . state ) ; } if ( state ) { group . addClass ( 'highcharts-series-' + state ) ; } } } ) ; series . state = state ; if ( ! series . chart . styledMode ) { if ( ( stateOptions as any ) [ state ] && ( stateOptions as any ) [ state ] . enabled === false ) { return ; } if ( state ) { lineWidth = ( ( stateOptions as any ) [ state ] . lineWidth || lineWidth + ( ( stateOptions as any ) [ state ] . lineWidthPlus || 0 ) ) ; opacity = pick ( ( stateOptions as any ) [ state ] . opacity , opacity ) ; } if ( graph && ! graph . dashstyle ) { attribs = { 'stroke-width' : lineWidth } ; graph . animate ( attribs , stateAnimation ) ; while ( ( series as any ) [ 'zone-graph-' + i ] ) { ( series as any ) [ 'zone-graph-' + i ] . animate ( attribs , stateAnimation ) ; i = i + 1 ; } } if ( ! inactiveOtherPoints ) { [ series . group , series . markerGroup , series . dataLabelsGroup , series . labelBySeries ] . forEach ( function ( group ) : void { if ( group ) { group . animate ( { opacity : opacity } , stateAnimation ) ; } } ) ; } } } if ( inherit && inactiveOtherPoints && series . points ) { series . setAllPointsToState ( state || void 0 ) ; } } function private param { string } state public setAllPointsToState ( state ? ) { this . points . forEach ( function ( point ) : void { if ( point . setState ) { point . setState ( state ) ; } } ) ; } function param { boolean } visible param { boolean } redraw 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  Chart after.
     *
     *  emits emits public setVisible ( vis ? , redraw ? ) { const series = this , chart = series . chart , legendItem = series . legendItem , ignoreHiddenSeries = chart . options . chart . ignoreHiddenSeries , oldVisibility = series . visible ; series . visible = vis = series . options . visible = series . userOptions . visible = typeof vis === 'undefined' ? ! oldVisibility : vis ; const showOrHide = vis ? 'show' : 'hide' ; [ 'group' , 'dataLabelsGroup' , 'markerGroup' , 'tracker' , 'tt' ] . forEach ( function ( key ) : void { if ( ( series as any ) [ key ] ) { ( series as any ) [ key ] [ showOrHide ] ( ) ; } } ) ; if ( chart . hoverSeries === series || ( chart . hoverPoint && chart . hoverPoint . series ) === series ) { series . onMouseOut ( ) ; } if ( legendItem ) { chart . legend . colorizeItem ( series , vis ) ; } series . isDirty = true ; if ( series . options . stacking ) { chart . series . forEach ( function ( otherSeries ) : void { if ( otherSeries . options . stacking && otherSeries . visible ) { otherSeries . isDirty = true ; } } ) ; } series . linkedSeries . forEach ( function ( otherSeries ) : void { otherSeries . setVisible ( vis , false ) ; } ) ; if ( ignoreHiddenSeries ) { chart . isDirtyBox = true ; } fireEvent ( series , showOrHide ) ; if ( redraw !== false ) { chart . redraw ( ) ; } } sample function emits public show ( ) { this . setVisible ( true ) ; } sample function emits public hide ( ) { this . setVisible ( false ) ; } /**
     * Select or unselect the series. This means its
     *  Highcharts . Series . selected * property is set, the checkbox in the legend is toggled and when selected,
     * the series is returned by the  Highcharts . Chart * function.
     *
     *  sample function param { boolean } selected emits emits public select ( selected ? ) { const series = this ; series . selected = selected = this . options . selected = ( typeof selected === 'undefined' ? ! series . selected : selected ) ; if ( series . checkbox ) { series . checkbox . checked = selected ; } fireEvent ( series , selected ? 'select' : 'unselect' ) ; } private public shouldShowTooltip ( plotX , plotY , options = { } ) { options . series = this ; options . visiblePlotOnly = true ; return this . chart . isInsidePlot ( plotX , plotY , options ) ; } } interface Series extends SeriesLike { axisTypes : Array < string > ; coll : 'series' ; colorCounter : number ; cropShoulder : number ; directTouch : boolean ; hcEvents ? : Record < string , Array < U . EventWrapperObject < Series > > > ; isCartesian : boolean ; kdAxisArray : Array < string > ; parallelArrays : Array < string > ; pointClass : typeof Point ; requireSorting : boolean ; sorted : boolean ; } extend ( Series . prototype , { axisTypes : [ 'xAxis' , 'yAxis' ] , coll : 'series' , colorCounter : 0 , cropShoulder : 1 , directTouch : false , drawLegendSymbol : LegendSymbol . drawLineMarker , isCartesian : true , kdAxisArray : [ 'clientX' , 'plotY' ] , parallelArrays : [ 'x' , 'y' ] , pointClass : Point , requireSorting : true , sorted : true } ) ; namespace Series { export interface CropDataObject { end : number ; start : number ; xData : Array < number > ; yData : ( Array < ( number | null ) > | Array < Array < ( number | null ) > > ) ; } export interface PlotBoxObject { scaleX : number ; scaleY : number ; translateX : number ; translateY : number ; } export interface ProcessedDataObject { xData : Array < number > ; yData : ( Array < ( number | null ) > | Array < Array < ( number | null ) > > ) ; cropped : ( boolean | undefined ) ; cropStart : number ; closestPointRange : ( number | undefined ) ; } } SeriesRegistry . series = Series ; export default Series ; ignore-declaration typedef { Highcharts . SeriesOptions | Highcharts . Dictionary < * > } Highcharts . SeriesOptionsType interface since name type { boolean | undefined } name type { boolean | undefined } name type { string | undefined } callback Highcharts . SeriesAfterAnimateCallbackFunction param { Highcharts . Series } this param { Highcharts . SeriesAfterAnimateEventObject } event interface name type { Highcharts . Series } name type { "afterAnimate" } callback Highcharts . SeriesCheckboxClickCallbackFunction param { Highcharts . Series } this param { Highcharts . SeriesCheckboxClickEventObject } event interface name type { boolean } name type { Highcharts . Series } name type { Highcharts . Series } name type { "checkboxClick" } callback Highcharts . SeriesClickCallbackFunction param { Highcharts . Series } this param { Highcharts . SeriesClickEventObject } event interface extends global . Event name type { Highcharts . Point } callback Highcharts . SeriesHideCallbackFunction param { Highcharts . Series } this param { global . Event } event typedef { "butt" | "round" | "square" | string } Highcharts . SeriesLinecapValue callback Highcharts . SeriesLegendItemClickCallbackFunction param { Highcharts . Series } this param { Highcharts . SeriesLegendItemClickEventObject } event interface name type { global . PointerEvent } name type { Function } name type { Highcharts . Series } name type { "checkboxClick" } callback Highcharts . SeriesMouseOutCallbackFunction param { Highcharts . Series } this param { global . PointerEvent } event callback Highcharts . SeriesMouseOverCallbackFunction param { Highcharts . Series } this param { global . PointerEvent } event interface name type { number } name type { number } name type { number } name type { number } callback Highcharts . SeriesShowCallbackFunction param { Highcharts . Series } this param { global . Event } event typedef { "hover" | "inactive" | "normal" | "select" } Highcharts . SeriesStateValue '' ; example type { Array < * > } apioption sample type { string } since apioption type { number } since apioption see sample type { number } apioption sample sample type { string } apioption sample type { number | string } since product apioption sample sample sample type { string } apioption /**
 * 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 product apioption /**
 * 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 type { number | string } default product apioption sample sample sample sample type { number } product apioption '' ;