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