'use strict' ; import type BBoxObject from '../../Core/Renderer/BBoxObject' ; import type Chart from '../../Core/Chart/Chart' ; import type ColumnMetricsObject from './ColumnMetricsObject' ; import type ColumnPoint from './ColumnPoint' ; import type ColumnSeriesOptions from './ColumnSeriesOptions' ; import type DashStyleValue from '../../Core/Renderer/DashStyleValue' ; import type PointerEvent from '../../Core/PointerEvent' ; import type { SeriesStateHoverOptions } from '../../Core/Series/SeriesOptions' ; import type { StatesOptionsKey } from '../../Core/Series/StatesOptions' ; import type SVGAttributes from '../../Core/Renderer/SVG/SVGAttributes' ; import type SVGElement from '../../Core/Renderer/SVG/SVGElement' ; import A from '../../Core/Animation/AnimationUtilities.js' ; const { animObject } = A ; import Color from '../../Core/Color/Color.js' ; const { parse : color } = Color ; import H from '../../Core/Globals.js' ; const { hasTouch , noop } = H ; import LegendSymbol from '../../Core/Legend/LegendSymbol.js' ; import { Palette } from '../../Core/Color/Palettes.js' ; import Series from '../../Core/Series/Series.js' ; import SeriesRegistry from '../../Core/Series/SeriesRegistry.js' ; import U from '../../Core/Utilities.js' ; const { clamp , css , defined , extend , fireEvent , isArray , isNumber , merge , pick , objectEach } = U ; declare module '../../Core/Series/SeriesLike' { interface SeriesLike { barW ? : number ; pointXOffset ? : number ; } } private class name augments Highcharts . Series class ColumnSeries extends Series { sample sample extends plotOptions . line excluding product optionparent public static defaultOptions : ColumnSeriesOptions = merge ( Series . defaultOptions , { sample product private borderRadius : 0 , see sample sample type { boolean } default since product apioption type { Array < Highcharts . ColorString | Highcharts . GradientColorObject | Highcharts . PatternObject > } since product apioption sample since product private centerInCategory : false , sample sample product private groupPadding : 0.2 , sample sample type { boolean } default since product apioption ignore-option private marker : null as any , see sample sample type { number } since product apioption sample sample sample product private pointPadding : 0.1 , see sample type { number } since product apioption see type { number } default since product apioption sample sample product private minPointLength : 0 , product private cropThreshold : 50 , sample type { number | null } since product private pointRange : null , states : { extends plotOptions . series . states . hover excluding product hover : { ignore-option halo : false , type { Highcharts . ColorString | Highcharts . GradientColorObject | Highcharts . PatternObject } product apioption type { Highcharts . ColorString | Highcharts . GradientColorObject | Highcharts . PatternObject } product apioption sample product brightness : 0.1 } , extends plotOptions . series . states . select excluding product select : { type { Highcharts . ColorString | Highcharts . GradientColorObject | Highcharts . PatternObject } default product color : Palette . neutralColor20 , type { Highcharts . ColorString | Highcharts . GradientColorObject | Highcharts . PatternObject } default product borderColor : Palette . neutralColor100 } } , dataLabels : { align : void 0 , verticalAlign : void 0 , type { number } y : void 0 } , ignore-option private startFromThreshold : true , stickyTracking : false , tooltip : { distance : 6 } , type { number | null } since product private threshold : 0 , sample type { number } default product apioption sample type { Highcharts . ColorString | Highcharts . GradientColorObject | Highcharts . PatternObject } default product private borderColor : Palette . backgroundColor } ) ; public borderWidth : number = void 0 as any ; public columnIndex ? : number ; public columnMetrics ? : ColumnMetricsObject ; public cropShould ? : number ; public dashStyle ? : DashStyleValue ; public data : Array < ColumnPoint > = void 0 as any ; public dense ? : boolean ; public group : SVGElement = void 0 as any ; public options : ColumnSeriesOptions = void 0 as any ; public points : Array < ColumnPoint > = void 0 as any ; public pointXOffset ? : number ; public translatedThreshold ? : number ; private function param { boolean } init public animate ( init ) { const series = this , yAxis = this . yAxis , options = series . options , inverted = this . chart . inverted , attr = { } , translateProp = inverted ? 'translateX' : 'translateY' ; let translateStart , translatedThreshold ; if ( init ) { attr . scaleY = 0.001 ; translatedThreshold = clamp ( yAxis . toPixels ( options . threshold as any ) , yAxis . pos , yAxis . pos + yAxis . len ) ; if ( inverted ) { attr . translateX = translatedThreshold - yAxis . len ; } else { attr . translateY = translatedThreshold ; } if ( series . clipBox ) { series . setClip ( ) ; } series . group . attr ( attr ) ; } else { translateStart = Number ( series . group . attr ( translateProp ) ) ; series . group . animate ( { scaleY : 1 } , extend ( animObject ( series . options . animation ) , { step : function ( val , fx ) : void { if ( series . group ) { attr [ translateProp ] = translateStart + fx . pos * ( yAxis . pos - translateStart ) ; series . group . attr ( attr ) ; } } } ) ) ; } } private function public init ( chart , options ) { super . init . apply ( this , arguments as any ) ; const series = this ; chart = series . chart ; if ( chart . hasRendered ) { chart . series . forEach ( function ( otherSeries ) : void { if ( otherSeries . type === series . type ) { otherSeries . isDirty = true ; } } ) ; } } private function public getColumnMetrics ( ) { const series = this , options = series . options , xAxis = series . xAxis , yAxis = series . yAxis , reversedStacks = xAxis . options . reversedStacks , reverseStacks = ( xAxis . reversed && ! reversedStacks ) || ( ! xAxis . reversed && reversedStacks ) , stackGroups = { } ; let stackKey , columnCount = 0 ; if ( options . grouping === false ) { columnCount = 1 ; } else { series . chart . series . forEach ( function ( otherSeries ) : void { const otherYAxis = otherSeries . yAxis , otherOptions = otherSeries . options ; let columnIndex ; if ( otherSeries . type === series . type && ( otherSeries . visible || ! series . chart . options . chart . ignoreHiddenSeries ) && yAxis . len === otherYAxis . len && yAxis . pos === otherYAxis . pos ) { if ( otherOptions . stacking && otherOptions . stacking !== 'group' ) { stackKey = otherSeries . stackKey ; if ( typeof stackGroups [ stackKey as any ] === 'undefined' ) { stackGroups [ stackKey as any ] = columnCount ++ ; } columnIndex = stackGroups [ stackKey as any ] ; } else if ( otherOptions . grouping !== false ) { columnIndex = columnCount ++ ; } ( otherSeries as any ) . columnIndex = columnIndex ; } } ) ; } const categoryWidth = Math . min ( Math . abs ( xAxis . transA ) * ( ( xAxis . ordinal && xAxis . ordinal . slope ) || options . pointRange || xAxis . closestPointRange || xAxis . tickInterval || 1 ) , xAxis . len ) , groupPadding = categoryWidth * ( options . groupPadding as any ) , groupWidth = categoryWidth - 2 * groupPadding , pointOffsetWidth = groupWidth / ( columnCount || 1 ) , pointWidth = Math . min ( options . maxPointWidth || xAxis . len , pick ( options . pointWidth , pointOffsetWidth * ( 1 - 2 * ( options . pointPadding as any ) ) ) ) , pointPadding = ( pointOffsetWidth - pointWidth ) / 2 , colIndex = ( series . columnIndex || 0 ) + ( reverseStacks ? 1 : 0 ) , pointXOffset = pointPadding + ( groupPadding + colIndex * pointOffsetWidth - ( categoryWidth / 2 ) ) * ( reverseStacks ? - 1 : 1 ) ; series . columnMetrics = { width : pointWidth , offset : pointXOffset , paddedWidth : pointOffsetWidth , columnCount } ; return series . columnMetrics ; } private function public crispCol ( x , y , w , h ) { const chart = this . chart , borderWidth = this . borderWidth , xCrisp = - ( ( borderWidth as any ) % 2 ? 0.5 : 0 ) ; let right , yCrisp = ( borderWidth as any ) % 2 ? 0.5 : 1 ; if ( chart . inverted && chart . renderer . isVML ) { yCrisp += 1 ; } if ( this . options . crisp ) { right = Math . round ( x + w ) + xCrisp ; x = Math . round ( x ) + xCrisp ; w = right - x ; } const bottom = Math . round ( y + h ) + yCrisp , fromTop = Math . abs ( y ) <= 0.5 && bottom > 0.5 ; y = Math . round ( y ) + yCrisp ; h = bottom - y ; if ( fromTop && h ) { y -= 1 ; h += 1 ; } return { x : x , y : y , width : w , height : h } ; } private function param { number } x param { number } pointWidth param { Highcharts . ColumnPoint } point param { Highcharts . ColumnMetricsObject } metrics return { number } public adjustForMissingColumns ( x , pointWidth , point , metrics ) { const stacking = this . options . stacking ; if ( ! point . isNull && metrics . columnCount > 1 ) { const reversedStacks = this . yAxis . options . reversedStacks ; let indexInCategory = 0 , totalInCategory = reversedStacks ? 0 : - metrics . columnCount ; objectEach ( this . yAxis . stacking && this . yAxis . stacking . stacks , ( stack ) : void => { if ( typeof point . x === 'number' ) { const stackItem = stack [ point . x . toString ( ) ] ; if ( stackItem ) { const pointValues = stackItem . points [ this . index as any ] , total = stackItem . total ; if ( stacking ) { if ( pointValues ) { indexInCategory = totalInCategory ; } if ( stackItem . hasValidPoints ) { reversedStacks ? totalInCategory ++ : totalInCategory -- ; } } else if ( isArray ( pointValues ) ) { indexInCategory = pointValues [ 1 ] ; totalInCategory = total || 0 ; } } } } ) ; const boxWidth = ( totalInCategory - 1 ) * metrics . paddedWidth + pointWidth ; x = ( point . plotX || 0 ) + boxWidth / 2 - pointWidth - indexInCategory * metrics . paddedWidth ; } return x ; } private function public translate ( ) { const series = this , chart = series . chart , options = series . options , dense = series . dense = ( series . closestPointRange as any ) * series . xAxis . transA < 2 , borderWidth = series . borderWidth = pick ( options . borderWidth , dense ? 0 : 1 ) , xAxis = series . xAxis , yAxis = series . yAxis , threshold = options . threshold , translatedThreshold = series . translatedThreshold = yAxis . getThreshold ( threshold as any ) , minPointLength = pick ( options . minPointLength , 5 ) , metrics = series . getColumnMetrics ( ) , seriesPointWidth = metrics . width , seriesXOffset = series . pointXOffset = metrics . offset , dataMin = series . dataMin , dataMax = series . dataMax ; let seriesBarW = series . barW = Math . max ( seriesPointWidth , 1 + 2 * borderWidth ) ; if ( chart . inverted ) { ( translatedThreshold as any ) -= 0.5 ; } if ( options . pointPadding ) { seriesBarW = Math . ceil ( seriesBarW ) ; } Series . prototype . translate . apply ( series ) ; series . points . forEach ( function ( point ) : void { const yBottom = pick ( point . yBottom , translatedThreshold as any ) , safeDistance = 999 + Math . abs ( yBottom ) , plotX = point . plotX || 0 , plotY = clamp ( point . plotY as any , - safeDistance , yAxis . len + safeDistance ) ; let up , barY = Math . min ( plotY , yBottom ) , barH = Math . max ( plotY , yBottom ) - barY , pointWidth = seriesPointWidth , barX = plotX + seriesXOffset , barW = seriesBarW ; if ( minPointLength && Math . abs ( barH ) < minPointLength ) { barH = minPointLength ; up = ( ! yAxis . reversed && ! point . negative ) || ( yAxis . reversed && point . negative ) ; if ( isNumber ( threshold ) && isNumber ( dataMax ) && point . y === threshold && dataMax <= threshold && ( yAxis . min || 0 ) < threshold && ( dataMin !== dataMax || ( yAxis . max || 0 ) <= threshold ) ) { up = ! up ; } barY = ( Math . abs ( barY - ( translatedThreshold as any ) ) > minPointLength ? yBottom - minPointLength : ( translatedThreshold as any ) - ( up ? minPointLength : 0 ) ) ; } if ( defined ( point . options . pointWidth ) ) { pointWidth = barW = Math . ceil ( point . options . pointWidth as any ) ; barX -= Math . round ( ( pointWidth - seriesPointWidth ) / 2 ) ; } if ( options . centerInCategory ) { barX = series . adjustForMissingColumns ( barX , pointWidth , point , metrics ) ; } point . barX = barX ; point . pointWidth = pointWidth ; point . tooltipPos = chart . inverted ? [ clamp ( yAxis . len + yAxis . pos - chart . plotLeft - plotY , yAxis . pos - chart . plotLeft , yAxis . len + yAxis . pos - chart . plotLeft ) , xAxis . len + xAxis . pos - chart . plotTop - barX - barW / 2 , barH ] : [ xAxis . left - chart . plotLeft + barX + barW / 2 , clamp ( plotY + ( yAxis . pos as any ) - chart . plotTop , yAxis . pos - chart . plotTop , yAxis . len + yAxis . pos - chart . plotTop ) , barH ] ; point . shapeType = series . pointClass . prototype . shapeType || 'rect' ; point . shapeArgs = series . crispCol . apply ( series , point . isNull ? [ barX , translatedThreshold as any , barW , 0 ] : [ barX , barY , barW , barH ] ) ; } ) ; } private function public drawGraph ( ) { this . group [ this . dense ? 'addClass' : 'removeClass' ] ( 'highcharts-dense-data' ) ; } private function public pointAttribs ( point ? , state ? ) { const options = this . options , p2o = ( this as any ) . pointAttrToOptions || { } , strokeOption = p2o . stroke || 'borderColor' , strokeWidthOption = p2o [ 'stroke-width' ] || 'borderWidth' ; let stateOptions , zone , brightness , fill = ( point && point . color ) || this . color , stroke = ( ( point && ( point as any ) [ strokeOption ] ) || ( options as any ) [ strokeOption ] || fill ) , dashstyle = ( point && point . options . dashStyle ) || options . dashStyle , strokeWidth = ( point && ( point as any ) [ strokeWidthOption ] ) || ( options as any ) [ strokeWidthOption ] || ( this as any ) [ strokeWidthOption ] || 0 , opacity = pick ( point && point . opacity , options . opacity , 1 ) ; if ( point && this . zones . length ) { zone = point . getZone ( ) ; fill = ( point . options . color || ( zone && ( zone . color || point . nonZonedColor ) ) || this . color ) ; if ( zone ) { stroke = zone . borderColor || stroke ; dashstyle = zone . dashStyle || dashstyle ; strokeWidth = zone . borderWidth || strokeWidth ; } } if ( state && point ) { stateOptions = merge ( ( options . states as any ) [ state ] , point . options . states && ( point . options . states as any ) [ state ] || { } ) ; brightness = stateOptions . brightness ; fill = stateOptions . color || ( typeof brightness !== 'undefined' && color ( fill as any ) . brighten ( stateOptions . brightness as any ) . get ( ) ) || fill ; stroke = ( stateOptions as any ) [ strokeOption ] || stroke ; strokeWidth = ( stateOptions as any ) [ strokeWidthOption ] || strokeWidth ; dashstyle = stateOptions . dashStyle || dashstyle ; opacity = pick ( stateOptions . opacity , opacity ) ; } const ret = { fill : fill as any , stroke : stroke , 'stroke-width' : strokeWidth , opacity : opacity } ; if ( dashstyle ) { ret . dashstyle = dashstyle ; } return ret ; } private function public drawPoints ( ) { const series = this , chart = this . chart , options = series . options , renderer = chart . renderer , animationLimit = options . animationLimit || 250 ; let shapeArgs ; series . points . forEach ( function ( point ) : void { const plotY = point . plotY ; let graphic = point . graphic , hasGraphic = ! ! graphic , verb = graphic && chart . pointCount < animationLimit ? 'animate' : 'attr' ; if ( isNumber ( plotY ) && point . y !== null ) { shapeArgs = point . shapeArgs ; if ( graphic && point . hasNewShapeType ( ) ) { graphic = graphic . destroy ( ) ; } if ( series . enabledDataSorting ) { point . startXPos = series . xAxis . reversed ? - ( shapeArgs ? ( shapeArgs . width || 0 ) : 0 ) : series . xAxis . width ; } if ( ! graphic ) { point . graphic = graphic = ( renderer as any ) [ point . shapeType as any ] ( shapeArgs ) . add ( point . group || series . group ) ; if ( graphic && series . enabledDataSorting && chart . hasRendered && chart . pointCount < animationLimit ) { graphic . attr ( { x : point . startXPos } ) ; hasGraphic = true ; verb = 'animate' ; } } if ( graphic && hasGraphic ) { graphic [ verb ] ( merge ( shapeArgs ) ) ; } if ( options . borderRadius ) { ( graphic as any ) [ verb ] ( { r : options . borderRadius } ) ; } if ( ! chart . styledMode ) { ( graphic as any ) [ verb ] ( series . pointAttribs ( point , ( point . selected && 'select' ) as any ) ) . shadow ( point . allowShadow !== false && options . shadow , null , options . stacking && ! options . borderRadius ) ; } if ( graphic ) { graphic . addClass ( point . getClassName ( ) , true ) ; graphic . attr ( { visibility : point . visible ? 'inherit' : 'hidden' } ) ; } } else if ( graphic ) { point . graphic = graphic . destroy ( ) ; } } ) ; } private public drawTracker ( ) { const series = this , chart = series . chart , pointer = chart . pointer , onMouseOver = function ( e ) : void { const point = pointer . getPointFromEvent ( e ) ; if ( typeof point !== 'undefined' ) { pointer . isDirectTouch = true ; point . onMouseOver ( e ) ; } } ; let dataLabels ; series . points . forEach ( function ( point ) : void { dataLabels = ( isArray ( point . dataLabels ) ? point . dataLabels : ( point . dataLabel ? [ point . dataLabel ] : [ ] ) ) ; if ( point . graphic ) { ( point . graphic . element as any ) . point = point ; } ( dataLabels as any ) . forEach ( function ( dataLabel ) : void { if ( dataLabel . div ) { dataLabel . div . point = point ; } else { ( dataLabel . element as any ) . point = point ; } } ) ; } ) ; if ( ! series . _hasTracking ) { ( series . trackerGroups as any ) . forEach ( function ( key ) : void { if ( ( series as any ) [ key ] ) { ( series as any ) [ key ] . addClass ( 'highcharts-tracker' ) . on ( 'mouseover' , onMouseOver ) . on ( 'mouseout' , function ( e ) : void { pointer . onTrackerMouseOut ( e ) ; } ) ; if ( hasTouch ) { ( series as any ) [ key ] . on ( 'touchstart' , onMouseOver ) ; } if ( ! chart . styledMode && series . options . cursor ) { ( series as any ) [ key ] . css ( css ) . css ( { cursor : series . options . cursor } ) ; } } } ) ; series . _hasTracking = true ; } fireEvent ( this , 'afterDrawTracker' ) ; } private function public remove ( ) { const series = this , chart = series . chart ; if ( chart . hasRendered ) { chart . series . forEach ( function ( otherSeries ) : void { if ( otherSeries . type === series . type ) { otherSeries . isDirty = true ; } } ) ; } Series . prototype . remove . apply ( series , arguments as any ) ; } } interface ColumnSeries { pointClass : typeof ColumnPoint ; } extend ( ColumnSeries . prototype , { cropShoulder : 0 , directTouch : true , private function param { Highcharts . Legend } legend param { Highcharts . Series | Highcharts . Point } item drawLegendSymbol : LegendSymbol . drawRectangle , getSymbol : noop , negStacks : true , trackerGroups : [ 'group' , 'dataLabelsGroup' ] } ) ; declare module '../../Core/Series/SeriesType' { interface SeriesTypeRegistry { column : typeof ColumnSeries ; } } SeriesRegistry . registerSeriesType ( 'column' , ColumnSeries ) ; export default ColumnSeries ; private interface name type { number } name type { number } '' ; extends series excluding product apioption sample sample sample sample sample type { Array < number | Array < ( number | string ) , ( number | null ) > | null | * > } extends series . line . data excluding product apioption sample type { Highcharts . ColorString | Highcharts . GradientColorObject | Highcharts . PatternObject } product apioption sample type { number } product apioption see type { Highcharts . DashStyleValue } apioption see type { number } apioption excluding product apioption excluding product apioption '' ;