diff --git a/js/modules/boost/wgl-renderer.js b/js/modules/boost/wgl-renderer.js index 85efafc7155..e9f47fcc4bb 100644 --- a/js/modules/boost/wgl-renderer.js +++ b/js/modules/boost/wgl-renderer.js @@ -742,7 +742,7 @@ function GLRenderer(postRenderCallback) { shader.setUniform('xAxisLen', axis.len); shader.setUniform('xAxisPos', axis.pos); shader.setUniform('xAxisCVSCoord', (!axis.horiz)); - shader.setUniform('xAxisIsLog', axis.isLog); + shader.setUniform('xAxisIsLog', (!!axis.logarithmic)); shader.setUniform('xAxisReversed', (!!axis.reversed)); } /** @@ -761,7 +761,7 @@ function GLRenderer(postRenderCallback) { shader.setUniform('yAxisLen', axis.len); shader.setUniform('yAxisPos', axis.pos); shader.setUniform('yAxisCVSCoord', (!axis.horiz)); - shader.setUniform('yAxisIsLog', axis.isLog); + shader.setUniform('yAxisIsLog', (!!axis.logarithmic)); shader.setUniform('yAxisReversed', (!!axis.reversed)); } /** diff --git a/js/modules/drag-panes.src.js b/js/modules/drag-panes.src.js index d193366adf2..f42c1c2c5f5 100644 --- a/js/modules/drag-panes.src.js +++ b/js/modules/drag-panes.src.js @@ -453,7 +453,7 @@ var AxisResizer = /** @class */ (function () { return AxisResizer; }()); // Keep resizer reference on axis update -Axis.prototype.keepProps.push('resizer'); +Axis.keepProps.push('resizer'); /* eslint-disable no-invalid-this */ // Add new AxisResizer, update or remove it addEvent(Axis, 'afterRender', function () { diff --git a/js/modules/parallel-coordinates.src.js b/js/modules/parallel-coordinates.src.js index 4b4560f4d62..57c4981232a 100644 --- a/js/modules/parallel-coordinates.src.js +++ b/js/modules/parallel-coordinates.src.js @@ -203,7 +203,7 @@ extend(ChartProto, /** @lends Highcharts.Chart.prototype */ { } }); // On update, keep parallelPosition. -AxisProto.keepProps.push('parallelPosition'); +Axis.keepProps.push('parallelPosition'); // Update default options with predefined for a parallel coords. addEvent(Axis, 'afterSetOptions', function (e) { var axis = this, chart = axis.chart, axisPosition = ['left', 'width', 'height', 'top']; diff --git a/js/modules/solid-gauge.src.js b/js/modules/solid-gauge.src.js index c4d4694c862..bc2d8d5df07 100644 --- a/js/modules/solid-gauge.src.js +++ b/js/modules/solid-gauge.src.js @@ -117,7 +117,7 @@ colorAxisMethods = { } } else { - if (this.isLog) { + if (this.logarithmic) { value = this.val2lin(value); } pos = 1 - ((this.max - value) / (this.max - this.min)); diff --git a/js/parts-3d/Series.js b/js/parts-3d/Series.js index 26fb064a48b..43c001e4510 100644 --- a/js/parts-3d/Series.js +++ b/js/parts-3d/Series.js @@ -27,7 +27,7 @@ H.Series.prototype.translate3dPoints = function () { for (i = 0; i < series.data.length; i++) { rawPoint = series.data[i]; if (zAxis && zAxis.translate) { - zValue = zAxis.isLog && zAxis.val2lin ? + zValue = zAxis.logarithmic && zAxis.val2lin ? zAxis.val2lin(rawPoint.z) : rawPoint.z; // #4562 rawPoint.plotZ = zAxis.translate(zValue); diff --git a/js/parts-map/ColorAxis.js b/js/parts-map/ColorAxis.js index 90945af5f33..eb604bbd655 100644 --- a/js/parts-map/ColorAxis.js +++ b/js/parts-map/ColorAxis.js @@ -470,7 +470,7 @@ extend(ColorAxis.prototype, { 'legendItemWidth', 'legendItem', 'legendSymbol' - ].concat(Axis.prototype.keepProps), + ].concat(Axis.keepProps), /* eslint-disable no-invalid-this, valid-jsdoc */ /** * Initializes the color axis. @@ -636,8 +636,8 @@ extend(ColorAxis.prototype, { * @private */ normalizedValue: function (value) { - if (this.isLog) { - value = this.val2lin(value); + if (this.logarithmic) { + value = this.logarithmic.log2lin(value); } return 1 - ((this.max - value) / ((this.max - this.min) || 1)); diff --git a/js/parts-more/BubbleSeries.js b/js/parts-more/BubbleSeries.js index d14343db20d..093815225d2 100644 --- a/js/parts-more/BubbleSeries.js +++ b/js/parts-more/BubbleSeries.js @@ -465,7 +465,7 @@ Axis.prototype.beforePadding = function () { } }); // Apply the padding to the min and max properties - if (activeSeries.length && range > 0 && !this.isLog) { + if (activeSeries.length && range > 0 && !this.logarithmic) { pxMax -= axisLength; transA *= (axisLength + Math.max(0, pxMin) - // #8901 diff --git a/js/parts/Axis.js b/js/parts/Axis.js index 15af313f98f..3c5ebae7e15 100644 --- a/js/parts/Axis.js +++ b/js/parts/Axis.js @@ -259,7 +259,6 @@ var Axis = /** @class */ (function () { this.hasVisibleSeries = void 0; this.height = void 0; this.isLinked = void 0; - this.isLog = void 0; this.labelEdge = void 0; // @todo this.labelFormatter = void 0; this.left = void 0; @@ -424,8 +423,7 @@ var Axis = /** @class */ (function () { // Placeholder for plotlines and plotbands groups axis.plotLinesAndBandsGroups = {}; // Shorthand types - axis.isLog = type === 'logarithmic'; - axis.positiveValuesOnly = axis.isLog && !axis.allowNegativeLog; + axis.positiveValuesOnly = !!(axis.logarithmic && !options.allowNegativeLog); // Flag, if axis is linked to another axis axis.isLinked = defined(options.linkedTo); /** @@ -516,12 +514,6 @@ var Axis = /** @class */ (function () { 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'); }; /** @@ -564,7 +556,7 @@ var Axis = /** @class */ (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 ? + numericSymbolDetector = axis.logarithmic ? Math.abs(value) : axis.tickInterval; var chart = this.chart; @@ -731,7 +723,7 @@ var Axis = /** @class */ (function () { var axis = this.linkedParent || this, // #1417 sign = 1, cvsOffset = 0, localA = old ? axis.oldTransA : axis.transA, localMin = old ? axis.oldMin : axis.min, returnValue = 0, minPixelPadding = axis.minPixelPadding, doPostTranslate = (axis.isOrdinal || axis.isBroken || - (axis.isLog && handleLog)) && axis.lin2val; + (axis.logarithmic && handleLog)) && axis.lin2val; if (!localA) { localA = axis.transA; } @@ -959,12 +951,13 @@ var Axis = /** @class */ (function () { // 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) { + var logarithmic_1 = axis.logarithmic; + if (logarithmic_1) { // 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)); + minorTickPositions.push.apply(minorTickPositions, logarithmic_1.getLogTickPositions(minorTickInterval, paddedTicks[i - 1], paddedTicks[i], true)); } }); } @@ -998,11 +991,11 @@ var Axis = /** @class */ (function () { * @function Highcharts.Axis#adjustForMinRange */ Axis.prototype.adjustForMinRange = function () { - var axis = this, options = axis.options, min = axis.min, max = axis.max, zoomOffset, spaceAvailable, closestDataRange, i, distance, xData, loopLength, minArgs, maxArgs, minRange; + var axis = this, options = axis.options, min = axis.min, max = axis.max, log = axis.logarithmic, zoomOffset, spaceAvailable, closestDataRange, i, distance, xData, loopLength, minArgs, maxArgs, minRange; // Set the automatic minimum range based on the closest point distance if (axis.isXAxis && typeof axis.minRange === 'undefined' && - !axis.isLog) { + !log) { if (defined(options.min) || defined(options.max)) { axis.minRange = null; // don't do this again } @@ -1038,8 +1031,8 @@ var Axis = /** @class */ (function () { ]; // If space is available, stay within the data range if (spaceAvailable) { - minArgs[2] = axis.isLog ? - axis.log2lin(axis.dataMin) : + minArgs[2] = axis.logarithmic ? + axis.logarithmic.log2lin(axis.dataMin) : axis.dataMin; } min = arrayMax(minArgs); @@ -1049,8 +1042,8 @@ var Axis = /** @class */ (function () { ]; // If space is availabe, stay within the data range if (spaceAvailable) { - maxArgs[2] = axis.isLog ? - axis.log2lin(axis.dataMax) : + maxArgs[2] = log ? + log.log2lin(axis.dataMax) : axis.dataMax; } max = arrayMin(maxArgs); @@ -1281,7 +1274,7 @@ var Axis = /** @class */ (function () { * @fires Highcharts.Axis#event:foundExtremes */ Axis.prototype.setTickInterval = function (secondPass) { - var axis = this, chart = axis.chart, options = axis.options, isLog = axis.isLog, 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; + var axis = this, chart = axis.chart, log = axis.logarithmic, options = axis.options, 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 (!axis.dateTime && !categories && !isLinked) { this.getTickAmount(); } @@ -1315,7 +1308,7 @@ var Axis = /** @class */ (function () { axis.min = pick(hardMin, thresholdMin, axis.dataMin); axis.max = pick(hardMax, thresholdMax, axis.dataMax); } - if (isLog) { + if (log) { if (axis.positiveValuesOnly && !secondPass && Math.min(axis.min, pick(axis.dataMin, axis.min)) <= 0) { // #978 @@ -1325,8 +1318,8 @@ var Axis = /** @class */ (function () { // 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), 16); - axis.max = correctFloat(axis.log2lin(axis.max), 16); + axis.min = correctFloat(log.log2lin(axis.min), 16); + axis.max = correctFloat(log.log2lin(axis.max), 16); } // handle zoomed range if (axis.range && defined(axis.max)) { @@ -1461,7 +1454,7 @@ var Axis = /** @class */ (function () { axis.tickInterval = minTickInterval; } // for linear axes, get magnitude and normalize the interval - if (!axis.dateTime && !isLog && !tickIntervalOption) { + if (!axis.dateTime && !axis.logarithmic && !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 @@ -1540,8 +1533,8 @@ var Axis = /** @class */ (function () { else if (axis.dateTime) { tickPositions = axis.getTimeTicks(axis.dateTime.normalizeTimeTickInterval(this.tickInterval, options.units), this.min, this.max, options.startOfWeek, axis.ordinal && axis.ordinal.positions, this.closestPointRange, true); } - else if (this.isLog) { - tickPositions = axis.getLogTickPositions(this.tickInterval, this.min, this.max); + else if (axis.logarithmic) { + tickPositions = axis.logarithmic.getLogTickPositions(this.tickInterval, this.min, this.max); } else { tickPositions = this.getLinearTickPositions(this.tickInterval, this.min, this.max); @@ -1640,8 +1633,8 @@ var Axis = /** @class */ (function () { * True if there are other axes. */ Axis.prototype.alignToOthers = function () { - var others = // Whether there is another axis to pair with this one - {}, hasOther, options = this.options; + var axis = this, others = // Whether there is another axis to pair with this one + {}, hasOther, options = axis.options; if ( // Only if alignTicks is true this.chart.options.chart.alignTicks !== false && @@ -1651,7 +1644,7 @@ var Axis = /** @class */ (function () { options.endOnTick !== false && // Don't try to align ticks on a log axis, they are not evenly // spaced (#6021) - !this.isLog) { + !axis.logarithmic) { this.chart[this.coll].forEach(function (axis) { var otherOptions = axis.options, horiz = axis.horiz, key = [ horiz ? otherOptions.left : otherOptions.top, @@ -1679,11 +1672,11 @@ var Axis = /** @class */ (function () { * @function Highcharts.Axis#getTickAmount */ Axis.prototype.getTickAmount = function () { - var options = this.options, tickAmount = options.tickAmount, tickPixelInterval = options.tickPixelInterval; + var axis = this, options = this.options, tickAmount = options.tickAmount, tickPixelInterval = options.tickPixelInterval; if (!defined(options.tickInterval) && this.len < tickPixelInterval && !this.isRadial && - !this.isLog && + !axis.logarithmic && options.startOnTick && options.endOnTick) { tickAmount = 2; @@ -1964,13 +1957,14 @@ var Axis = /** @class */ (function () { * An object containing extremes information. */ Axis.prototype.getExtremes = function () { - var axis = this, isLog = axis.isLog; + var axis = this; + var log = axis.logarithmic; return { - min: isLog ? - correctFloat(axis.lin2log(axis.min)) : + min: log ? + correctFloat(log.lin2log(axis.min)) : axis.min, - max: isLog ? - correctFloat(axis.lin2log(axis.max)) : + max: log ? + correctFloat(log.lin2log(axis.max)) : axis.max, dataMin: axis.dataMin, dataMax: axis.dataMax, @@ -1992,7 +1986,7 @@ var Axis = /** @class */ (function () { * stay within the axis bounds. */ Axis.prototype.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; + var axis = this, log = axis.logarithmic, realMin = log ? log.lin2log(axis.min) : axis.min, realMax = log ? log.lin2log(axis.max) : axis.max; if (threshold === null || threshold === -Infinity) { threshold = realMin; } @@ -2670,7 +2664,7 @@ var Axis = /** @class */ (function () { * @fires Highcharts.Axis#event:afterRender */ Axis.prototype.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; + var axis = this, chart = axis.chart, log = axis.logarithmic, renderer = chart.renderer, options = axis.options, 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; @@ -2722,8 +2716,8 @@ var Axis = /** @class */ (function () { } from = pos + tickmarkOffset; // #949 alternateBands[pos].options = { - from: isLog ? axis.lin2log(from) : from, - to: isLog ? axis.lin2log(to) : to, + from: log ? log.lin2log(from) : from, + to: log ? log.lin2log(to) : to, color: alternateGridColor }; alternateBands[pos].render(); @@ -2820,6 +2814,18 @@ var Axis = /** @class */ (function () { series.isDirty = true; }); }; + /** + * Returns an array of axis properties, that should be untouched during + * reinitialization. + * + * @private + * @function Highcharts.Axis#getKeepProps + * + * @return {Array} + */ + Axis.prototype.getKeepProps = function () { + return (this.keepProps || Axis.keepProps); + }; /** * Destroys an Axis instance. See {@link Axis#remove} for the API endpoint * to fully remove the axis. @@ -2866,7 +2872,7 @@ var Axis = /** @class */ (function () { } // Delete all properties and fall back to the prototype. objectEach(axis, function (val, key) { - if (axis.keepProps.indexOf(key) === -1) { + if (axis.getKeepProps().indexOf(key) === -1) { delete axis[key]; } }); @@ -5808,12 +5814,10 @@ var Axis = /** @class */ (function () { rotation: 0 } }; - return Axis; -}()); -extend(Axis.prototype, { // Properties to survive after destroy, needed for Axis.update (#4317, // #5773, #5881). - keepProps: ['extKey', 'hcEvents', 'names', 'series', 'userMax', 'userMin'] -}); + Axis.keepProps = ['extKey', 'hcEvents', 'names', 'series', 'userMax', 'userMin']; + return Axis; +}()); H.Axis = Axis; export default H.Axis; diff --git a/js/parts/LogarithmicAxis.js b/js/parts/LogarithmicAxis.js index 2a6acf554b9..2e911456348 100644 --- a/js/parts/LogarithmicAxis.js +++ b/js/parts/LogarithmicAxis.js @@ -8,114 +8,176 @@ * * */ 'use strict'; -import H from './Globals.js'; +import Axis from './Axis.js'; import U from './Utilities.js'; -var getMagnitude = U.getMagnitude, normalizeTickInterval = U.normalizeTickInterval, pick = U.pick; -var Axis = H.Axis; -/* ************************************************************************** * - * Methods defined on the Axis prototype - * ************************************************************************** */ +var addEvent = U.addEvent, getMagnitude = U.getMagnitude, normalizeTickInterval = U.normalizeTickInterval, pick = U.pick; /* eslint-disable valid-jsdoc */ /** - * Set the tick positions of a logarithmic axis. + * Provides logarithmic support for axes. * * @private - * @function Highcharts.Axis#getLogTickPositions - * @param {number} interval - * @param {number} min - * @param {number} max - * @param {boolean} [minor] - * @return {Array} + * @class */ -Axis.prototype.getLogTickPositions = function (interval, min, max, minor) { - var axis = this, options = axis.options, axisLength = axis.len, - // Since we use this method for both major and minor ticks, - // use a local variable and return the result - positions = []; - // Reset - if (!minor) { - axis._minorAutoInterval = null; +var LogarithmicAxisAdditions = /** @class */ (function () { + /* * + * + * Constructors + * + * */ + function LogarithmicAxisAdditions(axis) { + this.axis = axis; } - // First case: All ticks fall on whole logarithms: 1, 10, 100 etc. - if (interval >= 0.5) { - interval = Math.round(interval); - positions = axis.getLinearTickPositions(interval, min, max); - // Second case: We need intermediary ticks. For example - // 1, 2, 4, 6, 8, 10, 20, 40 etc. - } - else if (interval >= 0.08) { - var roundedMin = Math.floor(min), intermediate, i, j, len, pos, lastPos, break2; - if (interval > 0.3) { - intermediate = [1, 2, 4]; - // 0.2 equals five minor ticks per 1, 10, 100 etc - } - else if (interval > 0.15) { - intermediate = [1, 2, 4, 6, 8]; + /* * + * + * Functions + * + * */ + LogarithmicAxisAdditions.prototype.destroy = function () { + this.axis = void 0; + this.minorAutoInterval = void 0; + }; + /** + * Set the tick positions of a logarithmic axis. + */ + LogarithmicAxisAdditions.prototype.getLogTickPositions = function (interval, min, max, minor) { + var log = this; + var axis = log.axis; + var axisLength = axis.len; + var options = axis.options; + // Since we use this method for both major and minor ticks, + // use a local variable and return the result + var positions = []; + // Reset + if (!minor) { + log.minorAutoInterval = void 0; } - else { // 0.1 equals ten minor ticks per 1, 10, 100 etc - intermediate = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + // First case: All ticks fall on whole logarithms: 1, 10, 100 etc. + if (interval >= 0.5) { + interval = Math.round(interval); + positions = axis.getLinearTickPositions(interval, min, max); + // Second case: We need intermediary ticks. For example + // 1, 2, 4, 6, 8, 10, 20, 40 etc. } - for (i = roundedMin; i < max + 1 && !break2; i++) { - len = intermediate.length; - for (j = 0; j < len && !break2; j++) { - pos = axis.log2lin(axis.lin2log(i) * intermediate[j]); - // #1670, lastPos is #3113 - if (pos > min && - (!minor || lastPos <= max) && - typeof lastPos !== 'undefined') { - positions.push(lastPos); - } - if (lastPos > max) { - break2 = true; + else if (interval >= 0.08) { + var roundedMin = Math.floor(min), intermediate, i, j, len, pos, lastPos, break2; + if (interval > 0.3) { + intermediate = [1, 2, 4]; + // 0.2 equals five minor ticks per 1, 10, 100 etc + } + else if (interval > 0.15) { + intermediate = [1, 2, 4, 6, 8]; + } + else { // 0.1 equals ten minor ticks per 1, 10, 100 etc + intermediate = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + } + for (i = roundedMin; i < max + 1 && !break2; i++) { + len = intermediate.length; + for (j = 0; j < len && !break2; j++) { + pos = log.log2lin(log.lin2log(i) * intermediate[j]); + // #1670, lastPos is #3113 + if (pos > min && + (!minor || lastPos <= max) && + typeof lastPos !== 'undefined') { + positions.push(lastPos); + } + if (lastPos > max) { + break2 = true; + } + lastPos = pos; } - lastPos = pos; } + // Third case: We are so deep in between whole logarithmic values that + // we might as well handle the tick positions like a linear axis. For + // example 1.01, 1.02, 1.03, 1.04. } - // Third case: We are so deep in between whole logarithmic values that - // we might as well handle the tick positions like a linear axis. For - // example 1.01, 1.02, 1.03, 1.04. - } - else { - var realMin = axis.lin2log(min), realMax = axis.lin2log(max), tickIntervalOption = minor ? - this.getMinorTickInterval() : - options.tickInterval, filteredTickIntervalOption = tickIntervalOption === 'auto' ? - null : - tickIntervalOption, tickPixelIntervalOption = options.tickPixelInterval / (minor ? 5 : 1), totalPixelLength = minor ? - axisLength / axis.tickPositions.length : - axisLength; - interval = pick(filteredTickIntervalOption, axis._minorAutoInterval, (realMax - realMin) * - tickPixelIntervalOption / (totalPixelLength || 1)); - interval = normalizeTickInterval(interval, null, getMagnitude(interval)); - positions = axis.getLinearTickPositions(interval, realMin, realMax).map(axis.log2lin); + else { + var realMin = log.lin2log(min), realMax = log.lin2log(max), tickIntervalOption = minor ? + axis.getMinorTickInterval() : + options.tickInterval, filteredTickIntervalOption = tickIntervalOption === 'auto' ? + null : + tickIntervalOption, tickPixelIntervalOption = options.tickPixelInterval / (minor ? 5 : 1), totalPixelLength = minor ? + axisLength / axis.tickPositions.length : + axisLength; + interval = pick(filteredTickIntervalOption, log.minorAutoInterval, (realMax - realMin) * + tickPixelIntervalOption / (totalPixelLength || 1)); + interval = normalizeTickInterval(interval, void 0, getMagnitude(interval)); + positions = axis.getLinearTickPositions(interval, realMin, realMax).map(log.log2lin); + if (!minor) { + log.minorAutoInterval = interval / 5; + } + } + // Set the axis-level tickInterval variable if (!minor) { - axis._minorAutoInterval = interval / 5; + axis.tickInterval = interval; } + return positions; + }; + LogarithmicAxisAdditions.prototype.lin2log = function (num) { + return Math.pow(10, num); + }; + LogarithmicAxisAdditions.prototype.log2lin = function (num) { + return Math.log(num) / Math.LN10; + }; + return LogarithmicAxisAdditions; +}()); +var LogarithmicAxis = /** @class */ (function () { + function LogarithmicAxis() { } - // Set the axis-level tickInterval variable - if (!minor) { - axis.tickInterval = interval; - } - return positions; -}; -/** - * @private - * @function Highcharts.Axis#log2lin - * - * @param {number} num - * - * @return {number} - */ -Axis.prototype.log2lin = function (num) { - return Math.log(num) / Math.LN10; -}; -/** - * @private - * @function Highcharts.Axis#lin2log - * - * @param {number} num - * - * @return {number} - */ -Axis.prototype.lin2log = function (num) { - return Math.pow(10, num); -}; + /** + * Provides logarithmic support for axes. + * + * @private + */ + LogarithmicAxis.compose = function (AxisClass) { + /* eslint-disable no-invalid-this */ + // HC <= 8 backwards compatibility, allow wrapping + // Axis.prototype.lin2log and log2lin + // @todo Remove this in next major + var axisProto = AxisClass.prototype; + var logAxisProto = LogarithmicAxisAdditions.prototype; + axisProto.log2lin = logAxisProto.log2lin; + axisProto.lin2log = logAxisProto.lin2log; + addEvent(AxisClass, 'init', function (e) { + var axis = this; + var log = axis.logarithmic; + var options = e.userOptions; + if (options.type === 'logarithmic') { + if (!log) { + axis.logarithmic = new LogarithmicAxisAdditions(axis); + } + } + else if (log) { + log.destroy(); + axis.logarithmic = void 0; + } + // HC <= 8 backwards compatibility, allow wrapping + // Axis.prototype.lin2log and log2lin + // @todo Remove this in next major + var logarithmic = axis.logarithmic; + if (logarithmic) { + if (axis.log2lin !== logarithmic.log2lin) { + logarithmic.log2lin = axis.log2lin.bind(axis); + } + if (axis.lin2log !== logarithmic.lin2log) { + logarithmic.lin2log = axis.lin2log.bind(axis); + } + } + }); + addEvent(AxisClass, 'afterInit', function () { + var axis = this; + var log = axis.logarithmic; + // extend logarithmic axis + if (log) { + axis.lin2val = function (num) { + return log.lin2log(num); + }; + axis.val2lin = function (num) { + return log.log2lin(num); + }; + } + }); + }; + return LogarithmicAxis; +}()); +LogarithmicAxis.compose(Axis); // @todo move to factory functions +export default LogarithmicAxis; diff --git a/js/parts/OrdinalAxis.js b/js/parts/OrdinalAxis.js index 1bd8592a6fd..842c2f13a05 100644 --- a/js/parts/OrdinalAxis.js +++ b/js/parts/OrdinalAxis.js @@ -47,7 +47,7 @@ var OrdinalAxisAdditions = /** @class */ (function () { * @private */ OrdinalAxisAdditions.prototype.getExtendedPositions = function () { - var ordinal = this, axis = ordinal.axis, axisPrototype = axis.constructor.prototype, chart = axis.chart, grouping = axis.series[0].currentDataGrouping, ordinalIndex = ordinal.index, key = grouping ? + var ordinal = this, axis = ordinal.axis, axisProto = axis.constructor.prototype, chart = axis.chart, grouping = axis.series[0].currentDataGrouping, ordinalIndex = ordinal.index, key = grouping ? grouping.count + grouping.unitName : 'raw', overscroll = axis.options.overscroll, extremes = axis.getExtremes(), fakeAxis, fakeSeries; // If this is the first time, or the ordinal index is deleted by @@ -72,8 +72,8 @@ var OrdinalAxisAdditions = /** @class */ (function () { ordinal: true }, ordinal: {}, - ordinal2lin: axisPrototype.ordinal2lin, - val2lin: axisPrototype.val2lin // #2590 + ordinal2lin: axisProto.ordinal2lin, + val2lin: axisProto.val2lin // #2590 }; fakeAxis.ordinal.axis = fakeAxis; // Add the fake series to hold the full data, then apply @@ -233,13 +233,13 @@ var OrdinalAxis = /** @class */ (function () { * Series class to use. */ OrdinalAxis.compose = function (AxisClass, ChartClass, SeriesClass) { - var axisPrototype = AxisClass.prototype; + var axisProto = AxisClass.prototype; /** * Calculate the ordinal positions before tick positions are calculated. * * @private */ - axisPrototype.beforeSetTickPositions = function () { + axisProto.beforeSetTickPositions = function () { var axis = this, ordinal = axis.ordinal, len, ordinalPositions = [], uniqueOrdinalPositions, useOrdinal = false, dist, extremes = axis.getExtremes(), min = extremes.min, max = extremes.max, minIndex, maxIndex, slope, hasBreaks = axis.isXAxis && !!axis.options.breaks, isOrdinal = axis.options.ordinal, overscrollPointsRange = Number.MAX_VALUE, ignoreHiddenSeries = axis.chart.options.chart.ignoreHiddenSeries, i, hasBoostedSeries; // Apply the ordinal logic if (isOrdinal || hasBreaks) { // #4167 YAxis is never ordinal ? @@ -516,7 +516,7 @@ var OrdinalAxis = /** @class */ (function () { * * @return {number} */ - axisPrototype.lin2val = function (val, fromIndex) { + axisProto.lin2val = function (val, fromIndex) { var axis = this, ordinal = axis.ordinal, ordinalPositions = ordinal.positions, ret; // the visible range contains only equally spaced values if (!ordinalPositions) { @@ -587,7 +587,7 @@ var OrdinalAxis = /** @class */ (function () { * * @return {number} */ - axisPrototype.val2lin = function (val, toIndex) { + axisProto.val2lin = function (val, toIndex) { var axis = this, ordinal = axis.ordinal, ordinalPositions = ordinal.positions, ret; if (!ordinalPositions) { ret = val; @@ -623,7 +623,7 @@ var OrdinalAxis = /** @class */ (function () { return ret; }; // Record this to prevent overwriting by broken-axis module (#5979) - axisPrototype.ordinal2lin = axisPrototype.val2lin; + axisProto.ordinal2lin = axisProto.val2lin; addEvent(AxisClass, 'afterInit', function () { this.ordinal = new OrdinalAxisAdditions(this); }); diff --git a/js/parts/PlotLineOrBand.js b/js/parts/PlotLineOrBand.js index 8aabce1a9c7..21f6d4bef64 100644 --- a/js/parts/PlotLineOrBand.js +++ b/js/parts/PlotLineOrBand.js @@ -61,15 +61,15 @@ var PlotLineOrBand = /** @class */ (function () { */ PlotLineOrBand.prototype.render = function () { H.fireEvent(this, 'render'); - var plotLine = this, axis = plotLine.axis, horiz = axis.horiz, options = plotLine.options, optionsLabel = options.label, label = plotLine.label, to = options.to, from = options.from, value = options.value, isBand = defined(from) && defined(to), isLine = defined(value), svgElem = plotLine.svgElem, isNew = !svgElem, path = [], color = options.color, zIndex = pick(options.zIndex, 0), events = options.events, attribs = { + var plotLine = this, axis = plotLine.axis, horiz = axis.horiz, log = axis.logarithmic, options = plotLine.options, optionsLabel = options.label, label = plotLine.label, to = options.to, from = options.from, value = options.value, isBand = defined(from) && defined(to), isLine = defined(value), svgElem = plotLine.svgElem, isNew = !svgElem, path = [], color = options.color, zIndex = pick(options.zIndex, 0), events = options.events, attribs = { 'class': 'highcharts-plot-' + (isBand ? 'band ' : 'line ') + (options.className || '') }, groupAttribs = {}, renderer = axis.chart.renderer, groupName = isBand ? 'bands' : 'lines', group; // logarithmic conversion - if (axis.isLog) { - from = axis.log2lin(from); - to = axis.log2lin(to); - value = axis.log2lin(value); + if (log) { + from = log.log2lin(from); + to = log.log2lin(to); + value = log.log2lin(value); } // Set the presentational attributes if (!axis.chart.styledMode) { diff --git a/js/parts/Series.js b/js/parts/Series.js index efa27aee6ca..28688242bb5 100644 --- a/js/parts/Series.js +++ b/js/parts/Series.js @@ -3512,7 +3512,7 @@ null, processedXData = series.xData, processedYData = series.yData, dataLength = processedXData.length, croppedData, cropStart = 0, cropped, distance, closestPointRange, xAxis = series.xAxis, i, // loop variable options = series.options, cropThreshold = options.cropThreshold, getExtremesFromAll = series.getExtremesFromAll || options.getExtremesFromAll, // #4599 - isCartesian = series.isCartesian, xExtremes, val2lin = xAxis && xAxis.val2lin, isLog = xAxis && xAxis.isLog, throwOnUnsorted = series.requireSorting, min, max; + isCartesian = series.isCartesian, xExtremes, val2lin = xAxis && xAxis.val2lin, isLog = !!(xAxis && xAxis.logarithmic), throwOnUnsorted = series.requireSorting, min, max; // If the series data or axes haven't changed, don't go through // this. Return false to pass the message on to override methods // like in data grouping. diff --git a/js/parts/StockChart.js b/js/parts/StockChart.js index 0d3ba3ff130..2aeb6b86e03 100644 --- a/js/parts/StockChart.js +++ b/js/parts/StockChart.js @@ -423,7 +423,7 @@ addEvent(Axis, 'afterDrawCrosshair', function (event) { !this.cross) { return; } - var chart = this.chart, options = this.options.crosshair.label, // the label's options + 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 @@ -431,14 +431,10 @@ addEvent(Axis, 'afterDrawCrosshair', function (event) { 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, lin2log = this.lin2log, min, max; - if (this.isLog) { - min = lin2log(this.min); - max = lin2log(this.max); - } - else { - min = this.min; - max = this.max; + 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') : diff --git a/js/parts/Tick.js b/js/parts/Tick.js index 00390d95fc2..10b3e64c036 100644 --- a/js/parts/Tick.js +++ b/js/parts/Tick.js @@ -103,7 +103,7 @@ var Tick = /** @class */ (function () { * @return {void} */ Tick.prototype.addLabel = function () { - var tick = this, axis = tick.axis, options = axis.options, chart = axis.chart, categories = axis.categories, names = axis.names, pos = tick.pos, labelOptions = pick(tick.options && tick.options.labels, options.labels), str, tickPositions = axis.tickPositions, isFirst = pos === tickPositions[0], isLast = pos === tickPositions[tickPositions.length - 1], value = this.parameters.category || (categories ? + var tick = this, axis = tick.axis, options = axis.options, chart = axis.chart, categories = axis.categories, log = axis.logarithmic, names = axis.names, pos = tick.pos, labelOptions = pick(tick.options && tick.options.labels, options.labels), str, tickPositions = axis.tickPositions, isFirst = pos === tickPositions[0], isLast = pos === tickPositions[tickPositions.length - 1], value = this.parameters.category || (categories ? pick(categories[pos], names[pos], pos) : pos), label = tick.label, animateLabels = (!labelOptions.step || labelOptions.step === 1) && axis.tickInterval === 1, tickPositionInfo = tickPositions.info, dateTimeLabelFormat, dateTimeLabelFormats, i, list; @@ -138,7 +138,7 @@ var Tick = /** @class */ (function () { isLast: isLast, dateTimeLabelFormat: dateTimeLabelFormat, tickPositionInfo: tickPositionInfo, - value: axis.isLog ? correctFloat(axis.lin2log(value)) : value, + value: log ? correctFloat(log.lin2log(value)) : value, pos: pos }; str = axis.labelFormatter.call(tick.formatCtx, this.formatCtx); diff --git a/samples/highcharts/coloraxis/logarithmic-with-emulate-negative-values/demo.js b/samples/highcharts/coloraxis/logarithmic-with-emulate-negative-values/demo.js index b004c7369ae..6ea95136d6d 100644 --- a/samples/highcharts/coloraxis/logarithmic-with-emulate-negative-values/demo.js +++ b/samples/highcharts/coloraxis/logarithmic-with-emulate-negative-values/demo.js @@ -4,38 +4,38 @@ * logarithmic axis never reaches or crosses zero. */ (function (H) { - // Pass error messages - H.addEvent(H.ColorAxis, 'init', function (e) { - this.allowNegativeLog = e.userOptions.allowNegativeLog; - }); + H.addEvent(H.Axis, 'afterInit', function () { + const logarithmic = this.logarithmic; - // Override conversions - H.wrap(H.ColorAxis.prototype, 'log2lin', function (proceed, num) { - if (!this.allowNegativeLog) { - return proceed.call(this, num); - } + if (logarithmic && this.options.allowNegativeLog) { - var isNegative = num < 0, - adjustedNum = Math.abs(num), - result; - if (adjustedNum < 10) { - adjustedNum += (10 - adjustedNum) / 10; - } - result = Math.log(adjustedNum) / Math.LN10; - return isNegative ? -result : result; - }); - H.wrap(H.ColorAxis.prototype, 'lin2log', function (proceed, num) { - if (!this.allowNegativeLog) { - return proceed.call(this, num); - } + // Avoid errors on negative numbers on a log axis + this.positiveValuesOnly = false; + + // Override the converter functions + logarithmic.log2lin = num => { + const isNegative = num < 0; + + let adjustedNum = Math.abs(num); + + if (adjustedNum < 10) { + adjustedNum += (10 - adjustedNum) / 10; + } + + const result = Math.log(adjustedNum) / Math.LN10; + return isNegative ? -result : result; + }; + + logarithmic.lin2log = num => { + const isNegative = num < 0; - var isNegative = num < 0, - absNum = Math.abs(num), - result = Math.pow(10, absNum); - if (result < 10) { - result = (10 * (result - 1)) / (10 - 1); + let result = Math.pow(10, Math.abs(num)); + if (result < 10) { + result = (10 * (result - 1)) / (10 - 1); + } + return isNegative ? -result : result; + }; } - return isNegative ? -result : result; }); }(Highcharts)); diff --git a/samples/highcharts/yaxis/type-log-negative-legacy/demo.css b/samples/highcharts/yaxis/type-log-negative-legacy/demo.css new file mode 100644 index 00000000000..8fd024e55f4 --- /dev/null +++ b/samples/highcharts/yaxis/type-log-negative-legacy/demo.css @@ -0,0 +1,5 @@ +#container { + min-width: 320px; + max-width: 800px; + margin: 0 auto; +} \ No newline at end of file diff --git a/samples/highcharts/yaxis/type-log-negative-legacy/demo.details b/samples/highcharts/yaxis/type-log-negative-legacy/demo.details new file mode 100644 index 00000000000..7b061cbfd99 --- /dev/null +++ b/samples/highcharts/yaxis/type-log-negative-legacy/demo.details @@ -0,0 +1,6 @@ +--- + name: Highcharts Demo + authors: + - Torstein Hønsi + js_wrap: b +... \ No newline at end of file diff --git a/samples/highcharts/yaxis/type-log-negative-legacy/demo.html b/samples/highcharts/yaxis/type-log-negative-legacy/demo.html new file mode 100644 index 00000000000..ee09ee8297d --- /dev/null +++ b/samples/highcharts/yaxis/type-log-negative-legacy/demo.html @@ -0,0 +1,2 @@ + +
\ No newline at end of file diff --git a/samples/highcharts/yaxis/type-log-negative-legacy/demo.js b/samples/highcharts/yaxis/type-log-negative-legacy/demo.js new file mode 100644 index 00000000000..2675a0328e3 --- /dev/null +++ b/samples/highcharts/yaxis/type-log-negative-legacy/demo.js @@ -0,0 +1,73 @@ +/** + * Custom Axis extension to allow emulation of negative values on a logarithmic + * Y axis. Note that the scale is not mathematically correct, as a true + * logarithmic axis never reaches or crosses zero. + */ +(function (H) { + H.addEvent(H.Axis, 'init', function (e) { + this.allowNegativeLog = e.userOptions.allowNegativeLog; + }); + + // Override conversions + H.wrap(H.Axis.prototype, 'log2lin', function (proceed, num) { + + if (!this.allowNegativeLog) { + return proceed.call(this, num); + } + + var isNegative = num < 0, + adjustedNum = Math.abs(num), + result; + if (adjustedNum < 10) { + adjustedNum += (10 - adjustedNum) / 10; + } + result = Math.log(adjustedNum) / Math.LN10; + return isNegative ? -result : result; + }); + H.wrap(H.Axis.prototype, 'lin2log', function (proceed, num) { + if (!this.allowNegativeLog) { + return proceed.call(this, num); + } + + var isNegative = num < 0, + absNum = Math.abs(num), + result = Math.pow(10, absNum); + if (result < 10) { + result = (10 * (result - 1)) / (10 - 1); + } + return isNegative ? -result : result; + }); +}(Highcharts)); + + +Highcharts.chart('container', { + + title: { + text: 'Logarithmic axis with custom conversion allows negative values' + }, + + subtitle: { + text: 'Note: This sample exists for legacy testing purposes and will be removed after version 8', + style: { + color: 'red', + fontSize: 30 + }, + floating: true, + y: 150 + }, + + xAxis: { + categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + }, + + yAxis: { + type: 'logarithmic', + allowNegativeLog: true + }, + + series: [{ + data: [-1000, -100, -10, -1, -0.1, 0, 0.1, 1, 10, 100, 1000] + }] + +}); \ No newline at end of file diff --git a/samples/highcharts/yaxis/type-log-negative/demo.js b/samples/highcharts/yaxis/type-log-negative/demo.js index 62ec555c894..5c0487c0841 100644 --- a/samples/highcharts/yaxis/type-log-negative/demo.js +++ b/samples/highcharts/yaxis/type-log-negative/demo.js @@ -4,38 +4,38 @@ * logarithmic axis never reaches or crosses zero. */ (function (H) { - H.addEvent(H.Axis, 'init', function (e) { - this.allowNegativeLog = e.userOptions.allowNegativeLog; - }); + H.addEvent(H.Axis, 'afterInit', function () { + const logarithmic = this.logarithmic; - // Override conversions - H.wrap(H.Axis.prototype, 'log2lin', function (proceed, num) { + if (logarithmic && this.options.allowNegativeLog) { - if (!this.allowNegativeLog) { - return proceed.call(this, num); - } + // Avoid errors on negative numbers on a log axis + this.positiveValuesOnly = false; - var isNegative = num < 0, - adjustedNum = Math.abs(num), - result; - if (adjustedNum < 10) { - adjustedNum += (10 - adjustedNum) / 10; - } - result = Math.log(adjustedNum) / Math.LN10; - return isNegative ? -result : result; - }); - H.wrap(H.Axis.prototype, 'lin2log', function (proceed, num) { - if (!this.allowNegativeLog) { - return proceed.call(this, num); - } + // Override the converter functions + logarithmic.log2lin = num => { + const isNegative = num < 0; + + let adjustedNum = Math.abs(num); + + if (adjustedNum < 10) { + adjustedNum += (10 - adjustedNum) / 10; + } + + const result = Math.log(adjustedNum) / Math.LN10; + return isNegative ? -result : result; + }; + + logarithmic.lin2log = num => { + const isNegative = num < 0; - var isNegative = num < 0, - absNum = Math.abs(num), - result = Math.pow(10, absNum); - if (result < 10) { - result = (10 * (result - 1)) / (10 - 1); + let result = Math.pow(10, Math.abs(num)); + if (result < 10) { + result = (10 * (result - 1)) / (10 - 1); + } + return isNegative ? -result : result; + }; } - return isNegative ? -result : result; }); }(Highcharts)); diff --git a/ts/modules/boost/wgl-renderer.ts b/ts/modules/boost/wgl-renderer.ts index 3db294854f1..e3edc2fcb51 100644 --- a/ts/modules/boost/wgl-renderer.ts +++ b/ts/modules/boost/wgl-renderer.ts @@ -1112,7 +1112,7 @@ function GLRenderer( shader.setUniform('xAxisLen', axis.len); shader.setUniform('xAxisPos', axis.pos); shader.setUniform('xAxisCVSCoord', (!axis.horiz) as any); - shader.setUniform('xAxisIsLog', axis.isLog as any); + shader.setUniform('xAxisIsLog', (!!axis.logarithmic) as any); shader.setUniform('xAxisReversed', (!!axis.reversed) as any); } @@ -1133,7 +1133,7 @@ function GLRenderer( shader.setUniform('yAxisLen', axis.len); shader.setUniform('yAxisPos', axis.pos); shader.setUniform('yAxisCVSCoord', (!axis.horiz) as any); - shader.setUniform('yAxisIsLog', axis.isLog as any); + shader.setUniform('yAxisIsLog', (!!axis.logarithmic) as any); shader.setUniform('yAxisReversed', (!!axis.reversed) as any); } diff --git a/ts/modules/drag-panes.src.ts b/ts/modules/drag-panes.src.ts index 22f349746eb..99d9c7ecbc8 100644 --- a/ts/modules/drag-panes.src.ts +++ b/ts/modules/drag-panes.src.ts @@ -676,7 +676,7 @@ class AxisResizer { } // Keep resizer reference on axis update -Axis.prototype.keepProps.push('resizer'); +Axis.keepProps.push('resizer'); /* eslint-disable no-invalid-this */ // Add new AxisResizer, update or remove it diff --git a/ts/modules/parallel-coordinates.src.ts b/ts/modules/parallel-coordinates.src.ts index 9de67f3adf0..f484b5c2124 100644 --- a/ts/modules/parallel-coordinates.src.ts +++ b/ts/modules/parallel-coordinates.src.ts @@ -316,7 +316,7 @@ extend(ChartProto, /** @lends Highcharts.Chart.prototype */ { // On update, keep parallelPosition. -AxisProto.keepProps.push('parallelPosition'); +Axis.keepProps.push('parallelPosition'); // Update default options with predefined for a parallel coords. addEvent(Axis, 'afterSetOptions', function ( diff --git a/ts/modules/solid-gauge.src.ts b/ts/modules/solid-gauge.src.ts index 10c10224262..0137ab198bc 100644 --- a/ts/modules/solid-gauge.src.ts +++ b/ts/modules/solid-gauge.src.ts @@ -259,7 +259,7 @@ colorAxisMethods = { } else { - if (this.isLog) { + if (this.logarithmic) { value = this.val2lin(value); } pos = 1 - ((this.max - value) / (this.max - this.min)); diff --git a/ts/parts-3d/Series.ts b/ts/parts-3d/Series.ts index f9ac09f4ae5..25a1ca1d431 100644 --- a/ts/parts-3d/Series.ts +++ b/ts/parts-3d/Series.ts @@ -65,7 +65,7 @@ H.Series.prototype.translate3dPoints = function (): void { rawPoint = series.data[i]; if (zAxis && zAxis.translate) { - zValue = zAxis.isLog && zAxis.val2lin ? + zValue = zAxis.logarithmic && zAxis.val2lin ? zAxis.val2lin(rawPoint.z as any) : rawPoint.z; // #4562 rawPoint.plotZ = zAxis.translate(zValue as any); diff --git a/ts/parts-map/ColorAxis.ts b/ts/parts-map/ColorAxis.ts index e1d20714210..efe82d5c0b8 100644 --- a/ts/parts-map/ColorAxis.ts +++ b/ts/parts-map/ColorAxis.ts @@ -655,7 +655,7 @@ extend(ColorAxis.prototype, { 'legendItemWidth', 'legendItem', 'legendSymbol' - ].concat(Axis.prototype.keepProps), + ].concat(Axis.keepProps), /* eslint-disable no-invalid-this, valid-jsdoc */ @@ -892,8 +892,8 @@ extend(ColorAxis.prototype, { this: Highcharts.ColorAxis, value: number ): number { - if (this.isLog) { - value = this.val2lin(value); + if (this.logarithmic) { + value = this.logarithmic.log2lin(value); } return 1 - ( ((this.max as any) - value) / diff --git a/ts/parts-more/BubbleSeries.ts b/ts/parts-more/BubbleSeries.ts index 8671d82518f..9b802f2164e 100644 --- a/ts/parts-more/BubbleSeries.ts +++ b/ts/parts-more/BubbleSeries.ts @@ -725,7 +725,7 @@ Axis.prototype.beforePadding = function (this: Highcharts.Axis): void { }); // Apply the padding to the min and max properties - if (activeSeries.length && range > 0 && !this.isLog) { + if (activeSeries.length && range > 0 && !this.logarithmic) { pxMax -= axisLength; transA *= ( axisLength + diff --git a/ts/parts/Axis.ts b/ts/parts/Axis.ts index f58dd9b8e42..1d42e894698 100644 --- a/ts/parts/Axis.ts +++ b/ts/parts/Axis.ts @@ -203,6 +203,7 @@ declare global { accessibility?: XAxisAccessibilityOptions; alignTicks?: boolean; allowDecimals?: boolean; + allowNegativeLog?: boolean; alternateGridColor?: ( ColorString|GradientColorObject|PatternObject ); @@ -224,7 +225,6 @@ declare global { isX?: boolean; labels?: XAxisLabelsOptions; left?: (number|string); - linearToLogConverter?: undefined; lineColor?: (ColorString|GradientColorObject|PatternObject); lineWidth?: number; linkedTo?: number; @@ -320,6 +320,7 @@ declare global { public static defaultRightAxisOptions: AxisOptions; public static defaultTopAxisOptions: AxisOptions; public static defaultYAxisOptions: YAxisOptions; + public static keepProps: Array; public constructor(chart: Chart, userOptions: AxisOptions); public _addedPlotLB?: boolean; public allowZoomOutside?: boolean; @@ -354,12 +355,11 @@ declare global { public isDirty?: boolean; public isHidden?: boolean; public isLinked: boolean; - public isLog: boolean; public isOrdinal?: boolean; public isRadial?: boolean; public isXAxis?: boolean; public isZAxis?: boolean; - public keepProps: Array; + public keepProps?: Array; public labelAlign?: AlignValue; public labelEdge: Array; public labelFormatter: ( @@ -441,6 +441,7 @@ declare global { public generateTick(pos: number, i?: number): void; public getClosest(): number; public getExtremes(): ExtremesObject; + public getKeepProps(): Array; public getLinePath(lineWidth: number): SVGPathArray; public getLinearTickPositions( tickInterval: number, @@ -3766,6 +3767,10 @@ class Axis implements AxisComposition { } }; + // Properties to survive after destroy, needed for Axis.update (#4317, + // #5773, #5881). + public static keepProps = ['extKey', 'hcEvents', 'names', 'series', 'userMax', 'userMin']; + /* * * * Constructors @@ -3813,11 +3818,11 @@ class Axis implements AxisComposition { public isBroken?: boolean; public isDirty?: boolean; public isLinked: boolean = void 0 as any; - public isLog: boolean = void 0 as any; public isOrdinal?: boolean; public isRadial?: boolean; public isXAxis?: boolean; public isZAxis?: boolean; + public keepProps?: Array; public labelAlign?: Highcharts.AlignValue; public labelEdge: Array = void 0 as any; // @todo public labelFormatter: ( @@ -4037,8 +4042,7 @@ class Axis implements AxisComposition { axis.plotLinesAndBandsGroups = {}; // Shorthand types - axis.isLog = type === 'logarithmic'; - axis.positiveValuesOnly = axis.isLog && !(axis as any).allowNegativeLog; + axis.positiveValuesOnly = !!(axis.logarithmic && !options.allowNegativeLog); // Flag, if axis is linked to another axis axis.isLinked = defined(options.linkedTo); @@ -4152,13 +4156,6 @@ class Axis implements AxisComposition { } }); - // extend logarithmic axis - axis.lin2log = options.linearToLogConverter || axis.lin2log; - if (axis.isLog) { - axis.val2lin = axis.log2lin; - axis.lin2val = axis.lin2log; - } - fireEvent(this, 'afterInit'); } @@ -4223,7 +4220,7 @@ class Axis implements AxisComposition { // make sure the same symbol is added for all labels on a linear // axis - numericSymbolDetector = axis.isLog ? + numericSymbolDetector = axis.logarithmic ? Math.abs(value) : axis.tickInterval; const chart = this.chart; @@ -4448,7 +4445,7 @@ class Axis implements AxisComposition { doPostTranslate = ( axis.isOrdinal || axis.isBroken || - (axis.isLog && handleLog) + (axis.logarithmic && handleLog) ) && axis.lin2val; if (!localA) { @@ -4765,7 +4762,8 @@ class Axis implements AxisComposition { // long running script. So we don't draw them. if (range && range / minorTickInterval < axis.len / 3) { // #3875 - if (axis.isLog) { + const logarithmic = axis.logarithmic; + if (logarithmic) { // For each interval in the major ticks, compute the minor ticks // separately. this.paddedTicks.forEach(function ( @@ -4776,7 +4774,7 @@ class Axis implements AxisComposition { if (i) { minorTickPositions.push.apply( minorTickPositions, - axis.getLogTickPositions( + logarithmic.getLogTickPositions( minorTickInterval, paddedTicks[i - 1], paddedTicks[i], @@ -4834,6 +4832,7 @@ class Axis implements AxisComposition { options = axis.options, min = axis.min, max = axis.max, + log = axis.logarithmic, zoomOffset, spaceAvailable: boolean, closestDataRange: (number|undefined), @@ -4849,7 +4848,7 @@ class Axis implements AxisComposition { if ( axis.isXAxis && typeof axis.minRange === 'undefined' && - !axis.isLog + !log ) { if (defined(options.min) || defined(options.max)) { @@ -4896,8 +4895,8 @@ class Axis implements AxisComposition { ]; // If space is available, stay within the data range if (spaceAvailable) { - minArgs[2] = axis.isLog ? - axis.log2lin(axis.dataMin as any) : + minArgs[2] = axis.logarithmic ? + axis.logarithmic.log2lin(axis.dataMin as any) : axis.dataMin; } min = arrayMax(minArgs); @@ -4908,8 +4907,8 @@ class Axis implements AxisComposition { ]; // If space is availabe, stay within the data range if (spaceAvailable) { - maxArgs[2] = axis.isLog ? - axis.log2lin(axis.dataMax as any) : + maxArgs[2] = log ? + log.log2lin(axis.dataMax as any) : axis.dataMax; } @@ -5220,8 +5219,8 @@ class Axis implements AxisComposition { public setTickInterval(secondPass?: boolean): void { var axis: Highcharts.Axis = this as any, chart = axis.chart, + log = axis.logarithmic, options = axis.options, - isLog = axis.isLog, isXAxis = axis.isXAxis, isLinked = axis.isLinked, maxPadding = options.maxPadding, @@ -5285,7 +5284,7 @@ class Axis implements AxisComposition { } - if (isLog) { + if (log) { if ( axis.positiveValuesOnly && !secondPass && @@ -5299,8 +5298,8 @@ class Axis implements AxisComposition { // 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 as any), 16); - axis.max = correctFloat(axis.log2lin(axis.max as any), 16); + axis.min = correctFloat(log.log2lin(axis.min as any), 16); + axis.max = correctFloat(log.log2lin(axis.max as any), 16); } // handle zoomed range @@ -5474,7 +5473,7 @@ class Axis implements AxisComposition { } // for linear axes, get magnitude and normalize the interval - if (!axis.dateTime && !isLog && !tickIntervalOption) { + if (!axis.dateTime && !axis.logarithmic && !tickIntervalOption) { axis.tickInterval = normalizeTickInterval( axis.tickInterval, null as any, @@ -5598,8 +5597,8 @@ class Axis implements AxisComposition { this.closestPointRange, true ); - } else if (this.isLog) { - tickPositions = axis.getLogTickPositions( + } else if (axis.logarithmic) { + tickPositions = axis.logarithmic.getLogTickPositions( this.tickInterval, this.min as any, this.max as any @@ -5730,10 +5729,11 @@ class Axis implements AxisComposition { * True if there are other axes. */ public alignToOthers(): (boolean|undefined) { - var others = // Whether there is another axis to pair with this one + var axis: Highcharts.Axis = this as any, + others = // Whether there is another axis to pair with this one {} as Highcharts.AxisOptions, hasOther, - options = this.options; + options = axis.options; if ( // Only if alignTicks is true @@ -5746,7 +5746,7 @@ class Axis implements AxisComposition { // Don't try to align ticks on a log axis, they are not evenly // spaced (#6021) - !this.isLog + !axis.logarithmic ) { (this.chart as any)[this.coll].forEach(function ( axis: Highcharts.Axis @@ -5781,7 +5781,8 @@ class Axis implements AxisComposition { * @function Highcharts.Axis#getTickAmount */ public getTickAmount(): void { - var options = this.options, + var axis: Highcharts.Axis = this as any, + options = this.options, tickAmount = options.tickAmount, tickPixelInterval = options.tickPixelInterval; @@ -5789,7 +5790,7 @@ class Axis implements AxisComposition { !defined(options.tickInterval) && this.len < (tickPixelInterval as any) && !this.isRadial && - !this.isLog && + !axis.logarithmic && options.startOnTick && options.endOnTick ) { @@ -6184,15 +6185,15 @@ class Axis implements AxisComposition { * An object containing extremes information. */ public getExtremes(): Highcharts.ExtremesObject { - var axis: Highcharts.Axis = this as any, - isLog = axis.isLog; + const axis: Highcharts.Axis = this as any; + const log = axis.logarithmic; return { - min: isLog ? - correctFloat(axis.lin2log(axis.min as any)) : + min: log ? + correctFloat(log.lin2log(axis.min as any)) : axis.min as any, - max: isLog ? - correctFloat(axis.lin2log(axis.max as any)) : + max: log ? + correctFloat(log.lin2log(axis.max as any)) : axis.max as any, dataMin: axis.dataMin as any, dataMax: axis.dataMax as any, @@ -6216,9 +6217,9 @@ class Axis implements AxisComposition { */ public getThreshold(threshold: number): (number|undefined) { var axis: Highcharts.Axis = this as any, - isLog = axis.isLog, - realMin = isLog ? axis.lin2log(axis.min as any) : axis.min as any, - realMax = isLog ? axis.lin2log(axis.max as any) : axis.max as any; + log = axis.logarithmic, + realMin = log ? log.lin2log(axis.min as any) : axis.min as any, + realMax = log ? log.lin2log(axis.max as any) : axis.max as any; if (threshold === null || threshold === -Infinity) { threshold = realMin; @@ -7190,9 +7191,9 @@ class Axis implements AxisComposition { public render(): void { var axis: Highcharts.Axis = this as any, chart = axis.chart, + log = axis.logarithmic, renderer = chart.renderer, options = axis.options, - isLog = axis.isLog, isLinked = axis.isLinked, tickPositions = axis.tickPositions, axisTitle = axis.axisTitle, @@ -7278,8 +7279,8 @@ class Axis implements AxisComposition { } from = pos + tickmarkOffset; // #949 alternateBands[pos].options = { - from: isLog ? axis.lin2log(from) : from, - to: isLog ? axis.lin2log(to) : to, + from: log ? log.lin2log(from) : from, + to: log ? log.lin2log(to) : to, color: alternateGridColor }; alternateBands[pos].render(); @@ -7414,6 +7415,19 @@ class Axis implements AxisComposition { } + /** + * Returns an array of axis properties, that should be untouched during + * reinitialization. + * + * @private + * @function Highcharts.Axis#getKeepProps + * + * @return {Array} + */ + public getKeepProps(): Array { + return (this.keepProps || Axis.keepProps); + } + /** * Destroys an Axis instance. See {@link Axis#remove} for the API endpoint * to fully remove the axis. @@ -7484,7 +7498,7 @@ class Axis implements AxisComposition { // Delete all properties and fall back to the prototype. objectEach(axis, function (val: any, key: string): void { - if (axis.keepProps.indexOf(key) === -1) { + if (axis.getKeepProps().indexOf(key) === -1) { delete (axis as any)[key]; } }); @@ -7650,18 +7664,6 @@ class Axis implements AxisComposition { } } -interface Axis { - keepProps: Array; -} - -extend(Axis.prototype, { - - // Properties to survive after destroy, needed for Axis.update (#4317, - // #5773, #5881). - keepProps: ['extKey', 'hcEvents', 'names', 'series', 'userMax', 'userMin'] - -}); - H.Axis = Axis as any; export default H.Axis; diff --git a/ts/parts/LogarithmicAxis.ts b/ts/parts/LogarithmicAxis.ts index 5502dbf0abc..145c3aafa90 100644 --- a/ts/parts/LogarithmicAxis.ts +++ b/ts/parts/LogarithmicAxis.ts @@ -10,189 +10,269 @@ 'use strict'; -import H from './Globals.js'; +import Axis from './Axis.js'; +import U from './Utilities.js'; +const { + addEvent, + getMagnitude, + normalizeTickInterval, + pick +} = U; +// HC <= 8 backwards compatibility, allow wrapping Axis.prototype.lin2log and +// log2lin +// @todo Remove this in next major /** - * Internal types + * Internal, deprecated types * @private */ declare global { namespace Highcharts { interface Axis { - _minorAutoInterval?: (null|number); - getLogTickPositions( - interval: number, - min: number, - max: number, - minor?: boolean - ): Array; + /** @deprecated */ lin2log(num: number): number; + /** @deprecated */ log2lin(num: number): number; } } } -import U from './Utilities.js'; -const { - getMagnitude, - normalizeTickInterval, - pick -} = U; - -var Axis = H.Axis; - -/* ************************************************************************** * - * Methods defined on the Axis prototype - * ************************************************************************** */ - /* eslint-disable valid-jsdoc */ /** - * Set the tick positions of a logarithmic axis. + * Provides logarithmic support for axes. * * @private - * @function Highcharts.Axis#getLogTickPositions - * @param {number} interval - * @param {number} min - * @param {number} max - * @param {boolean} [minor] - * @return {Array} + * @class */ -Axis.prototype.getLogTickPositions = function ( - this: Highcharts.Axis, - interval: number, - min: number, - max: number, - minor?: boolean -): Array { - var axis = this, - options = axis.options, - axisLength = axis.len, - // Since we use this method for both major and minor ticks, - // use a local variable and return the result - positions = []; +class LogarithmicAxisAdditions { - // Reset - if (!minor) { - axis._minorAutoInterval = null; + /* * + * + * Constructors + * + * */ + + public constructor(axis: LogarithmicAxis) { + this.axis = axis; } - // First case: All ticks fall on whole logarithms: 1, 10, 100 etc. - if (interval >= 0.5) { - interval = Math.round(interval); - positions = axis.getLinearTickPositions(interval, min, max); - - // Second case: We need intermediary ticks. For example - // 1, 2, 4, 6, 8, 10, 20, 40 etc. - } else if (interval >= 0.08) { - var roundedMin = Math.floor(min), - intermediate, - i, - j, - len, - pos, - lastPos, - break2; - - if (interval > 0.3) { - intermediate = [1, 2, 4]; - - // 0.2 equals five minor ticks per 1, 10, 100 etc - } else if (interval > 0.15) { - intermediate = [1, 2, 4, 6, 8]; - } else { // 0.1 equals ten minor ticks per 1, 10, 100 etc - intermediate = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + /* * + * + * Properties + * + * */ + + public axis: LogarithmicAxis; + public minorAutoInterval?: number; + + /* * + * + * Functions + * + * */ + + public destroy(): void { + this.axis = void 0 as any; + this.minorAutoInterval = void 0; + } + + /** + * Set the tick positions of a logarithmic axis. + */ + public getLogTickPositions( + interval: number, + min: number, + max: number, + minor?: boolean + ): Array { + const log = this; + const axis = log.axis; + const axisLength = axis.len; + const options = axis.options; + + // Since we use this method for both major and minor ticks, + // use a local variable and return the result + let positions = []; + + // Reset + if (!minor) { + log.minorAutoInterval = void 0; } - for (i = roundedMin; i < max + 1 && !break2; i++) { - len = intermediate.length; - for (j = 0; j < len && !break2; j++) { - pos = axis.log2lin(axis.lin2log(i) * intermediate[j]); - // #1670, lastPos is #3113 - if ( - pos > min && - (!minor || (lastPos as any) <= max) && - typeof lastPos !== 'undefined' - ) { - positions.push(lastPos); - } + // First case: All ticks fall on whole logarithms: 1, 10, 100 etc. + if (interval >= 0.5) { + interval = Math.round(interval); + positions = axis.getLinearTickPositions(interval, min, max); + + // Second case: We need intermediary ticks. For example + // 1, 2, 4, 6, 8, 10, 20, 40 etc. + } else if (interval >= 0.08) { + var roundedMin = Math.floor(min), + intermediate, + i, + j, + len, + pos, + lastPos, + break2; + + if (interval > 0.3) { + intermediate = [1, 2, 4]; + + // 0.2 equals five minor ticks per 1, 10, 100 etc + } else if (interval > 0.15) { + intermediate = [1, 2, 4, 6, 8]; + } else { // 0.1 equals ten minor ticks per 1, 10, 100 etc + intermediate = [1, 2, 3, 4, 5, 6, 7, 8, 9]; + } - if ((lastPos as any) > max) { - break2 = true; + for (i = roundedMin; i < max + 1 && !break2; i++) { + len = intermediate.length; + for (j = 0; j < len && !break2; j++) { + pos = log.log2lin(log.lin2log(i) * intermediate[j]); + // #1670, lastPos is #3113 + if ( + pos > min && + (!minor || (lastPos as any) <= max) && + typeof lastPos !== 'undefined' + ) { + positions.push(lastPos); + } + + if ((lastPos as any) > max) { + break2 = true; + } + lastPos = pos; } - lastPos = pos; } - } - // Third case: We are so deep in between whole logarithmic values that - // we might as well handle the tick positions like a linear axis. For - // example 1.01, 1.02, 1.03, 1.04. - } else { - var realMin = axis.lin2log(min), - realMax = axis.lin2log(max), - tickIntervalOption = minor ? - this.getMinorTickInterval() : - options.tickInterval, - filteredTickIntervalOption = tickIntervalOption === 'auto' ? - null : - tickIntervalOption, - tickPixelIntervalOption = - (options.tickPixelInterval as any) / (minor ? 5 : 1), - totalPixelLength = minor ? - axisLength / axis.tickPositions.length : - axisLength; - - interval = pick( - filteredTickIntervalOption, - axis._minorAutoInterval, - (realMax - realMin) * - tickPixelIntervalOption / (totalPixelLength || 1) - ); - - interval = normalizeTickInterval( - interval, - null as any, - getMagnitude(interval) - ); - - positions = axis.getLinearTickPositions( - interval, - realMin, - realMax - ).map(axis.log2lin); + // Third case: We are so deep in between whole logarithmic values that + // we might as well handle the tick positions like a linear axis. For + // example 1.01, 1.02, 1.03, 1.04. + } else { + var realMin = log.lin2log(min), + realMax = log.lin2log(max), + tickIntervalOption = minor ? + axis.getMinorTickInterval() : + options.tickInterval, + filteredTickIntervalOption = tickIntervalOption === 'auto' ? + null : + tickIntervalOption, + tickPixelIntervalOption = + (options.tickPixelInterval as any) / (minor ? 5 : 1), + totalPixelLength = minor ? + axisLength / axis.tickPositions.length : + axisLength; + + interval = pick( + filteredTickIntervalOption, + log.minorAutoInterval, + (realMax - realMin) * + tickPixelIntervalOption / (totalPixelLength || 1) + ); + + interval = normalizeTickInterval( + interval, + void 0, + getMagnitude(interval) + ); + positions = axis.getLinearTickPositions( + interval, + realMin, + realMax + ).map(log.log2lin); + + if (!minor) { + log.minorAutoInterval = interval / 5; + } + } + + // Set the axis-level tickInterval variable if (!minor) { - axis._minorAutoInterval = interval / 5; + axis.tickInterval = interval; } + return positions; } - // Set the axis-level tickInterval variable - if (!minor) { - axis.tickInterval = interval; + public lin2log(num: number): number { + return Math.pow(10, num); } - return positions; -}; -/** - * @private - * @function Highcharts.Axis#log2lin - * - * @param {number} num - * - * @return {number} - */ -Axis.prototype.log2lin = function (this: Highcharts.Axis, num: number): number { - return Math.log(num) / Math.LN10; -}; + public log2lin(num: number): number { + return Math.log(num) / Math.LN10; + } -/** - * @private - * @function Highcharts.Axis#lin2log - * - * @param {number} num - * - * @return {number} - */ -Axis.prototype.lin2log = function (this: Highcharts.Axis, num: number): number { - return Math.pow(10, num); -}; +} + +class LogarithmicAxis { + + /** + * Provides logarithmic support for axes. + * + * @private + */ + public static compose(AxisClass: typeof Axis): void { + + /* eslint-disable no-invalid-this */ + + // HC <= 8 backwards compatibility, allow wrapping + // Axis.prototype.lin2log and log2lin + // @todo Remove this in next major + const axisProto = AxisClass.prototype; + const logAxisProto = LogarithmicAxisAdditions.prototype; + axisProto.log2lin = logAxisProto.log2lin; + axisProto.lin2log = logAxisProto.lin2log; + + addEvent(AxisClass, 'init', function (e: { userOptions: Axis['options'] }): void { + const axis = this; + const log = axis.logarithmic; + const options = e.userOptions; + + if (options.type === 'logarithmic') { + if (!log) { + axis.logarithmic = new LogarithmicAxisAdditions(axis as LogarithmicAxis); + } + } else if (log) { + log.destroy(); + axis.logarithmic = void 0; + } + + // HC <= 8 backwards compatibility, allow wrapping + // Axis.prototype.lin2log and log2lin + // @todo Remove this in next major + const logarithmic = axis.logarithmic; + if (logarithmic) { + if (axis.log2lin !== logarithmic.log2lin) { + logarithmic.log2lin = axis.log2lin.bind(axis); + } + if (axis.lin2log !== logarithmic.lin2log) { + logarithmic.lin2log = axis.lin2log.bind(axis); + } + } + }); + + addEvent(AxisClass, 'afterInit', function (): void { + const axis = this as LogarithmicAxis; + const log = axis.logarithmic; + // extend logarithmic axis + if (log) { + axis.lin2val = function (num: number): number { + return log.lin2log(num); + }; + axis.val2lin = function (num: number): number { + return log.log2lin(num); + }; + } + }); + } +} + +interface LogarithmicAxis extends Axis { + logarithmic: LogarithmicAxisAdditions; +} + +LogarithmicAxis.compose(Axis); // @todo move to factory functions + +export default LogarithmicAxis; diff --git a/ts/parts/OrdinalAxis.ts b/ts/parts/OrdinalAxis.ts index 286794e2ae2..587273d6b55 100644 --- a/ts/parts/OrdinalAxis.ts +++ b/ts/parts/OrdinalAxis.ts @@ -107,7 +107,7 @@ class OrdinalAxisAdditions { public getExtendedPositions(): Array { var ordinal = this, axis = ordinal.axis, - axisPrototype = axis.constructor.prototype, + axisProto = axis.constructor.prototype, chart = axis.chart, grouping = axis.series[0].currentDataGrouping, ordinalIndex = ordinal.index, @@ -144,8 +144,8 @@ class OrdinalAxisAdditions { ordinal: true }, ordinal: {}, - ordinal2lin: axisPrototype.ordinal2lin, // #6276 - val2lin: axisPrototype.val2lin // #2590 + ordinal2lin: axisProto.ordinal2lin, // #6276 + val2lin: axisProto.val2lin // #2590 } as any; fakeAxis.ordinal.axis = fakeAxis; @@ -353,14 +353,14 @@ class OrdinalAxis { SeriesClass: typeof Series ): void { - const axisPrototype = AxisClass.prototype as OrdinalAxis; + const axisProto = AxisClass.prototype as OrdinalAxis; /** * Calculate the ordinal positions before tick positions are calculated. * * @private */ - axisPrototype.beforeSetTickPositions = function (): void { + axisProto.beforeSetTickPositions = function (): void { var axis = this, ordinal = axis.ordinal, len, @@ -790,7 +790,7 @@ class OrdinalAxis { * * @return {number} */ - axisPrototype.lin2val = function ( + axisProto.lin2val = function ( val: number, fromIndex?: boolean ): number { @@ -881,7 +881,7 @@ class OrdinalAxis { * * @return {number} */ - axisPrototype.val2lin = function ( + axisProto.val2lin = function ( val: number, toIndex?: boolean ): number { @@ -930,7 +930,7 @@ class OrdinalAxis { return ret; }; // Record this to prevent overwriting by broken-axis module (#5979) - axisPrototype.ordinal2lin = axisPrototype.val2lin; + axisProto.ordinal2lin = axisProto.val2lin; addEvent(AxisClass, 'afterInit', function (): void { this.ordinal = new OrdinalAxisAdditions(this as OrdinalAxis); diff --git a/ts/parts/PlotLineOrBand.ts b/ts/parts/PlotLineOrBand.ts index fb208b2798b..eda890f3786 100644 --- a/ts/parts/PlotLineOrBand.ts +++ b/ts/parts/PlotLineOrBand.ts @@ -214,6 +214,7 @@ class PlotLineOrBand { var plotLine = this, axis = plotLine.axis, horiz = axis.horiz, + log = axis.logarithmic, options = plotLine.options as ( Highcharts.AxisPlotBandsOptions|Highcharts.AxisPlotLinesOptions ), @@ -240,10 +241,10 @@ class PlotLineOrBand { group; // logarithmic conversion - if (axis.isLog) { - from = axis.log2lin(from); - to = axis.log2lin(to); - value = axis.log2lin(value); + if (log) { + from = log.log2lin(from); + to = log.log2lin(to); + value = log.log2lin(value); } // Set the presentational attributes diff --git a/ts/parts/Series.ts b/ts/parts/Series.ts index 1cf7d5d8066..ecdfd98028d 100644 --- a/ts/parts/Series.ts +++ b/ts/parts/Series.ts @@ -4571,7 +4571,7 @@ H.Series = seriesType( isCartesian = series.isCartesian, xExtremes, val2lin = xAxis && xAxis.val2lin, - isLog = xAxis && xAxis.isLog, + isLog = !!(xAxis && xAxis.logarithmic), throwOnUnsorted = series.requireSorting, min, max; diff --git a/ts/parts/StockChart.ts b/ts/parts/StockChart.ts index 7b95927e8a5..6e62afc5338 100644 --- a/ts/parts/StockChart.ts +++ b/ts/parts/StockChart.ts @@ -647,6 +647,7 @@ addEvent(Axis, 'afterDrawCrosshair', function ( } var chart = this.chart, + log = this.logarithmic, options = (this.options.crosshair as any).label, // the label's options horiz = this.horiz, // axis orientation opposite = this.opposite, // axis position @@ -667,16 +668,12 @@ addEvent(Axis, 'afterDrawCrosshair', function ( // Use last available event (#5287) e = event.e || (this.cross && this.cross.e), point = event.point, - lin2log = this.lin2log, - min, - max; - - if (this.isLog) { - min = lin2log(this.min as any); - max = lin2log(this.max as any); - } else { - min = this.min; + min = this.min, max = this.max; + + if (log) { + min = log.lin2log(min as any); + max = log.lin2log(max as any); } align = (horiz ? 'center' : opposite ? diff --git a/ts/parts/Tick.ts b/ts/parts/Tick.ts index a2061f8ecbb..a10cedbe385 100644 --- a/ts/parts/Tick.ts +++ b/ts/parts/Tick.ts @@ -288,6 +288,7 @@ class Tick { options = axis.options, chart = axis.chart, categories = axis.categories, + log = axis.logarithmic, names = axis.names, pos = tick.pos, labelOptions = pick( @@ -351,7 +352,7 @@ class Tick { isLast: isLast, dateTimeLabelFormat: dateTimeLabelFormat as any, tickPositionInfo: tickPositionInfo, - value: axis.isLog ? correctFloat(axis.lin2log(value)) : value, + value: log ? correctFloat(log.lin2log(value)) : value, pos: pos }; str = (axis.labelFormatter as any).call(tick.formatCtx, this.formatCtx); diff --git a/ts/parts/axis/types.d.ts b/ts/parts/axis/types.d.ts index 62a0d36e5ea..d7ae6538d46 100644 --- a/ts/parts/axis/types.d.ts +++ b/ts/parts/axis/types.d.ts @@ -11,12 +11,14 @@ import type Axis from '../Axis'; import type DateTimeAxis from '../DateTimeAxis'; import type HiddenAxis from '../../parts-more/HiddenAxis'; +import type LogarithmicAxis from '../LogarithmicAxis'; import type OrdinalAxis from '../OrdinalAxis'; import type RadialAxis from '../../parts-more/RadialAxis'; import type ScrollbarAxis from '../ScrollbarAxis'; export interface AxisComposition { dateTime?: DateTimeAxis['dateTime']; + logarithmic?: LogarithmicAxis['logarithmic']; ordinal?: OrdinalAxis['ordinal']; scrollbar?: ScrollbarAxis['scrollbar']; } @@ -27,6 +29,7 @@ export interface AxisComposition { export type AxisType = ( Axis| HiddenAxis| + LogarithmicAxis| OrdinalAxis| RadialAxis| ScrollbarAxis