tupali/librerias/gantt/code/es-modules/parts/OrdinalAxis.js
2020-05-23 15:45:54 -05:00

760 lines
36 KiB
JavaScript

/* *
*
* (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.js';
import H from './Globals.js';
import U from './Utilities.js';
var addEvent = U.addEvent, css = U.css, defined = U.defined, pick = U.pick, timeUnits = U.timeUnits;
import './Chart.js';
// Has a dependency on Navigator due to the use of Axis.toFixedRange
import './Navigator.js';
import './Series.js';
var Chart = H.Chart, Series = H.Series;
/* eslint-disable valid-jsdoc */
var OrdinalAxisAdditions = /** @class */ (function () {
/* *
*
* Constructors
*
* */
/**
* @private
*/
function OrdinalAxisAdditions(axis) {
this.index = {};
this.axis = axis;
}
/* *
*
* Functions
*
* */
/**
* Get the ordinal positions for the entire data set. This is necessary
* in chart panning because we need to find out what points or data
* groups are available outside the visible range. When a panning
* operation starts, if an index for the given grouping does not exists,
* it is created and cached. This index is deleted on updated data, so
* it will be regenerated the next time a panning operation starts.
*
* @private
*/
OrdinalAxisAdditions.prototype.getExtendedPositions = function () {
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
// updatedData,
// create it.
if (!ordinalIndex) {
ordinalIndex = ordinal.index = {};
}
if (!ordinalIndex[key]) {
// Create a fake axis object where the extended ordinal
// positions are emulated
fakeAxis = {
series: [],
chart: chart,
getExtremes: function () {
return {
min: extremes.dataMin,
max: extremes.dataMax + overscroll
};
},
options: {
ordinal: true
},
ordinal: {},
ordinal2lin: axisProto.ordinal2lin,
val2lin: axisProto.val2lin // #2590
};
fakeAxis.ordinal.axis = fakeAxis;
// Add the fake series to hold the full data, then apply
// processData to it
axis.series.forEach(function (series) {
fakeSeries = {
xAxis: fakeAxis,
xData: series.xData.slice(),
chart: chart,
destroyGroupedData: H.noop,
getProcessedData: H.Series.prototype.getProcessedData
};
fakeSeries.xData = fakeSeries.xData.concat(ordinal.getOverscrollPositions());
fakeSeries.options = {
dataGrouping: grouping ? {
enabled: true,
forced: true,
// doesn't matter which, use the fastest
approximation: 'open',
units: [[
grouping.unitName,
[grouping.count]
]]
} : {
enabled: false
}
};
series.processData.apply(fakeSeries);
fakeAxis.series.push(fakeSeries);
});
// Run beforeSetTickPositions to compute the ordinalPositions
axis.beforeSetTickPositions.apply(fakeAxis);
// Cache it
ordinalIndex[key] = fakeAxis.ordinal.positions;
}
return ordinalIndex[key];
};
/**
* Find the factor to estimate how wide the plot area would have been if
* ordinal gaps were included. This value is used to compute an imagined
* plot width in order to establish the data grouping interval.
*
* A real world case is the intraday-candlestick example. Without this
* logic, it would show the correct data grouping when viewing a range
* within each day, but once moving the range to include the gap between
* two days, the interval would include the cut-away night hours and the
* data grouping would be wrong. So the below method tries to compensate
* by identifying the most common point interval, in this case days.
*
* An opposite case is presented in issue #718. We have a long array of
* daily data, then one point is appended one hour after the last point.
* We expect the data grouping not to change.
*
* In the future, if we find cases where this estimation doesn't work
* optimally, we might need to add a second pass to the data grouping
* logic, where we do another run with a greater interval if the number
* of data groups is more than a certain fraction of the desired group
* count.
*
* @private
*/
OrdinalAxisAdditions.prototype.getGroupIntervalFactor = function (xMin, xMax, series) {
var ordinal = this, axis = ordinal.axis, i, processedXData = series.processedXData, len = processedXData.length, distances = [], median, groupIntervalFactor = ordinal.groupIntervalFactor;
// Only do this computation for the first series, let the other
// inherit it (#2416)
if (!groupIntervalFactor) {
// Register all the distances in an array
for (i = 0; i < len - 1; i++) {
distances[i] =
processedXData[i + 1] - processedXData[i];
}
// Sort them and find the median
distances.sort(function (a, b) {
return a - b;
});
median = distances[Math.floor(len / 2)];
// Compensate for series that don't extend through the entire
// axis extent. #1675.
xMin = Math.max(xMin, processedXData[0]);
xMax = Math.min(xMax, processedXData[len - 1]);
ordinal.groupIntervalFactor = groupIntervalFactor =
(len * median) / (xMax - xMin);
}
// Return the factor needed for data grouping
return groupIntervalFactor;
};
/**
* Get ticks for an ordinal axis within a range where points don't
* exist. It is required when overscroll is enabled. We can't base on
* points, because we may not have any, so we use approximated
* pointRange and generate these ticks between Axis.dataMax,
* Axis.dataMax + Axis.overscroll evenly spaced. Used in panning and
* navigator scrolling.
*
* @private
*/
OrdinalAxisAdditions.prototype.getOverscrollPositions = function () {
var ordinal = this, axis = ordinal.axis, extraRange = axis.options.overscroll, distance = ordinal.overscrollPointsRange, positions = [], max = axis.dataMax;
if (defined(distance)) {
// Max + pointRange because we need to scroll to the last
positions.push(max);
while (max <= axis.dataMax + extraRange) {
max += distance;
positions.push(max);
}
}
return positions;
};
/**
* Make the tick intervals closer because the ordinal gaps make the
* ticks spread out or cluster.
*
* @private
*/
OrdinalAxisAdditions.prototype.postProcessTickInterval = function (tickInterval) {
// Problem: https://jsfiddle.net/highcharts/FQm4E/1/
// This is a case where this algorithm doesn't work optimally. In
// this case, the tick labels are spread out per week, but all the
// gaps reside within weeks. So we have a situation where the labels
// are courser than the ordinal gaps, and thus the tick interval
// should not be altered.
var ordinal = this, axis = ordinal.axis, ordinalSlope = ordinal.slope, ret;
if (ordinalSlope) {
if (!axis.options.breaks) {
ret = tickInterval / (ordinalSlope / axis.closestPointRange);
}
else {
ret = axis.closestPointRange || tickInterval; // #7275
}
}
else {
ret = tickInterval;
}
return ret;
};
return OrdinalAxisAdditions;
}());
/**
* Extends the axis with ordinal support.
*
* @private
*/
var OrdinalAxis = /** @class */ (function () {
function OrdinalAxis() {
}
/**
* Extends the axis with ordinal support.
*
* @private
*
* @param AxisClass
* Axis class to extend.
*
* @param ChartClass
* Chart class to use.
*
* @param SeriesClass
* Series class to use.
*/
OrdinalAxis.compose = function (AxisClass, ChartClass, SeriesClass) {
AxisClass.keepProps.push('ordinal');
var axisProto = AxisClass.prototype;
/**
* Calculate the ordinal positions before tick positions are calculated.
*
* @private
*/
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 ?
axis.series.forEach(function (series, i) {
uniqueOrdinalPositions = [];
if ((!ignoreHiddenSeries || series.visible !== false) &&
(series.takeOrdinalPosition !== false || hasBreaks)) {
// concatenate the processed X data into the existing
// positions, or the empty array
ordinalPositions = ordinalPositions.concat(series.processedXData);
len = ordinalPositions.length;
// remove duplicates (#1588)
ordinalPositions.sort(function (a, b) {
// without a custom function it is sorted as strings
return a - b;
});
overscrollPointsRange = Math.min(overscrollPointsRange, pick(
// Check for a single-point series:
series.closestPointRange, overscrollPointsRange));
if (len) {
i = 0;
while (i < len - 1) {
if (ordinalPositions[i] !== ordinalPositions[i + 1]) {
uniqueOrdinalPositions.push(ordinalPositions[i + 1]);
}
i++;
}
// Check first item:
if (uniqueOrdinalPositions[0] !== ordinalPositions[0]) {
uniqueOrdinalPositions.unshift(ordinalPositions[0]);
}
ordinalPositions = uniqueOrdinalPositions;
}
}
if (series.isSeriesBoosting) {
hasBoostedSeries = true;
}
});
if (hasBoostedSeries) {
ordinalPositions.length = 0;
}
// cache the length
len = ordinalPositions.length;
// Check if we really need the overhead of mapping axis data
// against the ordinal positions. If the series consist of
// evenly spaced data any way, we don't need any ordinal logic.
if (len > 2) { // two points have equal distance by default
dist = ordinalPositions[1] - ordinalPositions[0];
i = len - 1;
while (i-- && !useOrdinal) {
if (ordinalPositions[i + 1] - ordinalPositions[i] !== dist) {
useOrdinal = true;
}
}
// When zooming in on a week, prevent axis padding for
// weekends even though the data within the week is evenly
// spaced.
if (!axis.options.keepOrdinalPadding &&
(ordinalPositions[0] - min > dist ||
max - ordinalPositions[ordinalPositions.length - 1] >
dist)) {
useOrdinal = true;
}
}
else if (axis.options.overscroll) {
if (len === 2) {
// Exactly two points, distance for overscroll is fixed:
overscrollPointsRange =
ordinalPositions[1] - ordinalPositions[0];
}
else if (len === 1) {
// We have just one point, closest distance is unknown.
// Assume then it is last point and overscrolled range:
overscrollPointsRange = axis.options.overscroll;
ordinalPositions = [
ordinalPositions[0],
ordinalPositions[0] + overscrollPointsRange
];
}
else {
// In case of zooming in on overscrolled range, stick to
// the old range:
overscrollPointsRange = ordinal.overscrollPointsRange;
}
}
// Record the slope and offset to compute the linear values from
// the array index. Since the ordinal positions may exceed the
// current range, get the start and end positions within it
// (#719, #665b)
if (useOrdinal) {
if (axis.options.overscroll) {
ordinal.overscrollPointsRange = overscrollPointsRange;
ordinalPositions = ordinalPositions.concat(ordinal.getOverscrollPositions());
}
// Register
ordinal.positions = ordinalPositions;
// This relies on the ordinalPositions being set. Use
// Math.max and Math.min to prevent padding on either sides
// of the data.
minIndex = axis.ordinal2lin(// #5979
Math.max(min, ordinalPositions[0]), true);
maxIndex = Math.max(axis.ordinal2lin(Math.min(max, ordinalPositions[ordinalPositions.length - 1]), true), 1); // #3339
// Set the slope and offset of the values compared to the
// indices in the ordinal positions
ordinal.slope = slope = (max - min) / (maxIndex - minIndex);
ordinal.offset = min - (minIndex * slope);
}
else {
ordinal.overscrollPointsRange = pick(axis.closestPointRange, ordinal.overscrollPointsRange);
ordinal.positions = axis.ordinal.slope = ordinal.offset =
void 0;
}
}
axis.isOrdinal = isOrdinal && useOrdinal; // #3818, #4196, #4926
ordinal.groupIntervalFactor = null; // reset for next run
};
/**
* In an ordinal axis, there might be areas with dense consentrations of
* points, then large gaps between some. Creating equally distributed
* ticks over this entire range may lead to a huge number of ticks that
* will later be removed. So instead, break the positions up in
* segments, find the tick positions for each segment then concatenize
* them. This method is used from both data grouping logic and X axis
* tick position logic.
*
* @private
*/
AxisClass.prototype.getTimeTicks = function (normalizedInterval, min, max, startOfWeek, positions, closestDistance, findHigherRanks) {
if (positions === void 0) { positions = []; }
if (closestDistance === void 0) { closestDistance = 0; }
var start = 0, end, segmentPositions, higherRanks = {}, hasCrossedHigherRank, info, posLength, outsideMax, groupPositions = [], lastGroupPosition = -Number.MAX_VALUE, tickPixelIntervalOption = this.options.tickPixelInterval, time = this.chart.time,
// Record all the start positions of a segment, to use when
// deciding what's a gap in the data.
segmentStarts = [];
// The positions are not always defined, for example for ordinal
// positions when data has regular interval (#1557, #2090)
if ((!this.options.ordinal && !this.options.breaks) ||
!positions ||
positions.length < 3 ||
typeof min === 'undefined') {
return time.getTimeTicks.apply(time, arguments);
}
// Analyze the positions array to split it into segments on gaps
// larger than 5 times the closest distance. The closest distance is
// already found at this point, so we reuse that instead of
// computing it again.
posLength = positions.length;
for (end = 0; end < posLength; end++) {
outsideMax = end && positions[end - 1] > max;
if (positions[end] < min) { // Set the last position before min
start = end;
}
if (end === posLength - 1 ||
positions[end + 1] - positions[end] > closestDistance * 5 ||
outsideMax) {
// For each segment, calculate the tick positions from the
// getTimeTicks utility function. The interval will be the
// same regardless of how long the segment is.
if (positions[end] > lastGroupPosition) { // #1475
segmentPositions = time.getTimeTicks(normalizedInterval, positions[start], positions[end], startOfWeek);
// Prevent duplicate groups, for example for multiple
// segments within one larger time frame (#1475)
while (segmentPositions.length &&
segmentPositions[0] <= lastGroupPosition) {
segmentPositions.shift();
}
if (segmentPositions.length) {
lastGroupPosition =
segmentPositions[segmentPositions.length - 1];
}
segmentStarts.push(groupPositions.length);
groupPositions = groupPositions.concat(segmentPositions);
}
// Set start of next segment
start = end + 1;
}
if (outsideMax) {
break;
}
}
// Get the grouping info from the last of the segments. The info is
// the same for all segments.
info = segmentPositions.info;
// Optionally identify ticks with higher rank, for example when the
// ticks have crossed midnight.
if (findHigherRanks && info.unitRange <= timeUnits.hour) {
end = groupPositions.length - 1;
// Compare points two by two
for (start = 1; start < end; start++) {
if (time.dateFormat('%d', groupPositions[start]) !==
time.dateFormat('%d', groupPositions[start - 1])) {
higherRanks[groupPositions[start]] = 'day';
hasCrossedHigherRank = true;
}
}
// If the complete array has crossed midnight, we want to mark
// the first positions also as higher rank
if (hasCrossedHigherRank) {
higherRanks[groupPositions[0]] = 'day';
}
info.higherRanks = higherRanks;
}
// Save the info
info.segmentStarts = segmentStarts;
groupPositions.info = info;
// Don't show ticks within a gap in the ordinal axis, where the
// space between two points is greater than a portion of the tick
// pixel interval
if (findHigherRanks && defined(tickPixelIntervalOption)) {
var length = groupPositions.length, i = length, itemToRemove, translated, translatedArr = [], lastTranslated, medianDistance, distance, distances = [];
// Find median pixel distance in order to keep a reasonably even
// distance between ticks (#748)
while (i--) {
translated = this.translate(groupPositions[i]);
if (lastTranslated) {
distances[i] = lastTranslated - translated;
}
translatedArr[i] = lastTranslated = translated;
}
distances.sort();
medianDistance = distances[Math.floor(distances.length / 2)];
if (medianDistance < tickPixelIntervalOption * 0.6) {
medianDistance = null;
}
// Now loop over again and remove ticks where needed
i = groupPositions[length - 1] > max ? length - 1 : length; // #817
lastTranslated = void 0;
while (i--) {
translated = translatedArr[i];
distance = Math.abs(lastTranslated - translated);
// #4175 - when axis is reversed, the distance, is negative
// but tickPixelIntervalOption positive, so we need to
// compare the same values
// Remove ticks that are closer than 0.6 times the pixel
// interval from the one to the right, but not if it is
// close to the median distance (#748).
if (lastTranslated &&
distance < tickPixelIntervalOption * 0.8 &&
(medianDistance === null || distance < medianDistance * 0.8)) {
// Is this a higher ranked position with a normal
// position to the right?
if (higherRanks[groupPositions[i]] &&
!higherRanks[groupPositions[i + 1]]) {
// Yes: remove the lower ranked neighbour to the
// right
itemToRemove = i + 1;
lastTranslated = translated; // #709
}
else {
// No: remove this one
itemToRemove = i;
}
groupPositions.splice(itemToRemove, 1);
}
else {
lastTranslated = translated;
}
}
}
return groupPositions;
};
/**
* Translate from linear (internal) to axis value.
*
* @private
* @function Highcharts.Axis#lin2val
*
* @param {number} val
* The linear abstracted value.
*
* @param {boolean} [fromIndex]
* Translate from an index in the ordinal positions rather than a
* value.
*
* @return {number}
*/
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) {
ret = val;
}
else {
var ordinalSlope = ordinal.slope, ordinalOffset = ordinal.offset, i = ordinalPositions.length - 1, linearEquivalentLeft, linearEquivalentRight, distance;
// Handle the case where we translate from the index directly,
// used only when panning an ordinal axis
if (fromIndex) {
if (val < 0) { // out of range, in effect panning to the left
val = ordinalPositions[0];
}
else if (val > i) { // out of range, panning to the right
val = ordinalPositions[i];
}
else { // split it up
i = Math.floor(val);
distance = val - i; // the decimal
}
// Loop down along the ordinal positions. When the linear
// equivalent of i matches an ordinal position, interpolate
// between the left and right values.
}
else {
while (i--) {
linearEquivalentLeft =
(ordinalSlope * i) + ordinalOffset;
if (val >= linearEquivalentLeft) {
linearEquivalentRight =
(ordinalSlope *
(i + 1)) +
ordinalOffset;
// something between 0 and 1
distance = (val - linearEquivalentLeft) /
(linearEquivalentRight - linearEquivalentLeft);
break;
}
}
}
// If the index is within the range of the ordinal positions,
// return the associated or interpolated value. If not, just
// return the value.
return (typeof distance !== 'undefined' &&
typeof ordinalPositions[i] !== 'undefined' ?
ordinalPositions[i] + (distance ?
distance *
(ordinalPositions[i + 1] - ordinalPositions[i]) :
0) :
val);
}
return ret;
};
/**
* Translate from a linear axis value to the corresponding ordinal axis
* position. If there are no gaps in the ordinal axis this will be the
* same. The translated value is the value that the point would have if
* the axis were linear, using the same min and max.
*
* @private
* @function Highcharts.Axis#val2lin
*
* @param {number} val
* The axis value.
*
* @param {boolean} [toIndex]
* Whether to return the index in the ordinalPositions or the new value.
*
* @return {number}
*/
axisProto.val2lin = function (val, toIndex) {
var axis = this, ordinal = axis.ordinal, ordinalPositions = ordinal.positions, ret;
if (!ordinalPositions) {
ret = val;
}
else {
var ordinalLength = ordinalPositions.length, i, distance, ordinalIndex;
// first look for an exact match in the ordinalpositions array
i = ordinalLength;
while (i--) {
if (ordinalPositions[i] === val) {
ordinalIndex = i;
break;
}
}
// if that failed, find the intermediate position between the
// two nearest values
i = ordinalLength - 1;
while (i--) {
if (val > ordinalPositions[i] || i === 0) { // interpolate
// something between 0 and 1
distance = (val - ordinalPositions[i]) /
(ordinalPositions[i + 1] - ordinalPositions[i]);
ordinalIndex = i + distance;
break;
}
}
ret = toIndex ?
ordinalIndex :
ordinal.slope *
(ordinalIndex || 0) +
ordinal.offset;
}
return ret;
};
// Record this to prevent overwriting by broken-axis module (#5979)
axisProto.ordinal2lin = axisProto.val2lin;
/* eslint-disable no-invalid-this */
addEvent(AxisClass, 'afterInit', function () {
var axis = this;
if (!axis.ordinal) {
axis.ordinal = new OrdinalAxisAdditions(axis);
}
});
addEvent(AxisClass, 'foundExtremes', function () {
var axis = this;
if (axis.isXAxis &&
defined(axis.options.overscroll) &&
axis.max === axis.dataMax &&
(
// Panning is an execption. We don't want to apply
// overscroll when panning over the dataMax
!axis.chart.mouseIsDown ||
axis.isInternal) && (
// Scrollbar buttons are the other execption:
!axis.eventArgs ||
axis.eventArgs && axis.eventArgs.trigger !== 'navigator')) {
axis.max += axis.options.overscroll;
// Live data and buttons require translation for the min:
if (!axis.isInternal && defined(axis.userMin)) {
axis.min += axis.options.overscroll;
}
}
});
// For ordinal axis, that loads data async, redraw axis after data is
// loaded. If we don't do that, axis will have the same extremes as
// previously, but ordinal positions won't be calculated. See #10290
addEvent(AxisClass, 'afterSetScale', function () {
var axis = this;
if (axis.horiz && !axis.isDirty) {
axis.isDirty = axis.isOrdinal &&
axis.chart.navigator &&
!axis.chart.navigator.adaptToUpdatedData;
}
});
// Extending the Chart.pan method for ordinal axes
addEvent(ChartClass, 'pan', function (e) {
var chart = this, xAxis = chart.xAxis[0], overscroll = xAxis.options.overscroll, chartX = e.originalEvent.chartX, panning = chart.options.chart &&
chart.options.chart.panning, runBase = false;
if (panning &&
panning.type !== 'y' &&
xAxis.options.ordinal &&
xAxis.series.length) {
var mouseDownX = chart.mouseDownX, extremes = xAxis.getExtremes(), dataMax = extremes.dataMax, min = extremes.min, max = extremes.max, trimmedRange, hoverPoints = chart.hoverPoints, closestPointRange = (xAxis.closestPointRange ||
(xAxis.ordinal && xAxis.ordinal.overscrollPointsRange)), pointPixelWidth = (xAxis.translationSlope *
(xAxis.ordinal.slope || closestPointRange)),
// how many ordinal units did we move?
movedUnits = (mouseDownX - chartX) / pointPixelWidth,
// get index of all the chart's points
extendedAxis = { ordinal: { positions: xAxis.ordinal.getExtendedPositions() } }, ordinalPositions, searchAxisLeft, lin2val = xAxis.lin2val, val2lin = xAxis.val2lin, searchAxisRight;
// we have an ordinal axis, but the data is equally spaced
if (!extendedAxis.ordinal.positions) {
runBase = true;
}
else if (Math.abs(movedUnits) > 1) {
// Remove active points for shared tooltip
if (hoverPoints) {
hoverPoints.forEach(function (point) {
point.setState();
});
}
if (movedUnits < 0) {
searchAxisLeft = extendedAxis;
searchAxisRight = xAxis.ordinal.positions ? xAxis : extendedAxis;
}
else {
searchAxisLeft = xAxis.ordinal.positions ? xAxis : extendedAxis;
searchAxisRight = extendedAxis;
}
// In grouped data series, the last ordinal position
// represents the grouped data, which is to the left of the
// real data max. If we don't compensate for this, we will
// be allowed to pan grouped data series passed the right of
// the plot area.
ordinalPositions = searchAxisRight.ordinal.positions;
if (dataMax >
ordinalPositions[ordinalPositions.length - 1]) {
ordinalPositions.push(dataMax);
}
// Get the new min and max values by getting the ordinal
// index for the current extreme, then add the moved units
// and translate back to values. This happens on the
// extended ordinal positions if the new position is out of
// range, else it happens on the current x axis which is
// smaller and faster.
chart.fixedRange = max - min;
trimmedRange = xAxis.navigatorAxis.toFixedRange(null, null, lin2val.apply(searchAxisLeft, [
val2lin.apply(searchAxisLeft, [min, true]) + movedUnits,
true // translate from index
]), lin2val.apply(searchAxisRight, [
val2lin.apply(searchAxisRight, [max, true]) + movedUnits,
true // translate from index
]));
// Apply it if it is within the available data range
if (trimmedRange.min >= Math.min(extremes.dataMin, min) &&
trimmedRange.max <= Math.max(dataMax, max) + overscroll) {
xAxis.setExtremes(trimmedRange.min, trimmedRange.max, true, false, { trigger: 'pan' });
}
chart.mouseDownX = chartX; // set new reference for next run
css(chart.container, { cursor: 'move' });
}
}
else {
runBase = true;
}
// revert to the linear chart.pan version
if (runBase || (panning && /y/.test(panning.type))) {
if (overscroll) {
xAxis.max = xAxis.dataMax + overscroll;
}
}
else {
e.preventDefault();
}
});
addEvent(SeriesClass, 'updatedData', function () {
var xAxis = this.xAxis;
// Destroy the extended ordinal index on updated data
if (xAxis && xAxis.options.ordinal) {
delete xAxis.ordinal.index;
}
});
/* eslint-enable no-invalid-this */
};
return OrdinalAxis;
}());
OrdinalAxis.compose(Axis, Chart, Series); // @todo move to StockChart, remove from master
export default OrdinalAxis;