/* * * (c) 2010-2019 Torstein Honsi * * License: www.highcharts.com/license */ /** * @callback Highcharts.AxisEventCallbackFunction * * @param {Highcharts.Axis} this */ /** * Options for crosshairs on axes. * * @typedef {Highcharts.XAxisCrosshairOptions|Highcharts.YAxisCrosshairOptions} Highcharts.AxisCrosshairOptions */ /** * @interface Highcharts.AxisLabelsFormatterContextObject *//** * @name Highcharts.AxisLabelsFormatterContextObject#axis * @type {Highcharts.Axis} *//** * @name Highcharts.AxisLabelsFormatterContextObject#chart * @type {Highcharts.Chart} *//** * @name Highcharts.AxisLabelsFormatterContextObject#isFirst * @type {boolean} *//** * @name Highcharts.AxisLabelsFormatterContextObject#isLast * @type {boolean} *//** * @name Highcharts.AxisLabelsFormatterContextObject#value * @type {number} */ /** * Options for axes. * * @typedef {Highcharts.XAxisOptions|Highcharts.YAxisOptions|Highcharts.ZAxisOptions} Highcharts.AxisOptions */ /** * The returned object literal from the {@link Highcharts.Axis#getExtremes} * function. * * @interface Highcharts.ExtremesObject *//** * The maximum value of the axis' associated series. * @name Highcharts.ExtremesObject#dataMax * @type {number} *//** * The minimum value of the axis' associated series. * @name Highcharts.ExtremesObject#dataMin * @type {number} *//** * The maximum axis value, either automatic or set manually. If the `max` option * is not set, `maxPadding` is 0 and `endOnTick` is false, this value will be * the same as `dataMax`. * @name Highcharts.ExtremesObject#max * @type {number} *//** * The minimum axis value, either automatic or set manually. If the `min` option * is not set, `minPadding` is 0 and `startOnTick` is false, this value will be * the same as `dataMin`. * @name Highcharts.ExtremesObject#min * @type {number} *//** * The user defined maximum, either from the `max` option or from a zoom or * `setExtremes` action. * @name Highcharts.ExtremesObject#userMax * @type {number} *//** * The user defined minimum, either from the `min` option or from a zoom or * `setExtremes` action. * @name Highcharts.ExtremesObject#userMin * @type {number} */ /** * @callback Highcharts.AxisPointBreakEventCallbackFunction * * @param {Highcharts.Axis} this * * @param {Highcharts.AxisPointBreakEventObject} event */ /** * @interface Highcharts.AxisPointBreakEventObject *//** * @name Highcharts.AxisPointBreakEventObject#brk * @type {Highcharts.Dictionary} *//** * @name Highcharts.AxisPointBreakEventObject#point * @type {Highcharts.Point} *//** * @name Highcharts.AxisPointBreakEventObject#preventDefault * @type {Function} *//** * @name Highcharts.AxisPointBreakEventObject#target * @type {Highcharts.SVGElement} *//** * @name Highcharts.AxisPointBreakEventObject#type * @type {"pointBreak"|"pointInBreak"} */ /** * @callback Highcharts.AxisSetExtremesEventCallbackFunction * * @param {Highcharts.Axis} this * * @param {Highcharts.AxisSetExtremesEventObject} event */ /** * @interface Highcharts.AxisSetExtremesEventObject *//** * @name Highcharts.AxisSetExtremesEventObject#dataMax * @type {number} *//** * @name Highcharts.AxisSetExtremesEventObject#dataMin * @type {number} *//** * @name Highcharts.AxisSetExtremesEventObject#max * @type {number} *//** * @name Highcharts.AxisSetExtremesEventObject#min * @type {number} *//** * @name Highcharts.AxisSetExtremesEventObject#preventDefault * @type {Function} *//** * @name Highcharts.AxisSetExtremesEventObject#target * @type {Highcharts.SVGElement} *//** * @name Highcharts.AxisSetExtremesEventObject#trigger * @type {string} *//** * @name Highcharts.AxisSetExtremesEventObject#type * @type {"setExtremes"} *//** * @name Highcharts.AxisSetExtremesEventObject#userMax * @type {number} *//** * @name Highcharts.AxisSetExtremesEventObject#userMin * @type {number} */ /** * @callback Highcharts.AxisTickPositionerCallbackFunction * * @param {Highcharts.Axis} this * * @return {Array} */ 'use strict'; import H from './Globals.js'; import './Utilities.js'; import './Color.js'; import './Options.js'; import './Tick.js'; var addEvent = H.addEvent, animObject = H.animObject, arrayMax = H.arrayMax, arrayMin = H.arrayMin, color = H.color, correctFloat = H.correctFloat, defaultOptions = H.defaultOptions, defined = H.defined, deg2rad = H.deg2rad, destroyObjectProperties = H.destroyObjectProperties, extend = H.extend, fireEvent = H.fireEvent, format = H.format, getMagnitude = H.getMagnitude, isArray = H.isArray, isNumber = H.isNumber, isString = H.isString, merge = H.merge, normalizeTickInterval = H.normalizeTickInterval, objectEach = H.objectEach, pick = H.pick, removeEvent = H.removeEvent, splat = H.splat, syncTimeout = H.syncTimeout, Tick = H.Tick; /** * Create a new axis object. Called internally when instanciating a new chart or * adding axes by {@link Highcharts.Chart#addAxis}. * * A chart can have from 0 axes (pie chart) to multiples. In a normal, single * series cartesian chart, there is one X axis and one Y axis. * * The X axis or axes are referenced by {@link Highcharts.Chart.xAxis}, which is * an array of Axis objects. If there is only one axis, it can be referenced * through `chart.xAxis[0]`, and multiple axes have increasing indices. The same * pattern goes for Y axes. * * If you need to get the axes from a series object, use the `series.xAxis` and * `series.yAxis` properties. These are not arrays, as one series can only be * associated to one X and one Y axis. * * A third way to reference the axis programmatically is by `id`. Add an `id` in * the axis configuration options, and get the axis by * {@link Highcharts.Chart#get}. * * Configuration options for the axes are given in options.xAxis and * options.yAxis. * * @class * @name Highcharts.Axis * * @param {Highcharts.Chart} chart * The Chart instance to apply the axis on. * * @param {Highcharts.AxisOptions} options * Axis options. */ var Axis = function () { this.init.apply(this, arguments); }; H.extend(Axis.prototype, /** @lends Highcharts.Axis.prototype */{ /** * The X axis or category axis. Normally this is the horizontal axis, * though if the chart is inverted this is the vertical axis. In case of * multiple axes, the xAxis node is an array of configuration objects. * * See the [Axis class](/class-reference/Highcharts.Axis) for programmatic * access to the axis. * * @productdesc {highmaps} * In Highmaps, the axis is hidden, but it is used behind the scenes to * control features like zooming and panning. Zooming is in effect the same * as setting the extremes of one of the exes. * * @type {*|Array<*>} * @optionparent xAxis */ defaultOptions: { /** * When using multiple axis, the ticks of two or more opposite axes * will automatically be aligned by adding ticks to the axis or axes * with the least ticks, as if `tickAmount` were specified. * * This can be prevented by setting `alignTicks` to false. If the grid * lines look messy, it's a good idea to hide them for the secondary * axis by setting `gridLineWidth` to 0. * * If `startOnTick` or `endOnTick` in an Axis options are set to false, * then the `alignTicks ` will be disabled for the Axis. * * Disabled for logarithmic axes. * * @type {boolean} * @default true * @product highcharts highstock gantt * @apioption xAxis.alignTicks */ /** * Whether to allow decimals in this axis' ticks. When counting * integers, like persons or hits on a web page, decimals should * be avoided in the labels. * * @see [minTickInterval](#xAxis.minTickInterval) * * @sample {highcharts|highstock} highcharts/yaxis/allowdecimals-true/ * True by default * @sample {highcharts|highstock} highcharts/yaxis/allowdecimals-false/ * False * * @type {boolean} * @default true * @since 2.0 * @apioption xAxis.allowDecimals */ /** * When using an alternate grid color, a band is painted across the * plot area between every other grid line. * * @sample {highcharts} highcharts/yaxis/alternategridcolor/ * Alternate grid color on the Y axis * @sample {highstock} stock/xaxis/alternategridcolor/ * Alternate grid color on the Y axis * * @type {Highcharts.ColorString} * @apioption xAxis.alternateGridColor */ /** * An array defining breaks in the axis, the sections defined will be * left out and all the points shifted closer to each other. * * @productdesc {highcharts} * Requires that the broken-axis.js module is loaded. * * @sample {highcharts} highcharts/axisbreak/break-simple/ * Simple break * @sample {highcharts|highstock} highcharts/axisbreak/break-visualized/ * Advanced with callback * @sample {highstock} stock/demo/intraday-breaks/ * Break on nights and weekends * * @type {Array<*>} * @since 4.1.0 * @product highcharts highstock gantt * @apioption xAxis.breaks */ /** * A number indicating how much space should be left between the start * and the end of the break. The break size is given in axis units, * so for instance on a `datetime` axis, a break size of 3600000 would * indicate the equivalent of an hour. * * @type {number} * @default 0 * @since 4.1.0 * @product highcharts highstock gantt * @apioption xAxis.breaks.breakSize */ /** * The point where the break starts. * * @type {number} * @since 4.1.0 * @product highcharts highstock gantt * @apioption xAxis.breaks.from */ /** * Defines an interval after which the break appears again. By default * the breaks do not repeat. * * @type {number} * @default 0 * @since 4.1.0 * @product highcharts highstock gantt * @apioption xAxis.breaks.repeat */ /** * The point where the break ends. * * @type {number} * @since 4.1.0 * @product highcharts highstock gantt * @apioption xAxis.breaks.to */ /** * If categories are present for the xAxis, names are used instead of * numbers for that axis. Since Highcharts 3.0, categories can also * be extracted by giving each point a [name](#series.data) and setting * axis [type](#xAxis.type) to `category`. However, if you have multiple * series, best practice remains defining the `categories` array. * * Example: * *
categories: ['Apples', 'Bananas', 'Oranges']
* * @sample {highcharts} highcharts/demo/line-labels/ * With * @sample {highcharts} highcharts/xaxis/categories/ * Without * * @type {Array} * @product highcharts gantt * @apioption xAxis.categories */ /** * The highest allowed value for automatically computed axis extremes. * * @see [floor](#xAxis.floor) * * @sample {highcharts|highstock} highcharts/yaxis/floor-ceiling/ * Floor and ceiling * * @type {number} * @since 4.0 * @product highcharts highstock gantt * @apioption xAxis.ceiling */ /** * A class name that opens for styling the axis by CSS, especially in * Highcharts styled mode. The class name is applied to group elements * for the grid, axis elements and labels. * * @sample {highcharts|highstock|highmaps} highcharts/css/axis/ * Multiple axes with separate styling * * @type {string} * @since 5.0.0 * @apioption xAxis.className */ /** * Configure a crosshair that follows either the mouse pointer or the * hovered point. * * In styled mode, the crosshairs are styled in the * `.highcharts-crosshair`, `.highcharts-crosshair-thin` or * `.highcharts-xaxis-category` classes. * * @productdesc {highstock} * In Highstock, by default, the crosshair is enabled on the X axis and * disabled on the Y axis. * * @sample {highcharts} highcharts/xaxis/crosshair-both/ * Crosshair on both axes * @sample {highstock} stock/xaxis/crosshairs-xy/ * Crosshair on both axes * @sample {highmaps} highcharts/xaxis/crosshair-both/ * Crosshair on both axes * * @type {boolean|*} * @default false * @since 4.1 * @apioption xAxis.crosshair */ /** * A class name for the crosshair, especially as a hook for styling. * * @type {string} * @since 5.0.0 * @apioption xAxis.crosshair.className */ /** * The color of the crosshair. Defaults to `#cccccc` for numeric and * datetime axes, and `rgba(204,214,235,0.25)` for category axes, where * the crosshair by default highlights the whole category. * * @sample {highcharts|highstock|highmaps} highcharts/xaxis/crosshair-customized/ * Customized crosshairs * * @type {Highcharts.ColorString} * @default #cccccc * @since 4.1 * @apioption xAxis.crosshair.color */ /** * The dash style for the crosshair. See * [series.dashStyle](#plotOptions.series.dashStyle) * for possible values. * * @sample {highcharts|highmaps} highcharts/xaxis/crosshair-dotted/ * Dotted crosshair * @sample {highstock} stock/xaxis/crosshair-dashed/ * Dashed X axis crosshair * * @type {Highcharts.DashStyleType} * @default Solid * @since 4.1 * @apioption xAxis.crosshair.dashStyle */ /** * A label on the axis next to the crosshair. * * In styled mode, the label is styled with the * `.highcharts-crosshair-label` class. * * @sample {highstock} stock/xaxis/crosshair-label/ * Crosshair labels * @sample {highstock} highcharts/css/crosshair-label/ * Style mode * * @since 2.1 * @product highstock * @apioption xAxis.crosshair.label */ /** * Alignment of the label compared to the axis. Defaults to `left` for * right-side axes, `right` for left-side axes and `center` for * horizontal axes. * * @type {string} * @since 2.1 * @product highstock * @apioption xAxis.crosshair.label.align */ /** * The background color for the label. Defaults to the related series * color, or `#666666` if that is not available. * * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject} * @since 2.1 * @product highstock * @apioption xAxis.crosshair.label.backgroundColor */ /** * The border color for the crosshair label * * @type {Highcharts.ColorString} * @since 2.1 * @product highstock * @apioption xAxis.crosshair.label.borderColor */ /** * The border corner radius of the crosshair label. * * @type {number} * @default 3 * @since 2.1.10 * @product highstock * @apioption xAxis.crosshair.label.borderRadius */ /** * The border width for the crosshair label. * * @type {number} * @default 0 * @since 2.1 * @product highstock * @apioption xAxis.crosshair.label.borderWidth */ /** * A format string for the crosshair label. Defaults to `{value}` for * numeric axes and `{value:%b %d, %Y}` for datetime axes. * * @type {string} * @since 2.1 * @product highstock * @apioption xAxis.crosshair.label.format */ /** * Formatter function for the label text. * * @type {Highcharts.FormatterCallbackFunction} * @since 2.1 * @product highstock * @apioption xAxis.crosshair.label.formatter */ /** * Padding inside the crosshair label. * * @type {number} * @default 8 * @since 2.1 * @product highstock * @apioption xAxis.crosshair.label.padding */ /** * The shape to use for the label box. * * @type {string} * @default callout * @since 2.1 * @product highstock * @apioption xAxis.crosshair.label.shape */ /** * Text styles for the crosshair label. * * @type {Highcharts.CSSObject} * @default {"color": "white", "fontWeight": "normal", "fontSize": "11px", "textAlign": "center"} * @since 2.1 * @product highstock * @apioption xAxis.crosshair.label.style */ /** * Whether the crosshair should snap to the point or follow the pointer * independent of points. * * @sample {highcharts|highstock} highcharts/xaxis/crosshair-snap-false/ * True by default * @sample {highmaps} maps/demo/latlon-advanced/ * Snap is false * * @type {boolean} * @default true * @since 4.1 * @apioption xAxis.crosshair.snap */ /** * The pixel width of the crosshair. Defaults to 1 for numeric or * datetime axes, and for one category width for category axes. * * @sample {highcharts} highcharts/xaxis/crosshair-customized/ * Customized crosshairs * @sample {highstock} highcharts/xaxis/crosshair-customized/ * Customized crosshairs * @sample {highmaps} highcharts/xaxis/crosshair-customized/ * Customized crosshairs * * @type {number} * @default 1 * @since 4.1 * @apioption xAxis.crosshair.width */ /** * The Z index of the crosshair. Higher Z indices allow drawing the * crosshair on top of the series or behind the grid lines. * * @type {number} * @default 2 * @since 4.1 * @apioption xAxis.crosshair.zIndex */ /** * For a datetime axis, the scale will automatically adjust to the * appropriate unit. This member gives the default string * representations used for each unit. For intermediate values, * different units may be used, for example the `day` unit can be used * on midnight and `hour` unit be used for intermediate values on the * same axis. For an overview of the replacement codes, see * [dateFormat](/class-reference/Highcharts#dateFormat). Defaults to: * *
{
         *     millisecond: '%H:%M:%S.%L',
         *     second: '%H:%M:%S',
         *     minute: '%H:%M',
         *     hour: '%H:%M',
         *     day: '%e. %b',
         *     week: '%e. %b',
         *     month: '%b \'%y',
         *     year: '%Y'
         * }
* * @sample {highcharts} highcharts/xaxis/datetimelabelformats/ * Different day format on X axis * @sample {highstock} stock/xaxis/datetimelabelformats/ * More information in x axis labels * * @product highcharts highstock gantt */ dateTimeLabelFormats: { millisecond: { main: '%H:%M:%S.%L', range: false }, second: { main: '%H:%M:%S', range: false }, minute: { main: '%H:%M', range: false }, hour: { main: '%H:%M', range: false }, day: { main: '%e. %b' }, week: { main: '%e. %b' }, month: { main: '%b \'%y' }, year: { main: '%Y' } }, /** * _Requires Accessibility module_ * * Description of the axis to screen reader users. * * @type {string} * @since 5.0.0 * @apioption xAxis.description */ /** * Whether to force the axis to end on a tick. Use this option with * the `maxPadding` option to control the axis end. * * @productdesc {highstock} * In Highstock, `endOnTick` is always false when the navigator is * enabled, to prevent jumpy scrolling. * * @sample {highcharts} highcharts/chart/reflow-true/ * True by default * @sample {highcharts} highcharts/yaxis/endontick/ * False * @sample {highstock} stock/demo/basic-line/ * True by default * @sample {highstock} stock/xaxis/endontick/ * False * * @since 1.2.0 */ endOnTick: false, /** * Event handlers for the axis. * * @type {*} * @apioption xAxis.events */ /** * An event fired after the breaks have rendered. * * @see [breaks](#xAxis.breaks) * * @sample {highcharts} highcharts/axisbreak/break-event/ * AfterBreak Event * * @type {Highcharts.AxisEventCallbackFunction} * @since 4.1.0 * @product highcharts gantt * @apioption xAxis.events.afterBreaks */ /** * As opposed to the `setExtremes` event, this event fires after the * final min and max values are computed and corrected for `minRange`. * * Fires when the minimum and maximum is set for the axis, either by * calling the `.setExtremes()` method or by selecting an area in the * chart. One parameter, `event`, is passed to the function, containing * common event information. * * The new user set minimum and maximum values can be found by * `event.min` and `event.max`. These reflect the axis minimum and * maximum in axis values. The actual data extremes are found in * `event.dataMin` and `event.dataMax`. * * @type {Highcharts.AxisSetExtremesEventCallbackFunction} * @since 2.3 * @context Axis * @apioption xAxis.events.afterSetExtremes */ /** * An event fired when a break from this axis occurs on a point. * * @see [breaks](#xAxis.breaks) * * @sample {highcharts} highcharts/axisbreak/break-visualized/ * Visualization of a Break * * @type {Highcharts.AxisPointBreakEventCallbackFunction} * @since 4.1.0 * @product highcharts gantt * @context Axis * @apioption xAxis.events.pointBreak */ /** * An event fired when a point falls inside a break from this axis. * * @type {Highcharts.AxisPointBreakEventCallbackFunction} * @product highcharts highstock gantt * @context Axis * @apioption xAxis.events.pointInBreak */ /** * Fires when the minimum and maximum is set for the axis, either by * calling the `.setExtremes()` method or by selecting an area in the * chart. One parameter, `event`, is passed to the function, * containing common event information. * * The new user set minimum and maximum values can be found by * `event.min` and `event.max`. These reflect the axis minimum and * maximum in data values. When an axis is zoomed all the way out from * the "Reset zoom" button, `event.min` and `event.max` are null, and * the new extremes are set based on `this.dataMin` and `this.dataMax`. * * @sample {highstock} stock/xaxis/events-setextremes/ * Log new extremes on x axis * * @type {Highcharts.AxisSetExtremesEventCallbackFunction} * @since 1.2.0 * @context Axis * @apioption xAxis.events.setExtremes */ /** * The lowest allowed value for automatically computed axis extremes. * * @see [ceiling](#yAxis.ceiling) * * @sample {highcharts} highcharts/yaxis/floor-ceiling/ * Floor and ceiling * @sample {highstock} stock/demo/lazy-loading/ * Prevent negative stock price on Y axis * * @type {number} * @since 4.0 * @product highcharts highstock gantt * @apioption xAxis.floor */ /** * The dash or dot style of the grid lines. For possible values, see * [this demonstration](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/plotoptions/series-dashstyle-all/). * * @sample {highcharts} highcharts/yaxis/gridlinedashstyle/ * Long dashes * @sample {highstock} stock/xaxis/gridlinedashstyle/ * Long dashes * * @type {Highcharts.DashStyleType} * @default Solid * @since 1.2 * @apioption xAxis.gridLineDashStyle */ /** * The Z index of the grid lines. * * @sample {highcharts|highstock} highcharts/xaxis/gridzindex/ * A Z index of 4 renders the grid above the graph * * @type {number} * @default 1 * @product highcharts highstock gantt * @apioption xAxis.gridZIndex */ /** * An id for the axis. This can be used after render time to get * a pointer to the axis object through `chart.get()`. * * @sample {highcharts} highcharts/xaxis/id/ * Get the object * @sample {highstock} stock/xaxis/id/ * Get the object * * @type {string} * @since 1.2.0 * @apioption xAxis.id */ /** * The axis labels show the number or category for each tick. * * @productdesc {highmaps} * X and Y axis labels are by default disabled in Highmaps, but the * functionality is inherited from Highcharts and used on `colorAxis`, * and can be enabled on X and Y axes too. */ labels: { /** * What part of the string the given position is anchored to. * If `left`, the left side of the string is at the axis position. * Can be one of `"left"`, `"center"` or `"right"`. Defaults to * an intelligent guess based on which side of the chart the axis * is on and the rotation of the label. * * @see [reserveSpace](#xAxis.labels.reserveSpace) * * @sample {highcharts} highcharts/xaxis/labels-align-left/ * Left * @sample {highcharts} highcharts/xaxis/labels-align-right/ * Right * @sample {highcharts} highcharts/xaxis/labels-reservespace-true/ * Left-aligned labels on a vertical category axis * * @type {string} * @validvalue ["left", "center", "right"] * @apioption xAxis.labels.align */ /** * For horizontal axes, the allowed degrees of label rotation * to prevent overlapping labels. If there is enough space, * labels are not rotated. As the chart gets narrower, it * will start rotating the labels -45 degrees, then remove * every second label and try again with rotations 0 and -45 etc. * Set it to `false` to disable rotation, which will * cause the labels to word-wrap if possible. * * @sample {highcharts|highstock} highcharts/xaxis/labels-autorotation-default/ * Default auto rotation of 0 or -45 * @sample {highcharts|highstock} highcharts/xaxis/labels-autorotation-0-90/ * Custom graded auto rotation * * @type {Array} * @default [-45] * @since 4.1.0 * @product highcharts highstock gantt * @apioption xAxis.labels.autoRotation */ /** * When each category width is more than this many pixels, we don't * apply auto rotation. Instead, we lay out the axis label with word * wrap. A lower limit makes sense when the label contains multiple * short words that don't extend the available horizontal space for * each label. * * @sample {highcharts} highcharts/xaxis/labels-autorotationlimit/ * Lower limit * * @type {number} * @default 80 * @since 4.1.5 * @product highcharts gantt * @apioption xAxis.labels.autoRotationLimit */ /** * Polar charts only. The label's pixel distance from the perimeter * of the plot area. * * @type {number} * @default 15 * @product highcharts gantt * @apioption xAxis.labels.distance */ /** * Enable or disable the axis labels. * * @sample {highcharts} highcharts/xaxis/labels-enabled/ * X axis labels disabled * @sample {highstock} stock/xaxis/labels-enabled/ * X axis labels disabled * * @default {highcharts|highstock|gantt} true * @default {highmaps} false */ enabled: true, /** * A [format string](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting) * for the axis label. * * @sample {highcharts|highstock} highcharts/yaxis/labels-format/ * Add units to Y axis label * * @type {string} * @default {value} * @since 3.0 * @apioption xAxis.labels.format */ /** * Callback JavaScript function to format the label. The value * is given by `this.value`. Additional properties for `this` are * `axis`, `chart`, `isFirst` and `isLast`. The value of the default * label formatter can be retrieved by calling * `this.axis.defaultLabelFormatter.call(this)` within the function. * * Defaults to: * *
function() {
             *     return this.value;
             * }
* * @sample {highcharts} highcharts/xaxis/labels-formatter-linked/ * Linked category names * @sample {highcharts} highcharts/xaxis/labels-formatter-extended/ * Modified numeric labels * @sample {highstock} stock/xaxis/labels-formatter/ * Added units on Y axis * * @type {Highcharts.FormatterCallbackFunction} * @apioption xAxis.labels.formatter */ /** * The number of pixels to indent the labels per level in a treegrid * axis. * * @sample gantt/treegrid-axis/demo * Indentation 10px by default. * @sample gantt/treegrid-axis/indentation-0px * Indentation set to 0px. * * @product gantt */ indentation: 10, /** * Horizontal axis only. When `staggerLines` is not set, * `maxStaggerLines` defines how many lines the axis is allowed to * add to automatically avoid overlapping X labels. Set to `1` to * disable overlap detection. * * @deprecated * @type {number} * @default 5 * @since 1.3.3 * @apioption xAxis.labels.maxStaggerLines */ /** * How to handle overflowing labels on horizontal axis. If set to * `"allow"`, it will not be aligned at all. By default it * `"justify"` labels inside the chart area. If there is room to * move it, it will be aligned to the edge, else it will be removed. * * @type {string} * @default justify * @since 2.2.5 * @validvalue ["allow", "justify"] * @apioption xAxis.labels.overflow */ /** * The pixel padding for axis labels, to ensure white space between * them. * * @type {number} * @default 5 * @product highcharts gantt * @apioption xAxis.labels.padding */ /** * Whether to reserve space for the labels. By default, space is * reserved for the labels in these cases: * * * On all horizontal axes. * * On vertical axes if `label.align` is `right` on a left-side * axis or `left` on a right-side axis. * * On vertical axes if `label.align` is `center`. * * This can be turned off when for example the labels are rendered * inside the plot area instead of outside. * * @see [labels.align](#xAxis.labels.align) * * @sample {highcharts} highcharts/xaxis/labels-reservespace/ * No reserved space, labels inside plot * @sample {highcharts} highcharts/xaxis/labels-reservespace-true/ * Left-aligned labels on a vertical category axis * * @type {boolean} * @since 4.1.10 * @product highcharts gantt * @apioption xAxis.labels.reserveSpace */ /** * Rotation of the labels in degrees. * * @sample {highcharts} highcharts/xaxis/labels-rotation/ * X axis labels rotated 90° * * @type {number} * @default 0 * @apioption xAxis.labels.rotation */ /** * Horizontal axes only. The number of lines to spread the labels * over to make room or tighter labels. * * @sample {highcharts} highcharts/xaxis/labels-staggerlines/ * Show labels over two lines * @sample {highstock} stock/xaxis/labels-staggerlines/ * Show labels over two lines * * @type {number} * @since 2.1 * @apioption xAxis.labels.staggerLines */ /** * To show only every _n_'th label on the axis, set the step to _n_. * Setting the step to 2 shows every other label. * * By default, the step is calculated automatically to avoid * overlap. To prevent this, set it to 1\. This usually only * happens on a category axis, and is often a sign that you have * chosen the wrong axis type. * * Read more at * [Axis docs](https://www.highcharts.com/docs/chart-concepts/axes) * => What axis should I use? * * @sample {highcharts} highcharts/xaxis/labels-step/ * Showing only every other axis label on a categorized * x-axis * @sample {highcharts} highcharts/xaxis/labels-step-auto/ * Auto steps on a category axis * * @type {number} * @since 2.1 * @apioption xAxis.labels.step */ /** * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html) * to render the labels. * * @type {boolean} * @default false * @apioption xAxis.labels.useHTML */ /** * The x position offset of the label relative to the tick position * on the axis. * * @sample {highcharts} highcharts/xaxis/labels-x/ * Y axis labels placed on grid lines */ x: 0, /** * The y position offset of the label relative to the tick position * on the axis. The default makes it adapt to the font size on * bottom axis. * * @sample {highcharts} highcharts/xaxis/labels-x/ * Y axis labels placed on grid lines * * @type {number} * @apioption xAxis.labels.y */ /** * The Z index for the axis labels. * * @type {number} * @default 7 * @apioption xAxis.labels.zIndex */ /** * CSS styles for the label. Use `whiteSpace: 'nowrap'` to prevent * wrapping of category labels. Use `textOverflow: 'none'` to * prevent ellipsis (dots). * * In styled mode, the labels are styled with the * `.highcharts-axis-labels` class. * * @sample {highcharts} highcharts/xaxis/labels-style/ * Red X axis labels * * @type {Highcharts.CSSObject} * @default {"color": "#666666", "cursor": "default", "fontSize": "11px"} */ style: { /** @ignore-option */ color: '#666666', /** @ignore-option */ cursor: 'default', /** @ignore-option */ fontSize: '11px' } }, /** * Index of another axis that this axis is linked to. When an axis is * linked to a master axis, it will take the same extremes as * the master, but as assigned by min or max or by setExtremes. * It can be used to show additional info, or to ease reading the * chart by duplicating the scales. * * @sample {highcharts} highcharts/xaxis/linkedto/ * Different string formats of the same date * @sample {highcharts} highcharts/yaxis/linkedto/ * Y values on both sides * * @type {number} * @since 2.0.2 * @product highcharts highstock gantt * @apioption xAxis.linkedTo */ /** * The maximum value of the axis. If `null`, the max value is * automatically calculated. * * If the [endOnTick](#yAxis.endOnTick) option is true, the `max` value * might be rounded up. * * If a [tickAmount](#yAxis.tickAmount) is set, the axis may be extended * beyond the set max in order to reach the given number of ticks. The * same may happen in a chart with multiple axes, determined by [chart. * alignTicks](#chart), where a `tickAmount` is applied internally. * * @sample {highcharts} highcharts/yaxis/max-200/ * Y axis max of 200 * @sample {highcharts} highcharts/yaxis/max-logarithmic/ * Y axis max on logarithmic axis * @sample {highstock} stock/xaxis/min-max/ * Fixed min and max on X axis * @sample {highmaps} maps/axis/min-max/ * Pre-zoomed to a specific area * * @type {number} * @apioption xAxis.max */ /** * Padding of the max value relative to the length of the axis. A * padding of 0.05 will make a 100px axis 5px longer. This is useful * when you don't want the highest data value to appear on the edge * of the plot area. When the axis' `max` option is set or a max extreme * is set using `axis.setExtremes()`, the maxPadding will be ignored. * * @sample {highcharts} highcharts/yaxis/maxpadding/ * Max padding of 0.25 on y axis * @sample {highstock} stock/xaxis/minpadding-maxpadding/ * Greater min- and maxPadding * @sample {highmaps} maps/chart/plotbackgroundcolor-gradient/ * Add some padding * * @default {highcharts} 0.01 * @default {highstock|highmaps} 0 * @since 1.2.0 */ maxPadding: 0.01, /** * Deprecated. Use `minRange` instead. * * @deprecated * @type {number} * @product highcharts highstock * @apioption xAxis.maxZoom */ /** * The minimum value of the axis. If `null` the min value is * automatically calculated. * * If the [startOnTick](#yAxis.startOnTick) option is true (default), * the `min` value might be rounded down. * * The automatically calculated minimum value is also affected by * [floor](#yAxis.floor), [softMin](#yAxis.softMin), * [minPadding](#yAxis.minPadding), [minRange](#yAxis.minRange) * as well as [series.threshold](#plotOptions.series.threshold) * and [series.softThreshold](#plotOptions.series.softThreshold). * * @sample {highcharts} highcharts/yaxis/min-startontick-false/ * -50 with startOnTick to false * @sample {highcharts} highcharts/yaxis/min-startontick-true/ * -50 with startOnTick true by default * @sample {highstock} stock/xaxis/min-max/ * Set min and max on X axis * @sample {highmaps} maps/axis/min-max/ * Pre-zoomed to a specific area * * @type {number} * @apioption xAxis.min */ /** * The dash or dot style of the minor grid lines. For possible values, * see [this demonstration](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/plotoptions/series-dashstyle-all/). * * @sample {highcharts} highcharts/yaxis/minorgridlinedashstyle/ * Long dashes on minor grid lines * @sample {highstock} stock/xaxis/minorgridlinedashstyle/ * Long dashes on minor grid lines * * @type {Highcharts.DashStyleType} * @default Solid * @since 1.2 * @apioption xAxis.minorGridLineDashStyle */ /** * Specific tick interval in axis units for the minor ticks. On a linear * axis, if `"auto"`, the minor tick interval is calculated as a fifth * of the tickInterval. If `null` or `undefined`, minor ticks are not * shown. * * On logarithmic axes, the unit is the power of the value. For example, * setting the minorTickInterval to 1 puts one tick on each of 0.1, 1, * 10, 100 etc. Setting the minorTickInterval to 0.1 produces 9 ticks * between 1 and 10, 10 and 100 etc. * * If user settings dictate minor ticks to become too dense, they don't * make sense, and will be ignored to prevent performance problems. * * @sample {highcharts} highcharts/yaxis/minortickinterval-null/ * Null by default * @sample {highcharts} highcharts/yaxis/minortickinterval-5/ * 5 units * @sample {highcharts} highcharts/yaxis/minortickinterval-log-auto/ * "auto" * @sample {highcharts} highcharts/yaxis/minortickinterval-log/ * 0.1 * @sample {highstock} stock/demo/basic-line/ * Null by default * @sample {highstock} stock/xaxis/minortickinterval-auto/ * "auto" * * @type {number|string|null} * @apioption xAxis.minorTickInterval */ /** * The pixel length of the minor tick marks. * * @sample {highcharts} highcharts/yaxis/minorticklength/ * 10px on Y axis * @sample {highstock} stock/xaxis/minorticks/ * 10px on Y axis */ minorTickLength: 2, /** * The position of the minor tick marks relative to the axis line. * Can be one of `inside` and `outside`. * * @sample {highcharts} highcharts/yaxis/minortickposition-outside/ * Outside by default * @sample {highcharts} highcharts/yaxis/minortickposition-inside/ * Inside * @sample {highstock} stock/xaxis/minorticks/ * Inside * * @validvalue ["inside", "outside"] */ minorTickPosition: 'outside', /** * Enable or disable minor ticks. Unless * [minorTickInterval](#xAxis.minorTickInterval) is set, the tick * interval is calculated as a fifth of the `tickInterval`. * * On a logarithmic axis, minor ticks are laid out based on a best * guess, attempting to enter approximately 5 minor ticks between * each major tick. * * Prior to v6.0.0, ticks were unabled in auto layout by setting * `minorTickInterval` to `"auto"`. * * @productdesc {highcharts} * On axes using [categories](#xAxis.categories), minor ticks are not * supported. * * @sample {highcharts} highcharts/yaxis/minorticks-true/ * Enabled on linear Y axis * * @type {boolean} * @default false * @since 6.0.0 * @apioption xAxis.minorTicks */ /** * The pixel width of the minor tick mark. * * @sample {highcharts} highcharts/yaxis/minortickwidth/ * 3px width * @sample {highstock} stock/xaxis/minorticks/ * 1px width * * @type {number} * @default 0 * @apioption xAxis.minorTickWidth */ /** * Padding of the min value relative to the length of the axis. A * padding of 0.05 will make a 100px axis 5px longer. This is useful * when you don't want the lowest data value to appear on the edge * of the plot area. When the axis' `min` option is set or a min extreme * is set using `axis.setExtremes()`, the minPadding will be ignored. * * @sample {highcharts} highcharts/yaxis/minpadding/ * Min padding of 0.2 * @sample {highstock} stock/xaxis/minpadding-maxpadding/ * Greater min- and maxPadding * @sample {highmaps} maps/chart/plotbackgroundcolor-gradient/ * Add some padding * * @default {highcharts} 0.01 * @default {highstock|highmaps} 0 * @since 1.2.0 * @product highcharts highstock gantt */ minPadding: 0.01, /** * The minimum range to display on this axis. The entire axis will not * be allowed to span over a smaller interval than this. For example, * for a datetime axis the main unit is milliseconds. If minRange is * set to 3600000, you can't zoom in more than to one hour. * * The default minRange for the x axis is five times the smallest * interval between any of the data points. * * On a logarithmic axis, the unit for the minimum range is the power. * So a minRange of 1 means that the axis can be zoomed to 10-100, * 100-1000, 1000-10000 etc. * * Note that the `minPadding`, `maxPadding`, `startOnTick` and * `endOnTick` settings also affect how the extremes of the axis * are computed. * * @sample {highcharts} highcharts/xaxis/minrange/ * Minimum range of 5 * @sample {highstock} stock/xaxis/minrange/ * Max zoom of 6 months overrides user selections * @sample {highmaps} maps/axis/minrange/ * Minimum range of 1000 * * @type {number} * @apioption xAxis.minRange */ /** * The minimum tick interval allowed in axis values. For example on * zooming in on an axis with daily data, this can be used to prevent * the axis from showing hours. Defaults to the closest distance between * two points on the axis. * * @type {number} * @since 2.3.0 * @apioption xAxis.minTickInterval */ /** * The distance in pixels from the plot area to the axis line. * A positive offset moves the axis with it's line, labels and ticks * away from the plot area. This is typically used when two or more * axes are displayed on the same side of the plot. With multiple * axes the offset is dynamically adjusted to avoid collision, this * can be overridden by setting offset explicitly. * * @sample {highcharts} highcharts/yaxis/offset/ * Y axis offset of 70 * @sample {highcharts} highcharts/yaxis/offset-centered/ * Axes positioned in the center of the plot * @sample {highstock} stock/xaxis/offset/ * Y axis offset by 70 px * * @type {number} * @default 0 * @apioption xAxis.offset */ /** * Whether to display the axis on the opposite side of the normal. The * normal is on the left side for vertical axes and bottom for * horizontal, so the opposite sides will be right and top respectively. * This is typically used with dual or multiple axes. * * @sample {highcharts} highcharts/yaxis/opposite/ * Secondary Y axis opposite * @sample {highstock} stock/xaxis/opposite/ * Y axis on left side * * @type {boolean} * @default false * @apioption xAxis.opposite */ /** * In an ordinal axis, the points are equally spaced in the chart * regardless of the actual time or x distance between them. This means * that missing data periods (e.g. nights or weekends for a stock chart) * will not take up space in the chart. * Having `ordinal: false` will show any gaps created by the `gapSize` * setting proportionate to their duration. * * In stock charts the X axis is ordinal by default, unless * the boost module is used and at least one of the series' data length * exceeds the [boostThreshold](#series.line.boostThreshold). * * @sample {highstock} stock/xaxis/ordinal-true/ * True by default * @sample {highstock} stock/xaxis/ordinal-false/ * False * * @type {boolean} * @default true * @since 1.1 * @product highstock * @apioption xAxis.ordinal */ /** * Additional range on the right side of the xAxis. Works similar to * `xAxis.maxPadding`, but value is set in milliseconds. Can be set for * both main `xAxis` and the navigator's `xAxis`. * * @sample {highstock} stock/xaxis/overscroll/ * One minute overscroll with live data * * @type {number} * @default 0 * @since 6.0.0 * @product highstock * @apioption xAxis.overscroll */ /** * Refers to the index in the [panes](#panes) array. Used for circular * gauges and polar charts. When the option is not set then first pane * will be used. * * @sample highcharts/demo/gauge-vu-meter * Two gauges with different center * * @type {number} * @product highcharts * @apioption xAxis.pane */ /** * The zoomed range to display when only defining one or none of `min` * or `max`. For example, to show the latest month, a range of one month * can be set. * * @sample {highstock} stock/xaxis/range/ * Setting a zoomed range when the rangeSelector is disabled * * @type {number} * @product highstock * @apioption xAxis.range */ /** * Whether to reverse the axis so that the highest number is closest * to the origin. If the chart is inverted, the x axis is reversed by * default. * * @sample {highcharts} highcharts/yaxis/reversed/ * Reversed Y axis * @sample {highstock} stock/xaxis/reversed/ * Reversed Y axis * * @type {boolean} * @default false * @apioption xAxis.reversed */ // reversed: false, /** * This option determines how stacks should be ordered within a group. * For example reversed xAxis also reverses stacks, so first series * comes last in a group. To keep order like for non-reversed xAxis * enable this option. * * @sample {highcharts} highcharts/xaxis/reversedstacks/ * Reversed stacks comparison * @sample {highstock} highcharts/xaxis/reversedstacks/ * Reversed stacks comparison * * @type {boolean} * @default false * @since 6.1.1 * @product highcharts highstock * @apioption xAxis.reversedStacks */ /** * An optional scrollbar to display on the X axis in response to * limiting the minimum and maximum of the axis values. * * In styled mode, all the presentational options for the scrollbar are * replaced by the classes `.highcharts-scrollbar-thumb`, * `.highcharts-scrollbar-arrow`, `.highcharts-scrollbar-button`, * `.highcharts-scrollbar-rifles` and `.highcharts-scrollbar-track`. * * @sample {highstock} stock/yaxis/heatmap-scrollbars/ * Heatmap with both scrollbars * * @extends scrollbar * @since 4.2.6 * @product highstock * @apioption xAxis.scrollbar */ /** * Whether to show the axis line and title when the axis has no data. * * @sample {highcharts} highcharts/yaxis/showempty/ * When clicking the legend to hide series, one axis preserves * line and title, the other doesn't * @sample {highstock} highcharts/yaxis/showempty/ * When clicking the legend to hide series, one axis preserves * line and title, the other doesn't * * @type {boolean} * @default true * @since 1.1 * @apioption xAxis.showEmpty */ /** * Whether to show the first tick label. * * @sample {highcharts} highcharts/xaxis/showfirstlabel-false/ * Set to false on X axis * @sample {highstock} stock/xaxis/showfirstlabel/ * Labels below plot lines on Y axis * * @type {boolean} * @default true * @apioption xAxis.showFirstLabel */ /** * Whether to show the last tick label. Defaults to `true` on cartesian * charts, and `false` on polar charts. * * @sample {highcharts} highcharts/xaxis/showlastlabel-true/ * Set to true on X axis * @sample {highstock} stock/xaxis/showfirstlabel/ * Labels below plot lines on Y axis * * @type {boolean} * @default true * @product highcharts highstock gantt * @apioption xAxis.showLastLabel */ /** * A soft maximum for the axis. If the series data maximum is less than * this, the axis will stay at this maximum, but if the series data * maximum is higher, the axis will flex to show all data. * * @sample highcharts/yaxis/softmin-softmax/ * Soft min and max * * @type {number} * @since 5.0.1 * @product highcharts highstock gantt * @apioption xAxis.softMax */ /** * A soft minimum for the axis. If the series data minimum is greater * than this, the axis will stay at this minimum, but if the series * data minimum is lower, the axis will flex to show all data. * * @sample highcharts/yaxis/softmin-softmax/ * Soft min and max * * @type {number} * @since 5.0.1 * @product highcharts highstock gantt * @apioption xAxis.softMin */ /** * For datetime axes, this decides where to put the tick between weeks. * 0 = Sunday, 1 = Monday. * * @sample {highcharts} highcharts/xaxis/startofweek-monday/ * Monday by default * @sample {highcharts} highcharts/xaxis/startofweek-sunday/ * Sunday * @sample {highstock} stock/xaxis/startofweek-1 * Monday by default * @sample {highstock} stock/xaxis/startofweek-0 * Sunday * * @product highcharts highstock gantt */ startOfWeek: 1, /** * Whether to force the axis to start on a tick. Use this option with * the `minPadding` option to control the axis start. * * @productdesc {highstock} * In Highstock, `startOnTick` is always false when the navigator is * enabled, to prevent jumpy scrolling. * * @sample {highcharts} highcharts/xaxis/startontick-false/ * False by default * @sample {highcharts} highcharts/xaxis/startontick-true/ * True * @sample {highstock} stock/xaxis/endontick/ * False for Y axis * * @since 1.2.0 */ startOnTick: false, /** * The amount of ticks to draw on the axis. This opens up for aligning * the ticks of multiple charts or panes within a chart. This option * overrides the `tickPixelInterval` option. * * This option only has an effect on linear axes. Datetime, logarithmic * or category axes are not affected. * * @sample {highcharts} highcharts/yaxis/tickamount/ * 8 ticks on Y axis * @sample {highstock} highcharts/yaxis/tickamount/ * 8 ticks on Y axis * * @type {number} * @since 4.1.0 * @product highcharts highstock gantt * @apioption xAxis.tickAmount */ /** * The interval of the tick marks in axis units. When `undefined`, the * tick interval is computed to approximately follow the * [tickPixelInterval](#xAxis.tickPixelInterval) on linear and datetime * axes. On categorized axes, a `undefined` tickInterval will default to * 1, one category. Note that datetime axes are based on milliseconds, * so for example an interval of one day is expressed as * `24 * 3600 * 1000`. * * On logarithmic axes, the tickInterval is based on powers, so a * tickInterval of 1 means one tick on each of 0.1, 1, 10, 100 etc. A * tickInterval of 2 means a tick of 0.1, 10, 1000 etc. A tickInterval * of 0.2 puts a tick on 0.1, 0.2, 0.4, 0.6, 0.8, 1, 2, 4, 6, 8, 10, 20, * 40 etc. * * * If the tickInterval is too dense for labels to be drawn, Highcharts * may remove ticks. * * If the chart has multiple axes, the [alignTicks](#chart.alignTicks) * option may interfere with the `tickInterval` setting. * * @see [tickPixelInterval](#xAxis.tickPixelInterval) * @see [tickPositions](#xAxis.tickPositions) * @see [tickPositioner](#xAxis.tickPositioner) * * @sample {highcharts} highcharts/xaxis/tickinterval-5/ * Tick interval of 5 on a linear axis * @sample {highstock} stock/xaxis/tickinterval/ * Tick interval of 0.01 on Y axis * * @type {number} * @apioption xAxis.tickInterval */ /** * The pixel length of the main tick marks. * * @sample {highcharts} highcharts/xaxis/ticklength/ * 20 px tick length on the X axis * @sample {highstock} stock/xaxis/ticks/ * Formatted ticks on X axis */ tickLength: 10, /** * If tickInterval is `null` this option sets the approximate pixel * interval of the tick marks. Not applicable to categorized axis. * * The tick interval is also influenced by the [minTickInterval]( * #xAxis.minTickInterval) option, that, by default prevents ticks from * being denser than the data points. * * @see [tickInterval](#xAxis.tickInterval) * @see [tickPositioner](#xAxis.tickPositioner) * @see [tickPositions](#xAxis.tickPositions) * * @sample {highcharts} highcharts/xaxis/tickpixelinterval-50/ * 50 px on X axis * @sample {highstock} stock/xaxis/tickpixelinterval/ * 200 px on X axis */ tickPixelInterval: 100, /** * For categorized axes only. If `on` the tick mark is placed in the * center of the category, if `between` the tick mark is placed between * categories. The default is `between` if the `tickInterval` is 1, else * `on`. * * @sample {highcharts} highcharts/xaxis/tickmarkplacement-between/ * "between" by default * @sample {highcharts} highcharts/xaxis/tickmarkplacement-on/ * "on" * * @product highcharts gantt * @validvalue ["on", "between"] */ tickmarkPlacement: 'between', /** * The position of the major tick marks relative to the axis line. * Can be one of `inside` and `outside`. * * @sample {highcharts} highcharts/xaxis/tickposition-outside/ * "outside" by default * @sample {highcharts} highcharts/xaxis/tickposition-inside/ * "inside" * @sample {highstock} stock/xaxis/ticks/ * Formatted ticks on X axis * * @validvalue ["inside", "outside"] */ tickPosition: 'outside', /** * A callback function returning array defining where the ticks are * laid out on the axis. This overrides the default behaviour of * [tickPixelInterval](#xAxis.tickPixelInterval) and [tickInterval]( * #xAxis.tickInterval). The automatic tick positions are accessible * through `this.tickPositions` and can be modified by the callback. * * @see [tickPositions](#xAxis.tickPositions) * * @sample {highcharts} highcharts/xaxis/tickpositions-tickpositioner/ * Demo of tickPositions and tickPositioner * @sample {highstock} highcharts/xaxis/tickpositions-tickpositioner/ * Demo of tickPositions and tickPositioner * * @type {Highcharts.AxisTickPositionerCallbackFunction} * @apioption xAxis.tickPositioner */ /** * An array defining where the ticks are laid out on the axis. This * overrides the default behaviour of [tickPixelInterval]( * #xAxis.tickPixelInterval) and [tickInterval](#xAxis.tickInterval). * * @see [tickPositioner](#xAxis.tickPositioner) * * @sample {highcharts} highcharts/xaxis/tickpositions-tickpositioner/ * Demo of tickPositions and tickPositioner * @sample {highstock} highcharts/xaxis/tickpositions-tickpositioner/ * Demo of tickPositions and tickPositioner * * @type {Array} * @apioption xAxis.tickPositions */ /** * The pixel width of the major tick marks. * * In styled mode, the stroke width is given in the `.highcharts-tick` * class. * * @sample {highcharts} highcharts/xaxis/tickwidth/ * 10 px width * @sample {highcharts} highcharts/css/axis-grid/ * Styled mode * @sample {highstock} stock/xaxis/ticks/ * Formatted ticks on X axis * @sample {highstock} highcharts/css/axis-grid/ * Styled mode * * @type {number} * @default {highcharts} 1 * @default {highstock} 1 * @default {highmaps} 0 * @apioption xAxis.tickWidth */ /** * The axis title, showing next to the axis line. * * @productdesc {highmaps} * In Highmaps, the axis is hidden by default, but adding an axis title * is still possible. X axis and Y axis titles will appear at the bottom * and left by default. */ title: { /** * Deprecated. Set the `text` to `null` to disable the title. * * @deprecated * @type {string} * @default middle * @product highcharts * @apioption xAxis.title.enabled */ /** * The pixel distance between the axis labels or line and the title. * Defaults to 0 for horizontal axes, 10 for vertical * * @sample {highcharts} highcharts/xaxis/title-margin/ * Y axis title margin of 60 * * @type {number} * @apioption xAxis.title.margin */ /** * The distance of the axis title from the axis line. By default, * this distance is computed from the offset width of the labels, * the labels' distance from the axis and the title's margin. * However when the offset option is set, it overrides all this. * * @sample {highcharts} highcharts/yaxis/title-offset/ * Place the axis title on top of the axis * @sample {highstock} highcharts/yaxis/title-offset/ * Place the axis title on top of the Y axis * * @type {number} * @since 2.2.0 * @apioption xAxis.title.offset */ /** * Whether to reserve space for the title when laying out the axis. * * @type {boolean} * @default true * @since 5.0.11 * @product highcharts highstock gantt * @apioption xAxis.title.reserveSpace */ /** * The rotation of the text in degrees. 0 is horizontal, 270 is * vertical reading from bottom to top. * * @sample {highcharts} highcharts/yaxis/title-offset/ * Horizontal * * @type {number} * @default 0 * @apioption xAxis.title.rotation */ /** * The actual text of the axis title. It can contain basic HTML text * markup like , and spans with style. * * @sample {highcharts} highcharts/xaxis/title-text/ * Custom HTML * @sample {highstock} stock/xaxis/title-text/ * Titles for both axes * * @type {string|null} * @apioption xAxis.title.text */ /** * Alignment of the text, can be `"left"`, `"right"` or `"center"`. * Default alignment depends on the * [title.align](xAxis.title.align): * * Horizontal axes: * - for `align` = `"low"`, `textAlign` is set to `left` * - for `align` = `"middle"`, `textAlign` is set to `center` * - for `align` = `"high"`, `textAlign` is set to `right` * * Vertical axes: * - for `align` = `"low"` and `opposite` = `true`, `textAlign` is * set to `right` * - for `align` = `"low"` and `opposite` = `false`, `textAlign` is * set to `left` * - for `align` = `"middle"`, `textAlign` is set to `center` * - for `align` = `"high"` and `opposite` = `true` `textAlign` is * set to `left` * - for `align` = `"high"` and `opposite` = `false` `textAlign` is * set to `right` * * @type {string} * @apioption xAxis.title.textAlign */ /** * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html) * to render the axis title. * * @type {boolean} * @default false * @product highcharts highstock gantt * @apioption xAxis.title.useHTML */ /** * Horizontal pixel offset of the title position. * * @type {number} * @default 0 * @since 4.1.6 * @product highcharts highstock gantt * @apioption xAxis.title.x */ /** * Vertical pixel offset of the title position. * * @type {number} * @product highcharts highstock gantt * @apioption xAxis.title.y */ /** * Alignment of the title relative to the axis values. Possible * values are "low", "middle" or "high". * * @sample {highcharts} highcharts/xaxis/title-align-low/ * "low" * @sample {highcharts} highcharts/xaxis/title-align-center/ * "middle" by default * @sample {highcharts} highcharts/xaxis/title-align-high/ * "high" * @sample {highcharts} highcharts/yaxis/title-offset/ * Place the Y axis title on top of the axis * @sample {highstock} stock/xaxis/title-align/ * Aligned to "high" value * * @validvalue ["low", "middle", "high"] */ align: 'middle', /** * CSS styles for the title. If the title text is longer than the * axis length, it will wrap to multiple lines by default. This can * be customized by setting `textOverflow: 'ellipsis'`, by * setting a specific `width` or by setting `whiteSpace: 'nowrap'`. * * In styled mode, the stroke width is given in the * `.highcharts-axis-title` class. * * @sample {highcharts} highcharts/xaxis/title-style/ * Red * @sample {highcharts} highcharts/css/axis/ * Styled mode * * @type {Highcharts.CSSObject} * @default {"color": "#666666"} */ style: { /** @ignore-option */ color: '#666666' } }, /** * The type of axis. Can be one of `linear`, `logarithmic`, `datetime` * or `category`. In a datetime axis, the numbers are given in * milliseconds, and tick marks are placed on appropriate values like * full hours or days. In a category axis, the * [point names](#series.line.data.name) of the chart's series are used * for categories, if not a [categories](#xAxis.categories) array is * defined. * * @sample {highcharts} highcharts/xaxis/type-linear/ * Linear * @sample {highcharts} highcharts/yaxis/type-log/ * Logarithmic * @sample {highcharts} highcharts/yaxis/type-log-minorgrid/ * Logarithmic with minor grid lines * @sample {highcharts} highcharts/xaxis/type-log-both/ * Logarithmic on two axes * @sample {highcharts} highcharts/yaxis/type-log-negative/ * Logarithmic with extension to emulate negative values * * @product highcharts gantt * @validvalue ["linear", "logarithmic", "datetime", "category"] */ type: 'linear', /** * The type of axis. Can be one of `linear`, `logarithmic`, `datetime`, * `category` or `treegrid`. Defaults to `treegrid` for Gantt charts, * `linear` for other chart types. * * In a datetime axis, the numbers are given in milliseconds, and tick * marks are placed on appropriate values, like full hours or days. In a * category or treegrid axis, the [point names](#series.line.data.name) * of the chart's series are used for categories, if a * [categories](#xAxis.categories) array is not defined. * * @sample {highcharts} highcharts/yaxis/type-log-minorgrid/ * Logarithmic with minor grid lines * @sample {highcharts} highcharts/yaxis/type-log-negative/ * Logarithmic with extension to emulate negative values * @sample {gantt} gantt/treegrid-axis/demo * Treegrid axis * * @default {highcharts} linear * @default {gantt} treegrid * @product highcharts gantt * @validvalue ["linear", "logarithmic", "datetime", "category", * "treegrid"] * @apioption yAxis.type */ /** * Applies only when the axis `type` is `category`. When `uniqueNames` * is true, points are placed on the X axis according to their names. * If the same point name is repeated in the same or another series, * the point is placed on the same X position as other points of the * same name. When `uniqueNames` is false, the points are laid out in * increasing X positions regardless of their names, and the X axis * category will take the name of the last point in each position. * * @sample {highcharts} highcharts/xaxis/uniquenames-true/ * True by default * @sample {highcharts} highcharts/xaxis/uniquenames-false/ * False * * @type {boolean} * @default true * @since 4.2.7 * @product highcharts gantt * @apioption xAxis.uniqueNames */ /** * Datetime axis only. An array determining what time intervals the * ticks are allowed to fall on. Each array item is an array where the * first value is the time unit and the second value another array of * allowed multiples. Defaults to: * *
units: [[
         *     'millisecond', // unit name
         *     [1, 2, 5, 10, 20, 25, 50, 100, 200, 500] // allowed multiples
         * ], [
         *     'second',
         *     [1, 2, 5, 10, 15, 30]
         * ], [
         *     'minute',
         *     [1, 2, 5, 10, 15, 30]
         * ], [
         *     'hour',
         *     [1, 2, 3, 4, 6, 8, 12]
         * ], [
         *     'day',
         *     [1]
         * ], [
         *     'week',
         *     [1]
         * ], [
         *     'month',
         *     [1, 3, 6]
         * ], [
         *     'year',
         *     null
         * ]]
* * @type {Array|null)>>} * @product highcharts highstock gantt * @apioption xAxis.units */ /** * Whether axis, including axis title, line, ticks and labels, should * be visible. * * @type {boolean} * @default true * @since 4.1.9 * @product highcharts highstock gantt * @apioption xAxis.visible */ /** * Color of the minor, secondary grid lines. * * In styled mode, the stroke width is given in the * `.highcharts-minor-grid-line` class. * * @sample {highcharts} highcharts/yaxis/minorgridlinecolor/ * Bright grey lines from Y axis * @sample {highcharts|highstock} highcharts/css/axis-grid/ * Styled mode * @sample {highstock} stock/xaxis/minorgridlinecolor/ * Bright grey lines from Y axis * * @type {Highcharts.ColorString} * @default #f2f2f2 */ minorGridLineColor: '#f2f2f2', /** * Width of the minor, secondary grid lines. * * In styled mode, the stroke width is given in the * `.highcharts-grid-line` class. * * @sample {highcharts} highcharts/yaxis/minorgridlinewidth/ * 2px lines from Y axis * @sample {highcharts|highstock} highcharts/css/axis-grid/ * Styled mode * @sample {highstock} stock/xaxis/minorgridlinewidth/ * 2px lines from Y axis */ minorGridLineWidth: 1, /** * Color for the minor tick marks. * * @sample {highcharts} highcharts/yaxis/minortickcolor/ * Black tick marks on Y axis * @sample {highstock} stock/xaxis/minorticks/ * Black tick marks on Y axis * * @type {Highcharts.ColorString} * @default #999999 */ minorTickColor: '#999999', /** * The color of the line marking the axis itself. * * In styled mode, the line stroke is given in the * `.highcharts-axis-line` or `.highcharts-xaxis-line` class. * * @productdesc {highmaps} * In Highmaps, the axis line is hidden by default, because the axis is * not visible by default. * * @sample {highcharts} highcharts/yaxis/linecolor/ * A red line on Y axis * @sample {highcharts|highstock} highcharts/css/axis/ * Axes in styled mode * @sample {highstock} stock/xaxis/linecolor/ * A red line on X axis * * @type {Highcharts.ColorString} * @default #ccd6eb */ lineColor: '#ccd6eb', /** * The width of the line marking the axis itself. * * In styled mode, the stroke width is given in the * `.highcharts-axis-line` or `.highcharts-xaxis-line` class. * * @sample {highcharts} highcharts/yaxis/linecolor/ * A 1px line on Y axis * @sample {highcharts|highstock} highcharts/css/axis/ * Axes in styled mode * @sample {highstock} stock/xaxis/linewidth/ * A 2px line on X axis * * @default {highcharts|highstock} 1 * @default {highmaps} 0 */ lineWidth: 1, /** * Color of the grid lines extending the ticks across the plot area. * * In styled mode, the stroke is given in the `.highcharts-grid-line` * class. * * @productdesc {highmaps} * In Highmaps, the grid lines are hidden by default. * * @sample {highcharts} highcharts/yaxis/gridlinecolor/ * Green lines * @sample {highcharts|highstock} highcharts/css/axis-grid/ * Styled mode * @sample {highstock} stock/xaxis/gridlinecolor/ * Green lines * * @type {Highcharts.ColorString} * @default #e6e6e6 */ gridLineColor: '#e6e6e6', // gridLineDashStyle: 'solid', /** * The width of the grid lines extending the ticks across the plot area. * * In styled mode, the stroke width is given in the * `.highcharts-grid-line` class. * * @sample {highcharts} highcharts/yaxis/gridlinewidth/ * 2px lines * @sample {highcharts|highstock} highcharts/css/axis-grid/ * Styled mode * @sample {highstock} stock/xaxis/gridlinewidth/ * 2px lines * * @type {number} * @default 0 * @apioption xAxis.gridLineWidth */ // gridLineWidth: 0, /** * Color for the main tick marks. * * In styled mode, the stroke is given in the `.highcharts-tick` * class. * * @sample {highcharts} highcharts/xaxis/tickcolor/ * Red ticks on X axis * @sample {highcharts|highstock} highcharts/css/axis-grid/ * Styled mode * @sample {highstock} stock/xaxis/ticks/ * Formatted ticks on X axis * * @type {Highcharts.ColorString} * @default #ccd6eb */ tickColor: '#ccd6eb' // tickWidth: 1 }, /** * The Y axis or value axis. Normally this is the vertical axis, * though if the chart is inverted this is the horizontal axis. * In case of multiple axes, the yAxis node is an array of * configuration objects. * * See [the Axis object](/class-reference/Highcharts.Axis) for programmatic * access to the axis. * * @type {*|Array<*>} * @extends xAxis * @excluding ordinal,overscroll,currentDateIndicator * @optionparent yAxis */ defaultYAxisOptions: { /** * In a polar chart, this is the angle of the Y axis in degrees, where * 0 is up and 90 is right. The angle determines the position of the * axis line and the labels, though the coordinate system is unaffected. * * @sample {highcharts} highcharts/yaxis/angle/ * Dual axis polar chart * * @type {number} * @default 0 * @since 4.2.7 * @product highcharts * @apioption yAxis.angle */ /** * Polar charts only. Whether the grid lines should draw as a polygon * with straight lines between categories, or as circles. Can be either * `circle` or `polygon`. * * @sample {highcharts} highcharts/demo/polar-spider/ * Polygon grid lines * @sample {highcharts} highcharts/yaxis/gridlineinterpolation/ * Circle and polygon * * @type {string} * @product highcharts * @validvalue ["circle", "polygon"] * @apioption yAxis.gridLineInterpolation */ /** * The height of the Y axis. If it's a number, it is interpreted as * pixels. * * Since Highstock 2: If it's a percentage string, it is interpreted * as percentages of the total plot height. * * @see [yAxis.top](#yAxis.top) * * @sample {highstock} stock/demo/candlestick-and-volume/ * Percentage height panes * * @type {number|string} * @product highstock * @apioption yAxis.height */ /** * Solid gauge only. Unless [stops](#yAxis.stops) are set, the color * to represent the maximum value of the Y axis. * * @sample {highcharts} highcharts/yaxis/mincolor-maxcolor/ * Min and max colors * * @type {Highcharts.ColorString} * @default #003399 * @since 4.0 * @product highcharts * @apioption yAxis.maxColor */ /** * Solid gauge only. Unless [stops](#yAxis.stops) are set, the color * to represent the minimum value of the Y axis. * * @sample {highcharts} highcharts/yaxis/mincolor-maxcolor/ * Min and max color * * @type {Highcharts.ColorString} * @default #e6ebf5 * @since 4.0 * @product highcharts * @apioption yAxis.minColor */ /** * Whether to reverse the axis so that the highest number is closest * to the origin. * * @sample {highcharts} highcharts/yaxis/reversed/ * Reversed Y axis * @sample {highstock} stock/xaxis/reversed/ * Reversed Y axis * * @type {boolean} * @default {highcharts} false * @default {highstock} false * @default {highmaps} true * @default {gantt} true * @apioption yAxis.reversed */ /** * If `true`, the first series in a stack will be drawn on top in a * positive, non-reversed Y axis. If `false`, the first series is in * the base of the stack. * * @sample {highcharts} highcharts/yaxis/reversedstacks-false/ * Non-reversed stacks * @sample {highstock} highcharts/yaxis/reversedstacks-false/ * Non-reversed stacks * * @type {boolean} * @default true * @since 3.0.10 * @product highcharts highstock * @apioption yAxis.reversedStacks */ /** * Solid gauge series only. Color stops for the solid gauge. Use this * in cases where a linear gradient between a `minColor` and `maxColor` * is not sufficient. The stops is an array of tuples, where the first * item is a float between 0 and 1 assigning the relative position in * the gradient, and the second item is the color. * * For solid gauges, the Y axis also inherits the concept of * [data classes](http://api.highcharts.com/highmaps#colorAxis.dataClasses) * from the Highmaps color axis. * * @see [minColor](#yAxis.minColor) * @see [maxColor](#yAxis.maxColor) * * @sample {highcharts} highcharts/demo/gauge-solid/ * True by default * * @type {Array>} * @since 4.0 * @product highcharts * @apioption yAxis.stops */ /** * The pixel width of the major tick marks. * * @sample {highcharts} highcharts/xaxis/tickwidth/ 10 px width * @sample {highstock} stock/xaxis/ticks/ Formatted ticks on X axis * * @type {number} * @default 0 * @product highcharts highstock gantt * @apioption yAxis.tickWidth */ /** * Angular gauges and solid gauges only. The label's pixel distance * from the perimeter of the plot area. * * @type {number} * @default -25 * @product highcharts * @apioption yAxis.labels.distance */ /** * The y position offset of the label relative to the tick position * on the axis. * * @sample {highcharts} highcharts/xaxis/labels-x/ * Y axis labels placed on grid lines * * @type {number} * @default {highcharts} 3 * @default {highstock} -2 * @default {highmaps} 3 * @apioption yAxis.labels.y */ /** * @productdesc {highstock} * In Highstock, `endOnTick` is always false when the navigator is * enabled, to prevent jumpy scrolling. */ endOnTick: true, /** * Padding of the max value relative to the length of the axis. A * padding of 0.05 will make a 100px axis 5px longer. This is useful * when you don't want the highest data value to appear on the edge * of the plot area. When the axis' `max` option is set or a max extreme * is set using `axis.setExtremes()`, the maxPadding will be ignored. * * @sample {highcharts} highcharts/yaxis/maxpadding-02/ * Max padding of 0.2 * @sample {highstock} stock/xaxis/minpadding-maxpadding/ * Greater min- and maxPadding * * @since 1.2.0 * @product highcharts highstock gantt */ maxPadding: 0.05, /** * Padding of the min value relative to the length of the axis. A * padding of 0.05 will make a 100px axis 5px longer. This is useful * when you don't want the lowest data value to appear on the edge * of the plot area. When the axis' `min` option is set or a max extreme * is set using `axis.setExtremes()`, the maxPadding will be ignored. * * @sample {highcharts} highcharts/yaxis/minpadding/ * Min padding of 0.2 * @sample {highstock} stock/xaxis/minpadding-maxpadding/ * Greater min- and maxPadding * * @since 1.2.0 * @product highcharts highstock gantt */ minPadding: 0.05, /** * @productdesc {highstock} * In Highstock 1.x, the Y axis was placed on the left side by default. * * @sample {highcharts} highcharts/yaxis/opposite/ * Secondary Y axis opposite * @sample {highstock} stock/xaxis/opposite/ * Y axis on left side * * @type {boolean} * @default {highstock} true * @default {highcharts} false * @product highstock highcharts gantt * @apioption yAxis.opposite */ /** * @see [tickInterval](#xAxis.tickInterval) * @see [tickPositioner](#xAxis.tickPositioner) * @see [tickPositions](#xAxis.tickPositions) */ tickPixelInterval: 72, showLastLabel: true, /** * @extends xAxis.labels */ labels: { /** * What part of the string the given position is anchored to. Can * be one of `"left"`, `"center"` or `"right"`. The exact position * also depends on the `labels.x` setting. * * Angular gauges and solid gauges defaults to `center`. * * @sample {highcharts} highcharts/yaxis/labels-align-left/ * Left * * @type {string} * @default {highcharts|highmaps} right * @default {highstock} left * @validvalue ["left", "center", "right"] * @apioption yAxis.labels.align */ /** * The x position offset of the label relative to the tick position * on the axis. Defaults to -15 for left axis, 15 for right axis. * * @sample {highcharts} highcharts/xaxis/labels-x/ * Y axis labels placed on grid lines */ x: -8 }, /** * @productdesc {highmaps} * In Highmaps, the axis line is hidden by default, because the axis is * not visible by default. * * @type {Highcharts.ColorString} * @apioption yAxis.lineColor */ /** * If there are multiple axes on the same side of the chart, the pixel * margin between the axes. Defaults to 0 on vertical axes, 15 on * horizontal axes. * * @type number * @since 7.0.3 * @apioption xAxis.margin */ /** * @sample {highcharts} highcharts/yaxis/max-200/ * Y axis max of 200 * @sample {highcharts} highcharts/yaxis/max-logarithmic/ * Y axis max on logarithmic axis * @sample {highstock} stock/yaxis/min-max/ * Fixed min and max on Y axis * @sample {highmaps} maps/axis/min-max/ * Pre-zoomed to a specific area * * @type {number} * @apioption yAxis.max */ /** * @sample {highcharts} highcharts/yaxis/min-startontick-false/ * -50 with startOnTick to false * @sample {highcharts} highcharts/yaxis/min-startontick-true/ * -50 with startOnTick true by default * @sample {highstock} stock/yaxis/min-max/ * Fixed min and max on Y axis * @sample {highmaps} maps/axis/min-max/ * Pre-zoomed to a specific area * * @type {number} * @apioption yAxis.min */ /** * An optional scrollbar to display on the Y axis in response to * limiting the minimum an maximum of the axis values. * * In styled mode, all the presentational options for the scrollbar * are replaced by the classes `.highcharts-scrollbar-thumb`, * `.highcharts-scrollbar-arrow`, `.highcharts-scrollbar-button`, * `.highcharts-scrollbar-rifles` and `.highcharts-scrollbar-track`. * * @sample {highstock} stock/yaxis/scrollbar/ * Scrollbar on the Y axis * * @extends scrollbar * @since 4.2.6 * @product highstock * @excluding height * @apioption yAxis.scrollbar */ /** * Enable the scrollbar on the Y axis. * * @sample {highstock} stock/yaxis/scrollbar/ * Enabled on Y axis * * @type {boolean} * @default false * @since 4.2.6 * @product highstock * @apioption yAxis.scrollbar.enabled */ /** * Pixel margin between the scrollbar and the axis elements. * * @type {number} * @default 10 * @since 4.2.6 * @product highstock * @apioption yAxis.scrollbar.margin */ /** * Whether to show the scrollbar when it is fully zoomed out at max * range. Setting it to `false` on the Y axis makes the scrollbar stay * hidden until the user zooms in, like common in browsers. * * @type {boolean} * @default true * @since 4.2.6 * @product highstock * @apioption yAxis.scrollbar.showFull */ /** * The width of a vertical scrollbar or height of a horizontal * scrollbar. Defaults to 20 on touch devices. * * @type {number} * @default 14 * @since 4.2.6 * @product highstock * @apioption yAxis.scrollbar.size */ /** * Z index of the scrollbar elements. * * @type {number} * @default 3 * @since 4.2.6 * @product highstock * @apioption yAxis.scrollbar.zIndex */ /** * A soft maximum for the axis. If the series data maximum is less * than this, the axis will stay at this maximum, but if the series * data maximum is higher, the axis will flex to show all data. * * **Note**: The [series.softThreshold]( * #plotOptions.series.softThreshold) option takes precedence over this * option. * * @sample highcharts/yaxis/softmin-softmax/ * Soft min and max * * @type {number} * @since 5.0.1 * @product highcharts highstock gantt * @apioption yAxis.softMax */ /** * A soft minimum for the axis. If the series data minimum is greater * than this, the axis will stay at this minimum, but if the series * data minimum is lower, the axis will flex to show all data. * * **Note**: The [series.softThreshold]( * #plotOptions.series.softThreshold) option takes precedence over this * option. * * @sample highcharts/yaxis/softmin-softmax/ * Soft min and max * * @type {number} * @since 5.0.1 * @product highcharts highstock gantt * @apioption yAxis.softMin */ /** * Defines the horizontal alignment of the stack total label. Can be one * of `"left"`, `"center"` or `"right"`. The default value is calculated * at runtime and depends on orientation and whether the stack is * positive or negative. * * @sample {highcharts} highcharts/yaxis/stacklabels-align-left/ * Aligned to the left * @sample {highcharts} highcharts/yaxis/stacklabels-align-center/ * Aligned in center * @sample {highcharts} highcharts/yaxis/stacklabels-align-right/ * Aligned to the right * * @type {Highcharts.AlignType} * @since 2.1.5 * @product highcharts * @apioption yAxis.stackLabels.align */ /** * A [format string](http://docs.highcharts.com/#formatting) for the * data label. Available variables are the same as for `formatter`. * * @type {string} * @default {total} * @since 3.0.2 * @product highcharts highstock * @apioption yAxis.stackLabels.format */ /** * Rotation of the labels in degrees. * * @sample {highcharts} highcharts/yaxis/stacklabels-rotation/ * Labels rotated 45° * * @type {number} * @default 0 * @since 2.1.5 * @product highcharts * @apioption yAxis.stackLabels.rotation */ /** * The text alignment for the label. While `align` determines where the * texts anchor point is placed with regards to the stack, `textAlign` * determines how the text is aligned against its anchor point. Possible * values are `"left"`, `"center"` and `"right"`. The default value is * calculated at runtime and depends on orientation and whether the * stack is positive or negative. * * @sample {highcharts} highcharts/yaxis/stacklabels-textalign-left/ * Label in center position but text-aligned left * * @type {Highcharts.AlignType} * @since 2.1.5 * @product highcharts * @apioption yAxis.stackLabels.textAlign */ /** * Whether to [use HTML](https://www.highcharts.com/docs/chart-concepts/labels-and-string-formatting#html) * to render the labels. * * @type {boolean} * @default false * @since 3.0 * @product highcharts highstock * @apioption yAxis.stackLabels.useHTML */ /** * Defines the vertical alignment of the stack total label. Can be one * of `"top"`, `"middle"` or `"bottom"`. The default value is calculated * at runtime and depends on orientation and whether the stack is * positive or negative. * * @sample {highcharts} highcharts/yaxis/stacklabels-verticalalign-top/ * Vertically aligned top * @sample {highcharts} highcharts/yaxis/stacklabels-verticalalign-middle/ * Vertically aligned middle * @sample {highcharts} highcharts/yaxis/stacklabels-verticalalign-bottom/ * Vertically aligned bottom * * @type {Highcharts.VerticalAlignType} * @since 2.1.5 * @product highcharts * @apioption yAxis.stackLabels.verticalAlign */ /** * The x position offset of the label relative to the left of the * stacked bar. The default value is calculated at runtime and depends * on orientation and whether the stack is positive or negative. * * @sample {highcharts} highcharts/yaxis/stacklabels-x/ * Stack total labels with x offset * * @type {number} * @since 2.1.5 * @product highcharts * @apioption yAxis.stackLabels.x */ /** * The y position offset of the label relative to the tick position * on the axis. The default value is calculated at runtime and depends * on orientation and whether the stack is positive or negative. * * @sample {highcharts} highcharts/yaxis/stacklabels-y/ * Stack total labels with y offset * * @type {number} * @since 2.1.5 * @product highcharts * @apioption yAxis.stackLabels.y */ /** * Whether to force the axis to start on a tick. Use this option with * the `maxPadding` option to control the axis start. * * @sample {highcharts} highcharts/xaxis/startontick-false/ * False by default * @sample {highcharts} highcharts/xaxis/startontick-true/ * True * @sample {highstock} stock/xaxis/endontick/ * False for Y axis * * @since 1.2.0 * @product highcharts highstock gantt */ startOnTick: true, title: { /** * The pixel distance between the axis labels and the title. * Positive values are outside the axis line, negative are inside. * * @sample {highcharts} highcharts/xaxis/title-margin/ * Y axis title margin of 60 * * @type {number} * @default 40 * @apioption yAxis.title.margin */ /** * The rotation of the text in degrees. 0 is horizontal, 270 is * vertical reading from bottom to top. * * @sample {highcharts} highcharts/yaxis/title-offset/ * Horizontal */ rotation: 270, /** * The actual text of the axis title. Horizontal texts can contain * HTML, but rotated texts are painted using vector techniques and * must be clean text. The Y axis title is disabled by setting the * `text` option to `undefined`. * * @sample {highcharts} highcharts/xaxis/title-text/ * Custom HTML * * @type {string|null} * @default {highcharts} Values * @default {highstock} undefined * @product highcharts highstock gantt */ text: 'Values' }, /** * The top position of the Y axis. If it's a number, it is interpreted * as pixel position relative to the chart. * * Since Highstock 2: If it's a percentage string, it is interpreted * as percentages of the plot height, offset from plot area top. * * @see [yAxis.height](#yAxis.height) * * @sample {highstock} stock/demo/candlestick-and-volume/ * Percentage height panes * * @type {number|string} * @product highstock * @apioption yAxis.top */ /** * The stack labels show the total value for each bar in a stacked * column or bar chart. The label will be placed on top of positive * columns and below negative columns. In case of an inverted column * chart or a bar chart the label is placed to the right of positive * bars and to the left of negative bars. * * @product highcharts */ stackLabels: { /** * Allow the stack labels to overlap. * * @sample {highcharts} highcharts/yaxis/stacklabels-allowoverlap-false/ * Default false * * @since 5.0.13 * @product highcharts */ allowOverlap: false, /** * Enable or disable the stack total labels. * * @sample {highcharts} highcharts/yaxis/stacklabels-enabled/ * Enabled stack total labels * * @since 2.1.5 * @product highcharts */ enabled: false, /** * Callback JavaScript function to format the label. The value is * given by `this.total`. * * @sample {highcharts} highcharts/yaxis/stacklabels-formatter/ * Added units to stack total value * * @type {Highcharts.FormatterCallbackFunction} * @since 2.1.5 * @product highcharts */ formatter: function () { return H.numberFormat(this.total, -1); }, /** * CSS styles for the label. * * In styled mode, the styles are set in the * `.highcharts-stack-label` class. * * @sample {highcharts} highcharts/yaxis/stacklabels-style/ * Red stack total labels * * @type {Highcharts.CSSObject} * @default {"color": "#666666", "fontSize": "11px", "fontWeight": "bold", "textOutline": "1px contrast"} * @since 2.1.5 * @product highcharts */ style: { /** @ignore-option */ color: '#000000', /** @ignore-option */ fontSize: '11px', /** @ignore-option */ fontWeight: 'bold', /** @ignore-option */ textOutline: '1px contrast' } }, gridLineWidth: 1, lineWidth: 0 // tickWidth: 0 }, /** * The Z axis or depth axis for 3D plots. * * See the [Axis class](/class-reference/Highcharts.Axis) for programmatic * access to the axis. * * @sample {highcharts} highcharts/3d/scatter-zaxis-categories/ * Z-Axis with Categories * @sample {highcharts} highcharts/3d/scatter-zaxis-grid/ * Z-Axis with styling * * @type {*|Array<*>} * @extends xAxis * @since 5.0.0 * @product highcharts * @excluding breaks, crosshair, lineColor, lineWidth, nameToX, showEmpty * @apioption zAxis */ // This variable extends the defaultOptions for left axes. defaultLeftAxisOptions: { labels: { x: -15 }, title: { rotation: 270 } }, // This variable extends the defaultOptions for right axes. defaultRightAxisOptions: { labels: { x: 15 }, title: { rotation: 90 } }, // This variable extends the defaultOptions for bottom axes. defaultBottomAxisOptions: { labels: { autoRotation: [-45], x: 0 // overflow: undefined, // staggerLines: null }, margin: 15, title: { rotation: 0 } }, // This variable extends the defaultOptions for top axes. defaultTopAxisOptions: { labels: { autoRotation: [-45], x: 0 // overflow: undefined // staggerLines: null }, margin: 15, title: { rotation: 0 } }, /** * Overrideable function to initialize the axis. * * @see {@link Axis} * * @function Highcharts.Axis#init * * @param {Highcharts.Chart} chart * * @param {Highcharts.Options} userOptions * * @fires Highcharts.Axis#event:afterInit * @fires Highcharts.Axis#event:init */ init: function (chart, userOptions) { var isXAxis = userOptions.isX, axis = this; /** * The Chart that the axis belongs to. * * @name Highcharts.Axis#chart * @type {Highcharts.Chart} */ axis.chart = chart; /** * Whether the axis is horizontal. * * @name Highcharts.Axis#horiz * @type {boolean} */ axis.horiz = chart.inverted && !axis.isZAxis ? !isXAxis : isXAxis; /** * Whether the axis is the x-axis. * * @name Highcharts.Axis#isXAxis * @type {boolean|undefined} */ axis.isXAxis = isXAxis; /** * The collection where the axis belongs, for example `xAxis`, `yAxis` * or `colorAxis`. Corresponds to properties on Chart, for example * {@link Chart.xAxis}. * * @name Highcharts.Axis#coll * @type {string} */ axis.coll = axis.coll || (isXAxis ? 'xAxis' : 'yAxis'); fireEvent(this, 'init', { userOptions: userOptions }); axis.opposite = userOptions.opposite; // needed in setOptions /** * The side on which the axis is rendered. 0 is top, 1 is right, 2 * is bottom and 3 is left. * * @name Highcharts.Axis#side * @type {number} */ axis.side = userOptions.side || (axis.horiz ? (axis.opposite ? 0 : 2) : // top : bottom (axis.opposite ? 1 : 3)); // right : left axis.setOptions(userOptions); var options = this.options, type = options.type, isDatetimeAxis = type === 'datetime'; axis.labelFormatter = options.labels.formatter || // can be overwritten by dynamic format axis.defaultLabelFormatter; // Flag, stagger lines or not axis.userOptions = userOptions; axis.minPixelPadding = 0; /** * Whether the axis is reversed. Based on the `axis.reversed`, * option, but inverted charts have reversed xAxis by default. * * @name Highcharts.Axis#reversed * @type {boolean} */ axis.reversed = options.reversed; axis.visible = options.visible !== false; axis.zoomEnabled = options.zoomEnabled !== false; // Initial categories axis.hasNames = type === 'category' || options.categories === true; axis.categories = options.categories || axis.hasNames; if (!axis.names) { // Preserve on update (#3830) axis.names = []; axis.names.keys = {}; } // Placeholder for plotlines and plotbands groups axis.plotLinesAndBandsGroups = {}; // Shorthand types axis.isLog = type === 'logarithmic'; axis.isDatetimeAxis = isDatetimeAxis; axis.positiveValuesOnly = axis.isLog && !axis.allowNegativeLog; // Flag, if axis is linked to another axis axis.isLinked = defined(options.linkedTo); /** * List of major ticks mapped by postition on axis. * * @see {@link Highcharts.Tick} * * @private * @name Highcharts.Axis#ticks * @type {Highcharts.Dictionary} */ axis.ticks = {}; axis.labelEdge = []; /** * List of minor ticks mapped by position on the axis. * * @see {@link Highcharts.Tick} * * @private * @name Highcharts.Axis#minorTicks * @type {Highcharts.Dictionary} */ axis.minorTicks = {}; // List of plotLines/Bands axis.plotLinesAndBands = []; // Alternate bands axis.alternateBands = {}; // Axis metrics axis.len = 0; axis.minRange = axis.userMinRange = options.minRange || options.maxZoom; axis.range = options.range; axis.offset = options.offset || 0; // Dictionary for stacks axis.stacks = {}; axis.oldStacks = {}; axis.stacksTouched = 0; /** * The maximum value of the axis. In a logarithmic axis, this is the * logarithm of the real value, and the real value can be obtained from * {@link Axis#getExtremes}. * * @name Highcharts.Axis#max * @type {number|null} */ axis.max = null; /** * The minimum value of the axis. In a logarithmic axis, this is the * logarithm of the real value, and the real value can be obtained from * {@link Axis#getExtremes}. * * @name Highcharts.Axis#min * @type {number|null} */ axis.min = null; /** * The processed crosshair options. * * @name Highcharts.Axis#crosshair * @type {boolean|Highcharts.AxisCrosshairOptions} */ axis.crosshair = pick( options.crosshair, splat(chart.options.tooltip.crosshairs)[isXAxis ? 0 : 1], false ); var events = axis.options.events; // Register. Don't add it again on Axis.update(). if (chart.axes.indexOf(axis) === -1) { // if (isXAxis) { // #2713 chart.axes.splice(chart.xAxis.length, 0, axis); } else { chart.axes.push(axis); } chart[axis.coll].push(axis); } /** * All series associated to the axis. * * @name Highcharts.Axis#series * @type {Array} */ axis.series = axis.series || []; // populated by Series // Reversed axis if ( chart.inverted && !axis.isZAxis && isXAxis && axis.reversed === undefined ) { axis.reversed = true; } // register event listeners objectEach(events, function (event, eventType) { addEvent(axis, eventType, event); }); // extend logarithmic axis axis.lin2log = options.linearToLogConverter || axis.lin2log; if (axis.isLog) { axis.val2lin = axis.log2lin; axis.lin2val = axis.lin2log; } fireEvent(this, 'afterInit'); }, /** * Merge and set options. * * @private * @function Highcharts.Axis#setOptions * * @param {Highcharts.AxisOptions} userOptions * * @fires Highcharts.Axis#event:afterSetOptions */ setOptions: function (userOptions) { this.options = merge( this.defaultOptions, this.coll === 'yAxis' && this.defaultYAxisOptions, [ this.defaultTopAxisOptions, this.defaultRightAxisOptions, this.defaultBottomAxisOptions, this.defaultLeftAxisOptions ][this.side], merge( defaultOptions[this.coll], // if set in setOptions (#1053) userOptions ) ); fireEvent(this, 'afterSetOptions', { userOptions: userOptions }); }, /** * The default label formatter. The context is a special config object for * the label. In apps, use the * [labels.formatter](https://api.highcharts.com/highcharts/xAxis.labels.formatter) * instead except when a modification is needed. * @private */ defaultLabelFormatter: function () { var axis = this.axis, value = this.value, time = axis.chart.time, categories = axis.categories, dateTimeLabelFormat = this.dateTimeLabelFormat, lang = defaultOptions.lang, numericSymbols = lang.numericSymbols, numSymMagnitude = lang.numericSymbolMagnitude || 1000, i = numericSymbols && numericSymbols.length, multi, ret, formatOption = axis.options.labels.format, // make sure the same symbol is added for all labels on a linear // axis numericSymbolDetector = axis.isLog ? Math.abs(value) : axis.tickInterval; if (formatOption) { ret = format(formatOption, this, time); } else if (categories) { ret = value; } else if (dateTimeLabelFormat) { // datetime axis ret = time.dateFormat(dateTimeLabelFormat, value); } else if (i && numericSymbolDetector >= 1000) { // Decide whether we should add a numeric symbol like k (thousands) // or M (millions). If we are to enable this in tooltip or other // places as well, we can move this logic to the numberFormatter and // enable it by a parameter. while (i-- && ret === undefined) { multi = Math.pow(numSymMagnitude, i + 1); if ( // Only accept a numeric symbol when the distance is more // than a full unit. So for example if the symbol is k, we // don't accept numbers like 0.5k. numericSymbolDetector >= multi && // Accept one decimal before the symbol. Accepts 0.5k but // not 0.25k. How does this work with the previous? (value * 10) % multi === 0 && numericSymbols[i] !== null && value !== 0 ) { // #5480 ret = H.numberFormat(value / multi, -1) + numericSymbols[i]; } } } if (ret === undefined) { if (Math.abs(value) >= 10000) { // add thousands separators ret = H.numberFormat(value, -1); } else { // small numbers ret = H.numberFormat(value, -1, undefined, ''); // #2466 } } return ret; }, /** * Get the minimum and maximum for the series of each axis. The function * analyzes the axis series and updates `this.dataMin` and `this.dataMax`. * @private * @fires Highcharts.Axis#event:afterGetSeriesExtremes * @fires Highcharts.Axis#event:getSeriesExtremes */ getSeriesExtremes: function () { var axis = this, chart = axis.chart; fireEvent(this, 'getSeriesExtremes', null, function () { axis.hasVisibleSeries = false; // Reset properties in case we're redrawing (#3353) axis.dataMin = axis.dataMax = axis.threshold = null; axis.softThreshold = !axis.isXAxis; if (axis.buildStacks) { axis.buildStacks(); } // loop through this axis' series axis.series.forEach(function (series) { if (series.visible || !chart.options.chart.ignoreHiddenSeries) { var seriesOptions = series.options, xData, threshold = seriesOptions.threshold, seriesDataMin, seriesDataMax; axis.hasVisibleSeries = true; // Validate threshold in logarithmic axes if (axis.positiveValuesOnly && threshold <= 0) { threshold = null; } // Get dataMin and dataMax for X axes if (axis.isXAxis) { xData = series.xData; if (xData.length) { // If xData contains values which is not numbers, // then filter them out. To prevent performance hit, // we only do this after we have already found // seriesDataMin because in most cases all data is // valid. #5234. seriesDataMin = arrayMin(xData); seriesDataMax = arrayMax(xData); if ( !isNumber(seriesDataMin) && !(seriesDataMin instanceof Date) // #5010 ) { xData = xData.filter(isNumber); // Do it again with valid data seriesDataMin = arrayMin(xData); seriesDataMax = arrayMax(xData); } if (xData.length) { axis.dataMin = Math.min( pick(axis.dataMin, xData[0], seriesDataMin), seriesDataMin ); axis.dataMax = Math.max( pick(axis.dataMax, xData[0], seriesDataMax), seriesDataMax ); } } // Get dataMin and dataMax for Y axes, as well as handle // stacking and processed data } else { // Get this particular series extremes series.getExtremes(); seriesDataMax = series.dataMax; seriesDataMin = series.dataMin; // Get the dataMin and dataMax so far. If percentage is // used, the min and max are always 0 and 100. If // seriesDataMin and seriesDataMax is null, then series // doesn't have active y data, we continue with nulls if (defined(seriesDataMin) && defined(seriesDataMax)) { axis.dataMin = Math.min( pick(axis.dataMin, seriesDataMin), seriesDataMin ); axis.dataMax = Math.max( pick(axis.dataMax, seriesDataMax), seriesDataMax ); } // Adjust to threshold if (defined(threshold)) { axis.threshold = threshold; } // If any series has a hard threshold, it takes // precedence if ( !seriesOptions.softThreshold || axis.positiveValuesOnly ) { axis.softThreshold = false; } } } }); }); fireEvent(this, 'afterGetSeriesExtremes'); }, /** * Translate from axis value to pixel position on the chart, or back. Use * the `toPixels` and `toValue` functions in applications. * @private */ translate: function ( val, backwards, cvsCoord, old, handleLog, pointPlacement ) { var axis = this.linkedParent || this, // #1417 sign = 1, cvsOffset = 0, localA = old ? axis.oldTransA : axis.transA, localMin = old ? axis.oldMin : axis.min, returnValue, minPixelPadding = axis.minPixelPadding, doPostTranslate = ( axis.isOrdinal || axis.isBroken || (axis.isLog && handleLog) ) && axis.lin2val; if (!localA) { localA = axis.transA; } // In vertical axes, the canvas coordinates start from 0 at the top like // in SVG. if (cvsCoord) { sign *= -1; // canvas coordinates inverts the value cvsOffset = axis.len; } // Handle reversed axis if (axis.reversed) { sign *= -1; cvsOffset -= sign * (axis.sector || axis.len); } // From pixels to value if (backwards) { // reverse translation val = val * sign + cvsOffset; val -= minPixelPadding; returnValue = val / localA + localMin; // from chart pixel to value if (doPostTranslate) { // log and ordinal axes returnValue = axis.lin2val(returnValue); } // From value to pixels } else { if (doPostTranslate) { // log and ordinal axes val = axis.val2lin(val); } returnValue = isNumber(localMin) ? ( sign * (val - localMin) * localA + cvsOffset + (sign * minPixelPadding) + (isNumber(pointPlacement) ? localA * pointPlacement : 0) ) : undefined; } return returnValue; }, /** * Translate a value in terms of axis units into pixels within the chart. * * @function Highcharts.Axis#toPixels * * @param {number} value * A value in terms of axis units. * * @param {boolean} paneCoordinates * Whether to return the pixel coordinate relative to the chart or * just the axis/pane itself. * * @return {number} * Pixel position of the value on the chart or axis. */ toPixels: function (value, paneCoordinates) { return this.translate(value, false, !this.horiz, null, true) + (paneCoordinates ? 0 : this.pos); }, /** * Translate a pixel position along the axis to a value in terms of axis * units. * * @function Highcharts.Axis#toValue * * @param {number} pixel * The pixel value coordinate. * * @param {boolean} paneCoordiantes * Whether the input pixel is relative to the chart or just the * axis/pane itself. * * @return {number} * The axis value. */ toValue: function (pixel, paneCoordinates) { return this.translate( pixel - (paneCoordinates ? 0 : this.pos), true, !this.horiz, null, true ); }, /** * Create the path for a plot line that goes from the given value on * this axis, across the plot to the opposite side. Also used internally for * grid lines and crosshairs. * * @function Highcharts.Axis#getPlotLinePath * * @param {number} value * Axis value. * * @param {number} [lineWidth=1] * Used for calculation crisp line coordinates. * * @param {boolean} [old=false] * Use old coordinates (for resizing and rescaling). * * @param {boolean|string} [force=false] * If `false`, the function will return null when it falls outside * the axis bounds. If `true`, the function will return a path * aligned to the plot area sides if it falls outside. If `pass`, it * will return a path outside. * * @param {number} [translatedValue] * If given, return the plot line path of a pixel position on the * axis. * * @return {Array} * The SVG path definition for the plot line. */ getPlotLinePath: function (value, lineWidth, old, force, translatedValue) { var axis = this, chart = axis.chart, axisLeft = axis.left, axisTop = axis.top, x1, y1, x2, y2, cHeight = (old && chart.oldChartHeight) || chart.chartHeight, cWidth = (old && chart.oldChartWidth) || chart.chartWidth, skip, transB = axis.transB, evt, /** * Check if x is between a and b. If not, either move to a/b * or skip, depending on the force parameter. */ between = function (x, a, b) { if (force !== 'pass' && x < a || x > b) { if (force) { x = Math.min(Math.max(a, x), b); } else { skip = true; } } return x; }; evt = { value: value, lineWidth: lineWidth, old: old, force: force, translatedValue: translatedValue }; fireEvent(this, 'getPlotLinePath', evt, function (e) { translatedValue = pick( translatedValue, axis.translate(value, null, null, old) ); // Keep the translated value within sane bounds, and avoid Infinity // to fail the isNumber test (#7709). translatedValue = Math.min(Math.max(-1e5, translatedValue), 1e5); x1 = x2 = Math.round(translatedValue + transB); y1 = y2 = Math.round(cHeight - translatedValue - transB); if (!isNumber(translatedValue)) { // no min or max skip = true; force = false; // #7175, don't force it when path is invalid } else if (axis.horiz) { y1 = axisTop; y2 = cHeight - axis.bottom; x1 = x2 = between(x1, axisLeft, axisLeft + axis.width); } else { x1 = axisLeft; x2 = cWidth - axis.right; y1 = y2 = between(y1, axisTop, axisTop + axis.height); } e.path = skip && !force ? null : chart.renderer.crispLine( ['M', x1, y1, 'L', x2, y2], lineWidth || 1 ); }); return evt.path; }, /** * Internal function to et the tick positions of a linear axis to round * values like whole tens or every five. * * @function Highcharts.Axis#getLinearTickPositions * * @param {number} tickInterval * The normalized tick interval. * * @param {number} min * Axis minimum. * * @param {number} max * Axis maximum. * * @return {Array} * An array of axis values where ticks should be placed. */ getLinearTickPositions: function (tickInterval, min, max) { var pos, lastPos, roundedMin = correctFloat(Math.floor(min / tickInterval) * tickInterval), roundedMax = correctFloat(Math.ceil(max / tickInterval) * tickInterval), tickPositions = [], precision; // When the precision is higher than what we filter out in // correctFloat, skip it (#6183). if (correctFloat(roundedMin + tickInterval) === roundedMin) { precision = 20; } // For single points, add a tick regardless of the relative position // (#2662, #6274) if (this.single) { return [min]; } // Populate the intermediate values pos = roundedMin; while (pos <= roundedMax) { // Place the tick on the rounded value tickPositions.push(pos); // Always add the raw tickInterval, not the corrected one. pos = correctFloat( pos + tickInterval, precision ); // If the interval is not big enough in the current min - max range // to actually increase the loop variable, we need to break out to // prevent endless loop. Issue #619 if (pos === lastPos) { break; } // Record the last value lastPos = pos; } return tickPositions; }, /** * Resolve the new minorTicks/minorTickInterval options into the legacy * loosely typed minorTickInterval option. * * @function Highcharts.Axis#getMinorTickInterval * * @return {number|"auto"|null} */ getMinorTickInterval: function () { var options = this.options; if (options.minorTicks === true) { return pick(options.minorTickInterval, 'auto'); } if (options.minorTicks === false) { return null; } return options.minorTickInterval; }, /** * Internal function to return the minor tick positions. For logarithmic * axes, the same logic as for major ticks is reused. * * @function Highcharts.Axis#getMinorTickPositions * * @return {Array} * An array of axis values where ticks should be placed. */ getMinorTickPositions: function () { var axis = this, options = axis.options, tickPositions = axis.tickPositions, minorTickInterval = axis.minorTickInterval, minorTickPositions = [], pos, pointRangePadding = axis.pointRangePadding || 0, min = axis.min - pointRangePadding, // #1498 max = axis.max + pointRangePadding, // #1498 range = max - min; // If minor ticks get too dense, they are hard to read, and may cause // long running script. So we don't draw them. if (range && range / minorTickInterval < axis.len / 3) { // #3875 if (axis.isLog) { // For each interval in the major ticks, compute the minor ticks // separately. this.paddedTicks.forEach(function (pos, i, paddedTicks) { if (i) { minorTickPositions.push.apply( minorTickPositions, axis.getLogTickPositions( minorTickInterval, paddedTicks[i - 1], paddedTicks[i], true ) ); } }); } else if ( axis.isDatetimeAxis && this.getMinorTickInterval() === 'auto' ) { // #1314 minorTickPositions = minorTickPositions.concat( axis.getTimeTicks( axis.normalizeTimeTickInterval(minorTickInterval), min, max, options.startOfWeek ) ); } else { for ( pos = min + (tickPositions[0] - min) % minorTickInterval; pos <= max; pos += minorTickInterval ) { // Very, very, tight grid lines (#5771) if (pos === minorTickPositions[0]) { break; } minorTickPositions.push(pos); } } } if (minorTickPositions.length !== 0) { axis.trimTicks(minorTickPositions); // #3652 #3743 #1498 #6330 } return minorTickPositions; }, /** * Adjust the min and max for the minimum range. Keep in mind that the * series data is not yet processed, so we don't have information on data * cropping and grouping, or updated `axis.pointRange` or * `series.pointRange`. The data can't be processed until we have finally * established min and max. * @private */ adjustForMinRange: function () { var axis = this, options = axis.options, min = axis.min, max = axis.max, zoomOffset, spaceAvailable, closestDataRange, i, distance, xData, loopLength, minArgs, maxArgs, minRange; // Set the automatic minimum range based on the closest point distance if (axis.isXAxis && axis.minRange === undefined && !axis.isLog) { if (defined(options.min) || defined(options.max)) { axis.minRange = null; // don't do this again } else { // Find the closest distance between raw data points, as opposed // to closestPointRange that applies to processed points // (cropped and grouped) axis.series.forEach(function (series) { xData = series.xData; loopLength = series.xIncrement ? 1 : xData.length - 1; for (i = loopLength; i > 0; i--) { distance = xData[i] - xData[i - 1]; if ( closestDataRange === undefined || distance < closestDataRange ) { closestDataRange = distance; } } }); axis.minRange = Math.min( closestDataRange * 5, axis.dataMax - axis.dataMin ); } } // if minRange is exceeded, adjust if (max - min < axis.minRange) { spaceAvailable = axis.dataMax - axis.dataMin >= axis.minRange; minRange = axis.minRange; zoomOffset = (minRange - max + min) / 2; // if min and max options have been set, don't go beyond it minArgs = [min - zoomOffset, pick(options.min, min - zoomOffset)]; // If space is available, stay within the data range if (spaceAvailable) { minArgs[2] = axis.isLog ? axis.log2lin(axis.dataMin) : axis.dataMin; } min = arrayMax(minArgs); maxArgs = [min + minRange, pick(options.max, min + minRange)]; // If space is availabe, stay within the data range if (spaceAvailable) { maxArgs[2] = axis.isLog ? axis.log2lin(axis.dataMax) : axis.dataMax; } max = arrayMin(maxArgs); // now if the max is adjusted, adjust the min back if (max - min < minRange) { minArgs[0] = max - minRange; minArgs[1] = pick(options.min, max - minRange); min = arrayMax(minArgs); } } // Record modified extremes axis.min = min; axis.max = max; }, // Find the closestPointRange across all series. getClosest: function () { var ret; if (this.categories) { ret = 1; } else { this.series.forEach(function (series) { var seriesClosest = series.closestPointRange, visible = series.visible || !series.chart.options.chart.ignoreHiddenSeries; if ( !series.noSharedTooltip && defined(seriesClosest) && visible ) { ret = defined(ret) ? Math.min(ret, seriesClosest) : seriesClosest; } }); } return ret; }, /** * When a point name is given and no x, search for the name in the existing * categories, or if categories aren't provided, search names or create a * new category (#2522). * @private * @param {Highcharts.Point} point The point to inspect. * @return {number} The X value that the point is given. */ nameToX: function (point) { var explicitCategories = isArray(this.categories), names = explicitCategories ? this.categories : this.names, nameX = point.options.x, x; point.series.requireSorting = false; if (!defined(nameX)) { nameX = this.options.uniqueNames === false ? point.series.autoIncrement() : ( explicitCategories ? names.indexOf(point.name) : pick(names.keys[point.name], -1) ); } if (nameX === -1) { // Not found in currenct categories if (!explicitCategories) { x = names.length; } } else { x = nameX; } // Write the last point's name to the names array if (x !== undefined) { this.names[x] = point.name; // Backwards mapping is much faster than array searching (#7725) this.names.keys[point.name] = x; } return x; }, // When changes have been done to series data, update the axis.names. updateNames: function () { var axis = this, names = this.names, i = names.length; if (i > 0) { Object.keys(names.keys).forEach(function (key) { delete names.keys[key]; }); names.length = 0; this.minRange = this.userMinRange; // Reset (this.series || []).forEach(function (series) { // Reset incrementer (#5928) series.xIncrement = null; // When adding a series, points are not yet generated if (!series.points || series.isDirtyData) { // When we're updating the series with data that is longer // than it was, and cropThreshold is passed, we need to make // sure that the axis.max is increased _before_ running the // premature processData. Otherwise this early iteration of // processData will crop the points to axis.max, and the // names array will be too short (#5857). axis.max = Math.max(axis.max, series.xData.length - 1); series.processData(); series.generatePoints(); } series.data.forEach(function (point, i) { // #9487 var x; if ( point && point.options && point.name !== undefined // #9562 ) { x = axis.nameToX(point); if (x !== undefined && x !== point.x) { point.x = x; series.xData[i] = x; } } }); }); } }, /** * Update translation information. * @private * @param {boolean} saveOld * @fires Highcharts.Axis#event:afterSetAxisTranslation */ setAxisTranslation: function (saveOld) { var axis = this, range = axis.max - axis.min, pointRange = axis.axisPointRange || 0, closestPointRange, minPointOffset = 0, pointRangePadding = 0, linkedParent = axis.linkedParent, ordinalCorrection, hasCategories = !!axis.categories, transA = axis.transA, isXAxis = axis.isXAxis; // Adjust translation for padding. Y axis with categories need to go // through the same (#1784). if (isXAxis || hasCategories || pointRange) { // Get the closest points closestPointRange = axis.getClosest(); if (linkedParent) { minPointOffset = linkedParent.minPointOffset; pointRangePadding = linkedParent.pointRangePadding; } else { axis.series.forEach(function (series) { var seriesPointRange = hasCategories ? 1 : ( isXAxis ? pick( series.options.pointRange, closestPointRange, 0 ) : (axis.axisPointRange || 0) ), // #2806 pointPlacement = series.options.pointPlacement; pointRange = Math.max(pointRange, seriesPointRange); if (!axis.single) { // minPointOffset is the value padding to the left of // the axis in order to make room for points with a // pointRange, typically columns. When the // pointPlacement option is 'between' or 'on', this // padding does not apply. minPointOffset = Math.max( minPointOffset, isXAxis && isString(pointPlacement) ? 0 : seriesPointRange / 2 ); // Determine the total padding needed to the length of // the axis to make room for the pointRange. If the // series' pointPlacement is 'on', no padding is added. pointRangePadding = Math.max( pointRangePadding, isXAxis && pointPlacement === 'on' ? 0 : seriesPointRange ); } }); } // Record minPointOffset and pointRangePadding ordinalCorrection = axis.ordinalSlope && closestPointRange ? axis.ordinalSlope / closestPointRange : 1; // #988, #1853 axis.minPointOffset = minPointOffset = minPointOffset * ordinalCorrection; axis.pointRangePadding = pointRangePadding = pointRangePadding * ordinalCorrection; // pointRange means the width reserved for each point, like in a // column chart axis.pointRange = Math.min(pointRange, range); // closestPointRange means the closest distance between points. In // columns it is mostly equal to pointRange, but in lines pointRange // is 0 while closestPointRange is some other value if (isXAxis) { axis.closestPointRange = closestPointRange; } } // Secondary values if (saveOld) { axis.oldTransA = transA; } axis.translationSlope = axis.transA = transA = axis.staticScale || axis.len / ((range + pointRangePadding) || 1); // Translation addend axis.transB = axis.horiz ? axis.left : axis.bottom; axis.minPixelPadding = transA * minPointOffset; fireEvent(this, 'afterSetAxisTranslation'); }, minFromRange: function () { return this.max - this.range; }, /** * Set the tick positions to round values and optionally extend the extremes * to the nearest tick. * @private * @param {boolean} secondPass * @fires Highcharts.Axis#event:foundExtremes */ setTickInterval: function (secondPass) { var axis = this, chart = axis.chart, options = axis.options, isLog = axis.isLog, isDatetimeAxis = axis.isDatetimeAxis, isXAxis = axis.isXAxis, isLinked = axis.isLinked, maxPadding = options.maxPadding, minPadding = options.minPadding, length, linkedParentExtremes, tickIntervalOption = options.tickInterval, minTickInterval, tickPixelIntervalOption = options.tickPixelInterval, categories = axis.categories, threshold = isNumber(axis.threshold) ? axis.threshold : null, softThreshold = axis.softThreshold, thresholdMin, thresholdMax, hardMin, hardMax; if (!isDatetimeAxis && !categories && !isLinked) { this.getTickAmount(); } // Min or max set either by zooming/setExtremes or initial options hardMin = pick(axis.userMin, options.min); hardMax = pick(axis.userMax, options.max); // Linked axis gets the extremes from the parent axis if (isLinked) { axis.linkedParent = chart[axis.coll][options.linkedTo]; linkedParentExtremes = axis.linkedParent.getExtremes(); axis.min = pick( linkedParentExtremes.min, linkedParentExtremes.dataMin ); axis.max = pick( linkedParentExtremes.max, linkedParentExtremes.dataMax ); if (options.type !== axis.linkedParent.options.type) { H.error(11, 1, chart); // Can't link axes of different type } // Initial min and max from the extreme data values } else { // Adjust to hard threshold if (!softThreshold && defined(threshold)) { if (axis.dataMin >= threshold) { thresholdMin = threshold; minPadding = 0; } else if (axis.dataMax <= threshold) { thresholdMax = threshold; maxPadding = 0; } } axis.min = pick(hardMin, thresholdMin, axis.dataMin); axis.max = pick(hardMax, thresholdMax, axis.dataMax); } if (isLog) { if ( axis.positiveValuesOnly && !secondPass && Math.min(axis.min, pick(axis.dataMin, axis.min)) <= 0 ) { // #978 H.error(10, 1, chart); // Can't plot negative values on log axis } // The correctFloat cures #934, float errors on full tens. But it // was too aggressive for #4360 because of conversion back to lin, // therefore use precision 15. axis.min = correctFloat(axis.log2lin(axis.min), 15); axis.max = correctFloat(axis.log2lin(axis.max), 15); } // handle zoomed range if (axis.range && defined(axis.max)) { axis.userMin = axis.min = hardMin = Math.max(axis.dataMin, axis.minFromRange()); // #618, #6773 axis.userMax = hardMax = axis.max; axis.range = null; // don't use it when running setExtremes } // Hook for Highstock Scroller. Consider combining with beforePadding. fireEvent(axis, 'foundExtremes'); // Hook for adjusting this.min and this.max. Used by bubble series. if (axis.beforePadding) { axis.beforePadding(); } // adjust min and max for the minimum range axis.adjustForMinRange(); // Pad the values to get clear of the chart's edges. To avoid // tickInterval taking the padding into account, we do this after // computing tick interval (#1337). if ( !categories && !axis.axisPointRange && !axis.usePercentage && !isLinked && defined(axis.min) && defined(axis.max) ) { length = axis.max - axis.min; if (length) { if (!defined(hardMin) && minPadding) { axis.min -= length * minPadding; } if (!defined(hardMax) && maxPadding) { axis.max += length * maxPadding; } } } // Handle options for floor, ceiling, softMin and softMax (#6359) if (isNumber(options.softMin) && !isNumber(axis.userMin)) { axis.min = Math.min(axis.min, options.softMin); } if (isNumber(options.softMax) && !isNumber(axis.userMax)) { axis.max = Math.max(axis.max, options.softMax); } if (isNumber(options.floor)) { axis.min = Math.min( Math.max(axis.min, options.floor), Number.MAX_VALUE ); } if (isNumber(options.ceiling)) { axis.max = Math.max( Math.min(axis.max, options.ceiling), pick(axis.userMax, -Number.MAX_VALUE) ); } // When the threshold is soft, adjust the extreme value only if the data // extreme and the padded extreme land on either side of the threshold. // For example, a series of [0, 1, 2, 3] would make the yAxis add a tick // for -1 because of the default minPadding and startOnTick options. // This is prevented by the softThreshold option. if (softThreshold && defined(axis.dataMin)) { threshold = threshold || 0; if ( !defined(hardMin) && axis.min < threshold && axis.dataMin >= threshold ) { axis.min = threshold; } else if ( !defined(hardMax) && axis.max > threshold && axis.dataMax <= threshold ) { axis.max = threshold; } } // get tickInterval if ( axis.min === axis.max || axis.min === undefined || axis.max === undefined ) { axis.tickInterval = 1; } else if ( isLinked && !tickIntervalOption && tickPixelIntervalOption === axis.linkedParent.options.tickPixelInterval ) { axis.tickInterval = tickIntervalOption = axis.linkedParent.tickInterval; } else { axis.tickInterval = pick( tickIntervalOption, this.tickAmount ? ((axis.max - axis.min) / Math.max(this.tickAmount - 1, 1)) : undefined, // For categoried axis, 1 is default, for linear axis use // tickPix categories ? 1 : // don't let it be more than the data range (axis.max - axis.min) * tickPixelIntervalOption / Math.max(axis.len, tickPixelIntervalOption) ); } // Now we're finished detecting min and max, crop and group series data. // This is in turn needed in order to find tick positions in ordinal // axes. if (isXAxis && !secondPass) { axis.series.forEach(function (series) { series.processData( axis.min !== axis.oldMin || axis.max !== axis.oldMax ); }); } // set the translation factor used in translate function axis.setAxisTranslation(true); // hook for ordinal axes and radial axes if (axis.beforeSetTickPositions) { axis.beforeSetTickPositions(); } // hook for extensions, used in Highstock ordinal axes if (axis.postProcessTickInterval) { axis.tickInterval = axis.postProcessTickInterval(axis.tickInterval); } // In column-like charts, don't cramp in more ticks than there are // points (#1943, #4184) if (axis.pointRange && !tickIntervalOption) { axis.tickInterval = Math.max(axis.pointRange, axis.tickInterval); } // Before normalizing the tick interval, handle minimum tick interval. // This applies only if tickInterval is not defined. minTickInterval = pick( options.minTickInterval, axis.isDatetimeAxis && axis.closestPointRange ); if (!tickIntervalOption && axis.tickInterval < minTickInterval) { axis.tickInterval = minTickInterval; } // for linear axes, get magnitude and normalize the interval if (!isDatetimeAxis && !isLog && !tickIntervalOption) { axis.tickInterval = normalizeTickInterval( axis.tickInterval, null, getMagnitude(axis.tickInterval), // If the tick interval is between 0.5 and 5 and the axis max is // in the order of thousands, chances are we are dealing with // years. Don't allow decimals. #3363. pick( options.allowDecimals, !( axis.tickInterval > 0.5 && axis.tickInterval < 5 && axis.max > 1000 && axis.max < 9999 ) ), !!this.tickAmount ); } // Prevent ticks from getting so close that we can't draw the labels if (!this.tickAmount) { axis.tickInterval = axis.unsquish(); } this.setTickPositions(); }, /** * Now we have computed the normalized tickInterval, get the tick positions * * @function Highcharts.Axis#setTickPositions * * @fires Highcharts.Axis#event:afterSetTickPositions */ setTickPositions: function () { var options = this.options, tickPositions, tickPositionsOption = options.tickPositions, minorTickIntervalOption = this.getMinorTickInterval(), tickPositioner = options.tickPositioner, startOnTick = options.startOnTick, endOnTick = options.endOnTick; // Set the tickmarkOffset this.tickmarkOffset = ( this.categories && options.tickmarkPlacement === 'between' && this.tickInterval === 1 ) ? 0.5 : 0; // #3202 // get minorTickInterval this.minorTickInterval = minorTickIntervalOption === 'auto' && this.tickInterval ? this.tickInterval / 5 : minorTickIntervalOption; // When there is only one point, or all points have the same value on // this axis, then min and max are equal and tickPositions.length is 0 // or 1. In this case, add some padding in order to center the point, // but leave it with one tick. #1337. this.single = this.min === this.max && defined(this.min) && !this.tickAmount && ( // Data is on integer (#6563) parseInt(this.min, 10) === this.min || // Between integers and decimals are not allowed (#6274) options.allowDecimals !== false ); // Find the tick positions. Work on a copy (#1565) this.tickPositions = tickPositions = tickPositionsOption && tickPositionsOption.slice(); if (!tickPositions) { // Too many ticks (#6405). Create a friendly warning and provide two // ticks so at least we can show the data series. if ( !this.ordinalPositions && ( (this.max - this.min) / this.tickInterval > Math.max(2 * this.len, 200) ) ) { tickPositions = [this.min, this.max]; H.error(19, false, this.chart); } else if (this.isDatetimeAxis) { tickPositions = this.getTimeTicks( this.normalizeTimeTickInterval( this.tickInterval, options.units ), this.min, this.max, options.startOfWeek, this.ordinalPositions, this.closestPointRange, true ); } else if (this.isLog) { tickPositions = this.getLogTickPositions( this.tickInterval, this.min, this.max ); } else { tickPositions = this.getLinearTickPositions( this.tickInterval, this.min, this.max ); } // Too dense ticks, keep only the first and last (#4477) if (tickPositions.length > this.len) { tickPositions = [tickPositions[0], tickPositions.pop()]; // Reduce doubled value (#7339) if (tickPositions[0] === tickPositions[1]) { tickPositions.length = 1; } } this.tickPositions = tickPositions; // Run the tick positioner callback, that allows modifying auto tick // positions. if (tickPositioner) { tickPositioner = tickPositioner.apply( this, [this.min, this.max] ); if (tickPositioner) { this.tickPositions = tickPositions = tickPositioner; } } } // Reset min/max or remove extremes based on start/end on tick this.paddedTicks = tickPositions.slice(0); // Used for logarithmic minor this.trimTicks(tickPositions, startOnTick, endOnTick); if (!this.isLinked) { // Substract half a unit (#2619, #2846, #2515, #3390), // but not in case of multiple ticks (#6897) if (this.single && tickPositions.length < 2) { this.min -= 0.5; this.max += 0.5; } if (!tickPositionsOption && !tickPositioner) { this.adjustTickAmount(); } } fireEvent(this, 'afterSetTickPositions'); }, // Handle startOnTick and endOnTick by either adapting to padding min/max or // rounded min/max. Also handle single data points. trimTicks: function (tickPositions, startOnTick, endOnTick) { var roundedMin = tickPositions[0], roundedMax = tickPositions[tickPositions.length - 1], minPointOffset = this.minPointOffset || 0; fireEvent(this, 'trimTicks'); if (!this.isLinked) { if (startOnTick && roundedMin !== -Infinity) { // #6502 this.min = roundedMin; } else { while (this.min - minPointOffset > tickPositions[0]) { tickPositions.shift(); } } if (endOnTick) { this.max = roundedMax; } else { while (this.max + minPointOffset < tickPositions[tickPositions.length - 1]) { tickPositions.pop(); } } // If no tick are left, set one tick in the middle (#3195) if ( tickPositions.length === 0 && defined(roundedMin) && !this.options.tickPositions ) { tickPositions.push((roundedMax + roundedMin) / 2); } } }, /** * Check if there are multiple axes in the same pane. * @private * @return {boolean} True if there are other axes. */ alignToOthers: function () { var others = {}, // Whether there is another axis to pair with this one hasOther, options = this.options; if ( // Only if alignTicks is true this.chart.options.chart.alignTicks !== false && options.alignTicks !== false && // Disabled when startOnTick or endOnTick are false (#7604) options.startOnTick !== false && options.endOnTick !== false && // Don't try to align ticks on a log axis, they are not evenly // spaced (#6021) !this.isLog ) { this.chart[this.coll].forEach(function (axis) { var otherOptions = axis.options, horiz = axis.horiz, key = [ horiz ? otherOptions.left : otherOptions.top, otherOptions.width, otherOptions.height, otherOptions.pane ].join(','); if (axis.series.length) { // #4442 if (others[key]) { hasOther = true; // #4201 } else { others[key] = 1; } } }); } return hasOther; }, /** * Find the max ticks of either the x and y axis collection, and record it * in `this.tickAmount`. * @private */ getTickAmount: function () { var options = this.options, tickAmount = options.tickAmount, tickPixelInterval = options.tickPixelInterval; if ( !defined(options.tickInterval) && this.len < tickPixelInterval && !this.isRadial && !this.isLog && options.startOnTick && options.endOnTick ) { tickAmount = 2; } if (!tickAmount && this.alignToOthers()) { // Add 1 because 4 tick intervals require 5 ticks (including first // and last) tickAmount = Math.ceil(this.len / tickPixelInterval) + 1; } // For tick amounts of 2 and 3, compute five ticks and remove the // intermediate ones. This prevents the axis from adding ticks that are // too far away from the data extremes. if (tickAmount < 4) { this.finalTickAmt = tickAmount; tickAmount = 5; } this.tickAmount = tickAmount; }, /** * When using multiple axes, adjust the number of ticks to match the highest * number of ticks in that group. * @private */ adjustTickAmount: function () { var axis = this, axisOptions = axis.options, tickInterval = axis.tickInterval, tickPositions = axis.tickPositions, tickAmount = axis.tickAmount, finalTickAmt = axis.finalTickAmt, currentTickAmount = tickPositions && tickPositions.length, threshold = pick(axis.threshold, axis.softThreshold ? 0 : null), min, len, i; if (axis.hasData()) { if (currentTickAmount < tickAmount) { min = axis.min; while (tickPositions.length < tickAmount) { // Extend evenly for both sides unless we're on the // threshold (#3965) if ( tickPositions.length % 2 || min === threshold ) { // to the end tickPositions.push(correctFloat( tickPositions[tickPositions.length - 1] + tickInterval )); } else { // to the start tickPositions.unshift(correctFloat( tickPositions[0] - tickInterval )); } } axis.transA *= (currentTickAmount - 1) / (tickAmount - 1); // Do not crop when ticks are not extremes (#9841) axis.min = axisOptions.startOnTick ? tickPositions[0] : Math.min(axis.min, tickPositions[0]); axis.max = axisOptions.endOnTick ? tickPositions[tickPositions.length - 1] : Math.max(axis.max, tickPositions[tickPositions.length - 1]); // We have too many ticks, run second pass to try to reduce ticks } else if (currentTickAmount > tickAmount) { axis.tickInterval *= 2; axis.setTickPositions(); } // The finalTickAmt property is set in getTickAmount if (defined(finalTickAmt)) { i = len = tickPositions.length; while (i--) { if ( // Remove every other tick (finalTickAmt === 3 && i % 2 === 1) || // Remove all but first and last (finalTickAmt <= 2 && i > 0 && i < len - 1) ) { tickPositions.splice(i, 1); } } axis.finalTickAmt = undefined; } } }, /** * Set the scale based on data min and max, user set min and max or options. * @private * @fires Highcharts.Axis#event:afterSetScale */ setScale: function () { var axis = this, isDirtyData = axis.series.some(function (series) { return ( series.isDirtyData || series.isDirty || // When x axis is dirty, we need new data extremes for y as // well series.xAxis.isDirty ); }), isDirtyAxisLength; axis.oldMin = axis.min; axis.oldMax = axis.max; axis.oldAxisLength = axis.len; // set the new axisLength axis.setAxisSize(); isDirtyAxisLength = axis.len !== axis.oldAxisLength; // do we really need to go through all this? if ( isDirtyAxisLength || isDirtyData || axis.isLinked || axis.forceRedraw || axis.userMin !== axis.oldUserMin || axis.userMax !== axis.oldUserMax || axis.alignToOthers() ) { if (axis.resetStacks) { axis.resetStacks(); } axis.forceRedraw = false; // get data extremes if needed axis.getSeriesExtremes(); // get fixed positions based on tickInterval axis.setTickInterval(); // record old values to decide whether a rescale is necessary later // on (#540) axis.oldUserMin = axis.userMin; axis.oldUserMax = axis.userMax; // Mark as dirty if it is not already set to dirty and extremes have // changed. #595. if (!axis.isDirty) { axis.isDirty = isDirtyAxisLength || axis.min !== axis.oldMin || axis.max !== axis.oldMax; } } else if (axis.cleanStacks) { axis.cleanStacks(); } fireEvent(this, 'afterSetScale'); }, /** * Set the minimum and maximum of the axes after render time. If the * `startOnTick` and `endOnTick` options are true, the minimum and maximum * values are rounded off to the nearest tick. To prevent this, these * options can be set to false before calling setExtremes. Also, setExtremes * will not allow a range lower than the `minRange` option, which by default * is the range of five points. * * @sample highcharts/members/axis-setextremes/ * Set extremes from a button * @sample highcharts/members/axis-setextremes-datetime/ * Set extremes on a datetime axis * @sample highcharts/members/axis-setextremes-off-ticks/ * Set extremes off ticks * @sample stock/members/axis-setextremes/ * Set extremes in Highstock * @sample maps/members/axis-setextremes/ * Set extremes in Highmaps * * @function Highcharts.Axis#setExtremes * * @param {number} [newMin] * The new minimum value. * * @param {number} [newMax] * The new maximum value. * * @param {boolean} [redraw=true] * Whether to redraw the chart or wait for an explicit call to * {@link Highcharts.Chart#redraw} * * @param {boolean|Highcharts.AnimationOptionsObject} [animation=true] * Enable or modify animations. * * @param {*} [eventArguments] * Arguments to be accessed in event handler. * * @fires Highcharts.Axis#event:setExtremes */ setExtremes: function (newMin, newMax, redraw, animation, eventArguments) { var axis = this, chart = axis.chart; redraw = pick(redraw, true); // defaults to true axis.series.forEach(function (serie) { delete serie.kdTree; }); // Extend the arguments with min and max eventArguments = extend(eventArguments, { min: newMin, max: newMax }); // Fire the event fireEvent(axis, 'setExtremes', eventArguments, function () { axis.userMin = newMin; axis.userMax = newMax; axis.eventArgs = eventArguments; if (redraw) { chart.redraw(animation); } }); }, // Overridable method for zooming chart. Pulled out in a separate method to // allow overriding in stock charts. zoom: function (newMin, newMax) { var dataMin = this.dataMin, dataMax = this.dataMax, options = this.options, min = Math.min(dataMin, pick(options.min, dataMin)), max = Math.max(dataMax, pick(options.max, dataMax)), evt = { newMin: newMin, newMax: newMax }; fireEvent(this, 'zoom', evt, function (e) { // Use e.newMin and e.newMax - event handlers may have altered them var newMin = e.newMin, newMax = e.newMax; if (newMin !== this.min || newMax !== this.max) { // #5790 // Prevent pinch zooming out of range. Check for defined is for // #1946. #1734. if (!this.allowZoomOutside) { // #6014, sometimes newMax will be smaller than min (or // newMin will be larger than max). if (defined(dataMin)) { if (newMin < min) { newMin = min; } if (newMin > max) { newMin = max; } } if (defined(dataMax)) { if (newMax < min) { newMax = min; } if (newMax > max) { newMax = max; } } } // In full view, displaying the reset zoom button is not // required this.displayBtn = newMin !== undefined || newMax !== undefined; // Do it this.setExtremes( newMin, newMax, false, undefined, { trigger: 'zoom' } ); } e.zoomed = true; }); return evt.zoomed; }, // Update the axis metrics. setAxisSize: function () { var chart = this.chart, options = this.options, // [top, right, bottom, left] offsets = options.offsets || [0, 0, 0, 0], horiz = this.horiz, // Check for percentage based input values. Rounding fixes problems // with column overflow and plot line filtering (#4898, #4899) width = this.width = Math.round(H.relativeLength( pick( options.width, chart.plotWidth - offsets[3] + offsets[1] ), chart.plotWidth )), height = this.height = Math.round(H.relativeLength( pick( options.height, chart.plotHeight - offsets[0] + offsets[2] ), chart.plotHeight )), top = this.top = Math.round(H.relativeLength( pick(options.top, chart.plotTop + offsets[0]), chart.plotHeight, chart.plotTop )), left = this.left = Math.round(H.relativeLength( pick(options.left, chart.plotLeft + offsets[3]), chart.plotWidth, chart.plotLeft )); // Expose basic values to use in Series object and navigator this.bottom = chart.chartHeight - height - top; this.right = chart.chartWidth - width - left; // Direction agnostic properties this.len = Math.max(horiz ? width : height, 0); // Math.max fixes #905 this.pos = horiz ? left : top; // distance from SVG origin }, /** * Get the current extremes for the axis. * * @sample highcharts/members/axis-getextremes/ * Report extremes by click on a button * @sample maps/members/axis-getextremes/ * Get extremes in Highmaps * * @function Highcharts.Axis#getExtremes * * @returns {Highcharts.ExtremesObject} * An object containing extremes information. */ getExtremes: function () { var axis = this, isLog = axis.isLog; return { min: isLog ? correctFloat(axis.lin2log(axis.min)) : axis.min, max: isLog ? correctFloat(axis.lin2log(axis.max)) : axis.max, dataMin: axis.dataMin, dataMax: axis.dataMax, userMin: axis.userMin, userMax: axis.userMax }; }, /** * Get the zero plane either based on zero or on the min or max value. * Used in bar and area plots. * * @function Highcharts.Axis#getThreshold * * @param {number} threshold * The threshold in axis values. * * @return {number} * The translated threshold position in terms of pixels, and * corrected to stay within the axis bounds. */ getThreshold: function (threshold) { var axis = this, isLog = axis.isLog, realMin = isLog ? axis.lin2log(axis.min) : axis.min, realMax = isLog ? axis.lin2log(axis.max) : axis.max; if (threshold === null || threshold === -Infinity) { threshold = realMin; } else if (threshold === Infinity) { threshold = realMax; } else if (realMin > threshold) { threshold = realMin; } else if (realMax < threshold) { threshold = realMax; } return axis.translate(threshold, 0, 1, 0, 1); }, /** * Compute auto alignment for the axis label based on which side the axis is * on and the given rotation for the label. * @private * @param {number} rotation The rotation in degrees as set by either the * `rotation` or `autoRotation` options. * @return {string} Can be `center`, `left` or `right`. */ autoLabelAlign: function (rotation) { var angle = (pick(rotation, 0) - (this.side * 90) + 720) % 360, evt = { align: 'center' }; fireEvent(this, 'autoLabelAlign', evt, function (e) { if (angle > 15 && angle < 165) { e.align = 'right'; } else if (angle > 195 && angle < 345) { e.align = 'left'; } }); return evt.align; }, /** * Get the tick length and width for the axis based on axis options. * @private * @param {string} prefix 'tick' or 'minorTick' * @return {Array} An array of tickLength and tickWidth */ tickSize: function (prefix) { var options = this.options, tickLength = options[prefix + 'Length'], tickWidth = pick( options[prefix + 'Width'], prefix === 'tick' && this.isXAxis ? 1 : 0 // X axis default 1 ), e, tickSize; if (tickWidth && tickLength) { // Negate the length if (options[prefix + 'Position'] === 'inside') { tickLength = -tickLength; } tickSize = [tickLength, tickWidth]; } e = { tickSize: tickSize }; fireEvent(this, 'afterTickSize', e); return e.tickSize; }, // Return the size of the labels. labelMetrics: function () { var index = this.tickPositions && this.tickPositions[0] || 0; return this.chart.renderer.fontMetrics( this.options.labels.style && this.options.labels.style.fontSize, this.ticks[index] && this.ticks[index].label ); }, // Prevent the ticks from getting so close we can't draw the labels. On a // horizontal axis, this is handled by rotating the labels, removing ticks // and adding ellipsis. On a vertical axis remove ticks and add ellipsis. unsquish: function () { var labelOptions = this.options.labels, horiz = this.horiz, tickInterval = this.tickInterval, newTickInterval = tickInterval, slotSize = this.len / ( ((this.categories ? 1 : 0) + this.max - this.min) / tickInterval ), rotation, rotationOption = labelOptions.rotation, labelMetrics = this.labelMetrics(), step, bestScore = Number.MAX_VALUE, autoRotation, range = this.max - this.min, // Return the multiple of tickInterval that is needed to avoid // collision getStep = function (spaceNeeded) { var step = spaceNeeded / (slotSize || 1); step = step > 1 ? Math.ceil(step) : 1; // Guard for very small or negative angles (#9835) if ( step * tickInterval > range && spaceNeeded !== Infinity && slotSize !== Infinity ) { step = Math.ceil(range / tickInterval); } return correctFloat(step * tickInterval); }; if (horiz) { autoRotation = !labelOptions.staggerLines && !labelOptions.step && ( // #3971 defined(rotationOption) ? [rotationOption] : slotSize < pick(labelOptions.autoRotationLimit, 80) && labelOptions.autoRotation ); if (autoRotation) { // Loop over the given autoRotation options, and determine // which gives the best score. The best score is that with // the lowest number of steps and a rotation closest // to horizontal. autoRotation.forEach(function (rot) { var score; if ( rot === rotationOption || (rot && rot >= -90 && rot <= 90) ) { // #3891 step = getStep( Math.abs(labelMetrics.h / Math.sin(deg2rad * rot)) ); score = step + Math.abs(rot / 360); if (score < bestScore) { bestScore = score; rotation = rot; newTickInterval = step; } } }); } } else if (!labelOptions.step) { // #4411 newTickInterval = getStep(labelMetrics.h); } this.autoRotation = autoRotation; this.labelRotation = pick(rotation, rotationOption); return newTickInterval; }, /** * Get the general slot width for labels/categories on this axis. This may * change between the pre-render (from Axis.getOffset) and the final tick * rendering and placement. * @private * @param {Highcharts.Tick} [tick] Optionally, calculate the slot width * basing on tick label. It is used in highcharts-3d module, where the slots * has different widths depending on perspective angles. * @return {number} The pixel width allocated to each axis label. */ getSlotWidth: function (tick) { // #5086, #1580, #1931 var chart = this.chart, horiz = this.horiz, labelOptions = this.options.labels, slotCount = Math.max( this.tickPositions.length - (this.categories ? 0 : 1), 1 ), marginLeft = chart.margin[3]; return ( tick && tick.slotWidth // Used by grid axis ) || ( horiz && (labelOptions.step || 0) < 2 && !labelOptions.rotation && // #4415 ((this.staggerLines || 1) * this.len) / slotCount ) || ( !horiz && ( // #7028 ( labelOptions.style && parseInt(labelOptions.style.width, 10) ) || ( marginLeft && (marginLeft - chart.spacing[3]) ) || chart.chartWidth * 0.33 ) ); }, // Render the axis labels and determine whether ellipsis or rotation need to // be applied. renderUnsquish: function () { var chart = this.chart, renderer = chart.renderer, tickPositions = this.tickPositions, ticks = this.ticks, labelOptions = this.options.labels, labelStyleOptions = (labelOptions && labelOptions.style || {}), horiz = this.horiz, slotWidth = this.getSlotWidth(), innerWidth = Math.max( 1, Math.round(slotWidth - 2 * (labelOptions.padding || 5)) ), attr = {}, labelMetrics = this.labelMetrics(), textOverflowOption = labelOptions.style && labelOptions.style.textOverflow, commonWidth, commonTextOverflow, maxLabelLength = 0, label, i, pos; // Set rotation option unless it is "auto", like in gauges if (!isString(labelOptions.rotation)) { attr.rotation = labelOptions.rotation || 0; // #4443 } // Get the longest label length tickPositions.forEach(function (tick) { tick = ticks[tick]; if ( tick && tick.label && tick.label.textPxLength > maxLabelLength ) { maxLabelLength = tick.label.textPxLength; } }); this.maxLabelLength = maxLabelLength; // Handle auto rotation on horizontal axis if (this.autoRotation) { // Apply rotation only if the label is too wide for the slot, and // the label is wider than its height. if ( maxLabelLength > innerWidth && maxLabelLength > labelMetrics.h ) { attr.rotation = this.labelRotation; } else { this.labelRotation = 0; } // Handle word-wrap or ellipsis on vertical axis } else if (slotWidth) { // For word-wrap or ellipsis commonWidth = innerWidth; if (!textOverflowOption) { commonTextOverflow = 'clip'; // On vertical axis, only allow word wrap if there is room // for more lines. i = tickPositions.length; while (!horiz && i--) { pos = tickPositions[i]; label = ticks[pos].label; if (label) { // Reset ellipsis in order to get the correct // bounding box (#4070) if ( label.styles && label.styles.textOverflow === 'ellipsis' ) { label.css({ textOverflow: 'clip' }); // Set the correct width in order to read // the bounding box height (#4678, #5034) } else if (label.textPxLength > slotWidth) { label.css({ width: slotWidth + 'px' }); } if ( label.getBBox().height > ( this.len / tickPositions.length - (labelMetrics.h - labelMetrics.f) ) ) { label.specificTextOverflow = 'ellipsis'; } } } } } // Add ellipsis if the label length is significantly longer than ideal if (attr.rotation) { commonWidth = ( maxLabelLength > chart.chartHeight * 0.5 ? chart.chartHeight * 0.33 : maxLabelLength ); if (!textOverflowOption) { commonTextOverflow = 'ellipsis'; } } // Set the explicit or automatic label alignment this.labelAlign = labelOptions.align || this.autoLabelAlign(this.labelRotation); if (this.labelAlign) { attr.align = this.labelAlign; } // Apply general and specific CSS tickPositions.forEach(function (pos) { var tick = ticks[pos], label = tick && tick.label, widthOption = labelStyleOptions.width, css = {}; if (label) { // This needs to go before the CSS in old IE (#4502) label.attr(attr); if (tick.shortenLabel) { tick.shortenLabel(); } else if ( commonWidth && !widthOption && // Setting width in this case messes with the bounding box // (#7975) labelStyleOptions.whiteSpace !== 'nowrap' && ( // Speed optimizing, #7656 commonWidth < label.textPxLength || // Resetting CSS, #4928 label.element.tagName === 'SPAN' ) ) { css.width = commonWidth; if (!textOverflowOption) { css.textOverflow = ( label.specificTextOverflow || commonTextOverflow ); } label.css(css); // Reset previously shortened label (#8210) } else if ( label.styles && label.styles.width && !css.width && !widthOption ) { label.css({ width: null }); } delete label.specificTextOverflow; tick.rotation = attr.rotation; } }, this); // Note: Why is this not part of getLabelPosition? this.tickRotCorr = renderer.rotCorr( labelMetrics.b, this.labelRotation || 0, this.side !== 0 ); }, /** * Return true if the axis has associated data. * * @function Highcharts.Axis#hasData * * @return {boolean} * True if the axis has associated visible series and those series * have either valid data points or explicit `min` and `max` * settings. */ hasData: function () { return ( this.hasVisibleSeries || ( defined(this.min) && defined(this.max) && this.tickPositions && this.tickPositions.length > 0 ) ); }, /** * Adds the title defined in axis.options.title. * * @function Highcharts.Axis#addTitle * * @param {boolean} display * Whether or not to display the title. */ addTitle: function (display) { var axis = this, renderer = axis.chart.renderer, horiz = axis.horiz, opposite = axis.opposite, options = axis.options, axisTitleOptions = options.title, textAlign, styledMode = axis.chart.styledMode; if (!axis.axisTitle) { textAlign = axisTitleOptions.textAlign; if (!textAlign) { textAlign = (horiz ? { low: 'left', middle: 'center', high: 'right' } : { low: opposite ? 'right' : 'left', middle: 'center', high: opposite ? 'left' : 'right' })[axisTitleOptions.align]; } axis.axisTitle = renderer.text( axisTitleOptions.text, 0, 0, axisTitleOptions.useHTML ) .attr({ zIndex: 7, rotation: axisTitleOptions.rotation || 0, align: textAlign }) .addClass('highcharts-axis-title'); // #7814, don't mutate style option if (!styledMode) { axis.axisTitle.css(merge(axisTitleOptions.style)); } axis.axisTitle.add(axis.axisGroup); axis.axisTitle.isNew = true; } // Max width defaults to the length of the axis if (!styledMode && !axisTitleOptions.style.width && !axis.isRadial) { axis.axisTitle.css({ width: axis.len }); } // hide or show the title depending on whether showEmpty is set axis.axisTitle[display ? 'show' : 'hide'](true); }, /** * Generates a tick for initial positioning. * @private * @param {number} pos The tick position in axis values. * @param {number} i The index of the tick in {@link Axis.tickPositions}. */ generateTick: function (pos) { var ticks = this.ticks; if (!ticks[pos]) { ticks[pos] = new Tick(this, pos); } else { ticks[pos].addLabel(); // update labels depending on tick interval } }, /** * Render the tick labels to a preliminary position to get their sizes * @private * @fires Highcharts.Axis#event:afterGetOffset */ getOffset: function () { var axis = this, chart = axis.chart, renderer = chart.renderer, options = axis.options, tickPositions = axis.tickPositions, ticks = axis.ticks, horiz = axis.horiz, side = axis.side, invertedSide = chart.inverted && !axis.isZAxis ? [1, 0, 3, 2][side] : side, hasData, showAxis, titleOffset = 0, titleOffsetOption, titleMargin = 0, axisTitleOptions = options.title, labelOptions = options.labels, labelOffset = 0, // reset labelOffsetPadded, axisOffset = chart.axisOffset, clipOffset = chart.clipOffset, clip, directionFactor = [-1, 1, 1, -1][side], className = options.className, axisParent = axis.axisParent, // Used in color axis lineHeightCorrection, tickSize; // For reuse in Axis.render hasData = axis.hasData(); axis.showAxis = showAxis = hasData || pick(options.showEmpty, true); // Set/reset staggerLines axis.staggerLines = axis.horiz && labelOptions.staggerLines; // Create the axisGroup and gridGroup elements on first iteration if (!axis.axisGroup) { axis.gridGroup = renderer.g('grid') .attr({ zIndex: options.gridZIndex || 1 }) .addClass( 'highcharts-' + this.coll.toLowerCase() + '-grid ' + (className || '') ) .add(axisParent); axis.axisGroup = renderer.g('axis') .attr({ zIndex: options.zIndex || 2 }) .addClass( 'highcharts-' + this.coll.toLowerCase() + ' ' + (className || '') ) .add(axisParent); axis.labelGroup = renderer.g('axis-labels') .attr({ zIndex: labelOptions.zIndex || 7 }) .addClass( 'highcharts-' + axis.coll.toLowerCase() + '-labels ' + (className || '') ) .add(axisParent); } if (hasData || axis.isLinked) { // Generate ticks tickPositions.forEach(function (pos, i) { // i is not used here, but may be used in overrides axis.generateTick(pos, i); }); axis.renderUnsquish(); // Left side must be align: right and right side must // have align: left for labels axis.reserveSpaceDefault = ( side === 0 || side === 2 || { 1: 'left', 3: 'right' }[side] === axis.labelAlign ); if (pick( labelOptions.reserveSpace, axis.labelAlign === 'center' ? true : null, axis.reserveSpaceDefault )) { tickPositions.forEach(function (pos) { // get the highest offset labelOffset = Math.max( ticks[pos].getLabelSize(), labelOffset ); }); } if (axis.staggerLines) { labelOffset *= axis.staggerLines; } axis.labelOffset = labelOffset * (axis.opposite ? -1 : 1); } else { // doesn't have data objectEach(ticks, function (tick, n) { tick.destroy(); delete ticks[n]; }); } if ( axisTitleOptions && axisTitleOptions.text && axisTitleOptions.enabled !== false ) { axis.addTitle(showAxis); if (showAxis && axisTitleOptions.reserveSpace !== false) { axis.titleOffset = titleOffset = axis.axisTitle.getBBox()[horiz ? 'height' : 'width']; titleOffsetOption = axisTitleOptions.offset; titleMargin = defined(titleOffsetOption) ? 0 : pick(axisTitleOptions.margin, horiz ? 5 : 10); } } // Render the axis line axis.renderLine(); // handle automatic or user set offset axis.offset = directionFactor * pick( options.offset, axisOffset[side] ? axisOffset[side] + (options.margin || 0) : 0 ); axis.tickRotCorr = axis.tickRotCorr || { x: 0, y: 0 }; // polar if (side === 0) { lineHeightCorrection = -axis.labelMetrics().h; } else if (side === 2) { lineHeightCorrection = axis.tickRotCorr.y; } else { lineHeightCorrection = 0; } // Find the padded label offset labelOffsetPadded = Math.abs(labelOffset) + titleMargin; if (labelOffset) { labelOffsetPadded -= lineHeightCorrection; labelOffsetPadded += directionFactor * ( horiz ? pick( labelOptions.y, axis.tickRotCorr.y + directionFactor * 8 ) : labelOptions.x ); } axis.axisTitleMargin = pick(titleOffsetOption, labelOffsetPadded); if (axis.getMaxLabelDimensions) { axis.maxLabelDimensions = axis.getMaxLabelDimensions( ticks, tickPositions ); } // Due to GridAxis.tickSize, tickSize should be calculated after ticks // has rendered. tickSize = this.tickSize('tick'); axisOffset[side] = Math.max( axisOffset[side], axis.axisTitleMargin + titleOffset + directionFactor * axis.offset, labelOffsetPadded, // #3027 hasData && tickPositions.length && tickSize ? tickSize[0] + directionFactor * axis.offset : 0 // #4866 ); // Decide the clipping needed to keep the graph inside // the plot area and axis lines clip = options.offset ? 0 : Math.floor(axis.axisLine.strokeWidth() / 2) * 2; // #4308, #4371 clipOffset[invertedSide] = Math.max(clipOffset[invertedSide], clip); fireEvent(this, 'afterGetOffset'); }, /** * Internal function to get the path for the axis line. Extended for polar * charts. * * @function Highcharts.Axis#getLinePath * * @param {number} lineWidth * The line width in pixels. * * @return {Highcharts.SVGPathArray} * The SVG path definition in array form. */ getLinePath: function (lineWidth) { var chart = this.chart, opposite = this.opposite, offset = this.offset, horiz = this.horiz, lineLeft = this.left + (opposite ? this.width : 0) + offset, lineTop = chart.chartHeight - this.bottom - (opposite ? this.height : 0) + offset; if (opposite) { lineWidth *= -1; // crispify the other way - #1480, #1687 } return chart.renderer .crispLine([ 'M', horiz ? this.left : lineLeft, horiz ? lineTop : this.top, 'L', horiz ? chart.chartWidth - this.right : lineLeft, horiz ? lineTop : chart.chartHeight - this.bottom ], lineWidth); }, /** * Render the axis line. Called internally when rendering and redrawing the * axis. * * @function Highcharts.Axis#renderLine */ renderLine: function () { if (!this.axisLine) { this.axisLine = this.chart.renderer.path() .addClass('highcharts-axis-line') .add(this.axisGroup); if (!this.chart.styledMode) { this.axisLine.attr({ stroke: this.options.lineColor, 'stroke-width': this.options.lineWidth, zIndex: 7 }); } } }, /** * Position the axis title. * @private * @return {Highcharts.PositionObject} X and Y positions for the title. */ getTitlePosition: function () { // compute anchor points for each of the title align options var horiz = this.horiz, axisLeft = this.left, axisTop = this.top, axisLength = this.len, axisTitleOptions = this.options.title, margin = horiz ? axisLeft : axisTop, opposite = this.opposite, offset = this.offset, xOption = axisTitleOptions.x || 0, yOption = axisTitleOptions.y || 0, axisTitle = this.axisTitle, fontMetrics = this.chart.renderer.fontMetrics( axisTitleOptions.style && axisTitleOptions.style.fontSize, axisTitle ), // The part of a multiline text that is below the baseline of the // first line. Subtract 1 to preserve pixel-perfectness from the // old behaviour (v5.0.12), where only one line was allowed. textHeightOvershoot = Math.max( axisTitle.getBBox(null, 0).height - fontMetrics.h - 1, 0 ), // the position in the length direction of the axis alongAxis = { low: margin + (horiz ? 0 : axisLength), middle: margin + axisLength / 2, high: margin + (horiz ? axisLength : 0) }[axisTitleOptions.align], // the position in the perpendicular direction of the axis offAxis = (horiz ? axisTop + this.height : axisLeft) + (horiz ? 1 : -1) * // horizontal axis reverses the margin (opposite ? -1 : 1) * // so does opposite axes this.axisTitleMargin + [ -textHeightOvershoot, // top textHeightOvershoot, // right fontMetrics.f, // bottom -textHeightOvershoot // left ][this.side], titlePosition = { x: horiz ? alongAxis + xOption : offAxis + (opposite ? this.width : 0) + offset + xOption, y: horiz ? offAxis + yOption - (opposite ? this.height : 0) + offset : alongAxis + yOption }; fireEvent( this, 'afterGetTitlePosition', { titlePosition: titlePosition } ); return titlePosition; }, /** * Render a minor tick into the given position. If a minor tick already * exists in this position, move it. * * @function Highcharts.Axis#renderMinorTick * * @param {number} pos * The position in axis values. */ renderMinorTick: function (pos) { var slideInTicks = this.chart.hasRendered && isNumber(this.oldMin), minorTicks = this.minorTicks; if (!minorTicks[pos]) { minorTicks[pos] = new Tick(this, pos, 'minor'); } // Render new ticks in old position if (slideInTicks && minorTicks[pos].isNew) { minorTicks[pos].render(null, true); } minorTicks[pos].render(null, false, 1); }, /** * Render a major tick into the given position. If a tick already exists * in this position, move it. * * @function Highcharts.Axis#renderTick * * @param {number} pos * The position in axis values. * * @param {number} i * The tick index. */ renderTick: function (pos, i) { var isLinked = this.isLinked, ticks = this.ticks, slideInTicks = this.chart.hasRendered && isNumber(this.oldMin); // Linked axes need an extra check to find out if if (!isLinked || (pos >= this.min && pos <= this.max)) { if (!ticks[pos]) { ticks[pos] = new Tick(this, pos); } // NOTE this seems like overkill. Could be handled in tick.render by // setting old position in attr, then set new position in animate. // render new ticks in old position if (slideInTicks && ticks[pos].isNew) { // Start with negative opacity so that it is visible from // halfway into the animation ticks[pos].render(i, true, -1); } ticks[pos].render(i); } }, /** * Render the axis. * @private * @fires Highcharts.Axis#event:afterRender */ render: function () { var axis = this, chart = axis.chart, renderer = chart.renderer, options = axis.options, isLog = axis.isLog, isLinked = axis.isLinked, tickPositions = axis.tickPositions, axisTitle = axis.axisTitle, ticks = axis.ticks, minorTicks = axis.minorTicks, alternateBands = axis.alternateBands, stackLabelOptions = options.stackLabels, alternateGridColor = options.alternateGridColor, tickmarkOffset = axis.tickmarkOffset, axisLine = axis.axisLine, showAxis = axis.showAxis, animation = animObject(renderer.globalAnimation), from, to; // Reset axis.labelEdge.length = 0; axis.overlap = false; // Mark all elements inActive before we go over and mark the active ones [ticks, minorTicks, alternateBands].forEach(function (coll) { objectEach(coll, function (tick) { tick.isActive = false; }); }); // If the series has data draw the ticks. Else only the line and title if (axis.hasData() || isLinked) { // minor ticks if (axis.minorTickInterval && !axis.categories) { axis.getMinorTickPositions().forEach(function (pos) { axis.renderMinorTick(pos); }); } // Major ticks. Pull out the first item and render it last so that // we can get the position of the neighbour label. #808. if (tickPositions.length) { // #1300 tickPositions.forEach(function (pos, i) { axis.renderTick(pos, i); }); // In a categorized axis, the tick marks are displayed // between labels. So we need to add a tick mark and // grid line at the left edge of the X axis. if (tickmarkOffset && (axis.min === 0 || axis.single)) { if (!ticks[-1]) { ticks[-1] = new Tick(axis, -1, null, true); } ticks[-1].render(-1); } } // alternate grid color if (alternateGridColor) { tickPositions.forEach(function (pos, i) { to = tickPositions[i + 1] !== undefined ? tickPositions[i + 1] + tickmarkOffset : axis.max - tickmarkOffset; if ( i % 2 === 0 && pos < axis.max && to <= axis.max + ( chart.polar ? -tickmarkOffset : tickmarkOffset ) ) { // #2248, #4660 if (!alternateBands[pos]) { alternateBands[pos] = new H.PlotLineOrBand(axis); } from = pos + tickmarkOffset; // #949 alternateBands[pos].options = { from: isLog ? axis.lin2log(from) : from, to: isLog ? axis.lin2log(to) : to, color: alternateGridColor }; alternateBands[pos].render(); alternateBands[pos].isActive = true; } }); } // custom plot lines and bands if (!axis._addedPlotLB) { // only first time ( (options.plotLines || []).concat(options.plotBands || []) ).forEach( function (plotLineOptions) { axis.addPlotBandOrLine(plotLineOptions); } ); axis._addedPlotLB = true; } } // end if hasData // Remove inactive ticks [ticks, minorTicks, alternateBands].forEach(function (coll) { var i, forDestruction = [], delay = animation.duration, destroyInactiveItems = function () { i = forDestruction.length; while (i--) { // When resizing rapidly, the same items // may be destroyed in different timeouts, // or the may be reactivated if ( coll[forDestruction[i]] && !coll[forDestruction[i]].isActive ) { coll[forDestruction[i]].destroy(); delete coll[forDestruction[i]]; } } }; objectEach(coll, function (tick, pos) { if (!tick.isActive) { // Render to zero opacity tick.render(pos, false, 0); tick.isActive = false; forDestruction.push(pos); } }); // When the objects are finished fading out, destroy them syncTimeout( destroyInactiveItems, coll === alternateBands || !chart.hasRendered || !delay ? 0 : delay ); }); // Set the axis line path if (axisLine) { axisLine[axisLine.isPlaced ? 'animate' : 'attr']({ d: this.getLinePath(axisLine.strokeWidth()) }); axisLine.isPlaced = true; // Show or hide the line depending on options.showEmpty axisLine[showAxis ? 'show' : 'hide'](true); } if (axisTitle && showAxis) { var titleXy = axis.getTitlePosition(); if (isNumber(titleXy.y)) { axisTitle[axisTitle.isNew ? 'attr' : 'animate'](titleXy); axisTitle.isNew = false; } else { axisTitle.attr('y', -9999); axisTitle.isNew = true; } } // Stacked totals: if (stackLabelOptions && stackLabelOptions.enabled) { axis.renderStackTotals(); } // End stacked totals axis.isDirty = false; fireEvent(this, 'afterRender'); }, // Redraw the axis to reflect changes in the data or axis extremes. Called // internally from Highcharts.Chart#redraw. redraw: function () { if (this.visible) { // render the axis this.render(); // move plot lines and bands this.plotLinesAndBands.forEach(function (plotLine) { plotLine.render(); }); } // mark associated series as dirty and ready for redraw this.series.forEach(function (series) { series.isDirty = true; }); }, // Properties to survive after destroy, needed for Axis.update (#4317, // #5773, #5881). keepProps: ['extKey', 'hcEvents', 'names', 'series', 'userMax', 'userMin'], /** * Destroys an Axis instance. See {@link Axis#remove} for the API endpoint * to fully remove the axis. * @private * @param {boolean} keepEvents Whether to preserve events, used internally * in Axis.update. */ destroy: function (keepEvents) { var axis = this, stacks = axis.stacks, plotLinesAndBands = axis.plotLinesAndBands, plotGroup, i; fireEvent(this, 'destroy', { keepEvents: keepEvents }); // Remove the events if (!keepEvents) { removeEvent(axis); } // Destroy each stack total objectEach(stacks, function (stack, stackKey) { destroyObjectProperties(stack); stacks[stackKey] = null; }); // Destroy collections [axis.ticks, axis.minorTicks, axis.alternateBands].forEach( function (coll) { destroyObjectProperties(coll); } ); if (plotLinesAndBands) { i = plotLinesAndBands.length; while (i--) { // #1975 plotLinesAndBands[i].destroy(); } } // Destroy elements ['stackTotalGroup', 'axisLine', 'axisTitle', 'axisGroup', 'gridGroup', 'labelGroup', 'cross', 'scrollbar'].forEach( function (prop) { if (axis[prop]) { axis[prop] = axis[prop].destroy(); } } ); // Destroy each generated group for plotlines and plotbands for (plotGroup in axis.plotLinesAndBandsGroups) { axis.plotLinesAndBandsGroups[plotGroup] = axis.plotLinesAndBandsGroups[plotGroup].destroy(); } // Delete all properties and fall back to the prototype. objectEach(axis, function (val, key) { if (axis.keepProps.indexOf(key) === -1) { delete axis[key]; } }); }, /** * Internal function to draw a crosshair. * * @function Highcharts.Axis#drawCrosshair * * @param {Highcharts.PointerEventObject} [e] * The event arguments from the modified pointer event, extended with * `chartX` and `chartY` * * @param {Highcharts.Point} [point] * The Point object if the crosshair snaps to points. * * @fires Highcharts.Axis#event:afterDrawCrosshair * @fires Highcharts.Axis#event:drawCrosshair */ drawCrosshair: function (e, point) { var path, options = this.crosshair, snap = pick(options.snap, true), pos, categorized, graphic = this.cross; fireEvent(this, 'drawCrosshair', { e: e, point: point }); // Use last available event when updating non-snapped crosshairs without // mouse interaction (#5287) if (!e) { e = this.cross && this.cross.e; } if ( // Disabled in options !this.crosshair || // Snap ((defined(point) || !snap) === false) ) { this.hideCrosshair(); } else { // Get the path if (!snap) { pos = e && ( this.horiz ? e.chartX - this.pos : this.len - e.chartY + this.pos ); } else if (defined(point)) { // #3834 pos = pick( point.crosshairPos, // 3D axis extension this.isXAxis ? point.plotX : this.len - point.plotY ); } if (defined(pos)) { path = this.getPlotLinePath( // First argument, value, only used on radial point && (this.isXAxis ? point.x : pick(point.stackY, point.y) ), null, null, null, pos // Translated position ) || null; // #3189 } if (!defined(path)) { this.hideCrosshair(); return; } categorized = this.categories && !this.isRadial; // Draw the cross if (!graphic) { this.cross = graphic = this.chart.renderer .path() .addClass( 'highcharts-crosshair highcharts-crosshair-' + (categorized ? 'category ' : 'thin ') + options.className ) .attr({ zIndex: pick(options.zIndex, 2) }) .add(); // Presentational attributes if (!this.chart.styledMode) { graphic.attr({ 'stroke': options.color || ( categorized ? color('#ccd6eb') .setOpacity(0.25).get() : '#cccccc' ), 'stroke-width': pick(options.width, 1) }).css({ 'pointer-events': 'none' }); if (options.dashStyle) { graphic.attr({ dashstyle: options.dashStyle }); } } } graphic.show().attr({ d: path }); if (categorized && !options.width) { graphic.attr({ 'stroke-width': this.transA }); } this.cross.e = e; } fireEvent(this, 'afterDrawCrosshair', { e: e, point: point }); }, /** * Hide the crosshair if visible. * * @function Highcharts.Axis#hideCrosshair */ hideCrosshair: function () { if (this.cross) { this.cross.hide(); } fireEvent(this, 'afterHideCrosshair'); } }); // end Axis H.Axis = Axis; export default Axis;