
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
import { DataItem } from "../../../core/render/Component";
import { Axis } from "./Axis";
import { MultiDisposer } from "../../../core/util/Disposer";
import * as $type from "../../../core/util/Type";
import * as $array from "../../../core/util/Array";
import * as $math from "../../../core/util/Math";
import * as $utils from "../../../core/util/Utils";
/**
* Creates a value axis.
*
* @see {@link https://www.amcharts.com/docs/v5/charts/xy-chart/axes/value-axis/} for more info
* @important
*/
export class ValueAxis extends Axis {
constructor() {
super(...arguments);
Object.defineProperty(this, "_dirtyExtremes", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "_dirtySelectionExtremes", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "_deltaMinMax", {
enumerable: true,
configurable: true,
writable: true,
value: 1
});
Object.defineProperty(this, "_minReal", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_maxReal", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_baseValue", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "_syncDp", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_minLogAdjusted", {
enumerable: true,
configurable: true,
writable: true,
value: 1
});
}
/**
* @ignore
*/
markDirtyExtremes() {
this._dirtyExtremes = true;
this.markDirty();
}
/**
* @ignore
*/
markDirtySelectionExtremes() {
this._dirtySelectionExtremes = true;
this.markDirty();
}
_afterNew() {
this._settings.themeTags = $utils.mergeTags(this._settings.themeTags, ["axis"]);
this.setPrivateRaw("name", "value");
this.addTag("value");
super._afterNew();
}
_prepareChildren() {
super._prepareChildren();
if (this.isDirty("syncWithAxis")) {
let previousValue = this._prevSettings.syncWithAxis;
if (previousValue) {
if (this._syncDp) {
this._syncDp.dispose();
}
}
let syncWithAxis = this.get("syncWithAxis");
if (syncWithAxis) {
this._syncDp = new MultiDisposer([
syncWithAxis.onPrivate("selectionMinFinal", () => {
this._dirtySelectionExtremes = true;
}),
syncWithAxis.onPrivate("selectionMaxFinal", () => {
this._dirtySelectionExtremes = true;
})
]);
}
}
let someDirty = false;
if (this.isDirty("min") || this.isDirty("max") || this.isDirty("maxPrecision") || this.isDirty("numberFormat")) {
someDirty = true;
this.ghostLabel.set("text", "");
}
//if (this._dirtyExtremes || this.isPrivateDirty("width") || this.isPrivateDirty("height") || this.isDirty("min") || this.isDirty("max") || this.isDirty("extraMin") || this.isDirty("extraMax") || this.isDirty("logarithmic") || this.isDirty("treatZeroAs") || this.isDirty("baseValue") || this.isDirty("strictMinMax") || this.isDirty("maxPrecision")) {
if (this._sizeDirty || this._dirtyExtremes || this._valuesDirty || someDirty || this.isPrivateDirty("width") || this.isPrivateDirty("height") || this.isDirty("extraMin") || this.isDirty("extraMax") || this.isDirty("logarithmic") || this.isDirty("treatZeroAs") || this.isDirty("baseValue") || this.isDirty("strictMinMax") || this.isDirty("strictMinMaxSelection")) {
this._getMinMax();
this._dirtyExtremes = false;
}
if (this._dirtySelectionExtremes && !this._isPanning && this.get("autoZoom", true)) {
this._getSelectionMinMax();
this._dirtySelectionExtremes = false;
}
this._groupData();
if (this._sizeDirty || this._valuesDirty || this.isDirty("start") || this.isDirty("end") || this.isPrivateDirty("min") || this.isPrivateDirty("selectionMax") || this.isPrivateDirty("selectionMin") || this.isPrivateDirty("max") || this.isPrivateDirty("step") || this.isPrivateDirty("width") || this.isPrivateDirty("height") || this.isDirty("logarithmic")) {
this._handleRangeChange();
this._prepareAxisItems();
this._updateAxisRanges();
}
this._baseValue = this.baseValue();
}
_groupData() {
}
_formatText(value) {
const numberFormat = this.get("numberFormat");
const formatter = this.getNumberFormatter();
let text = "";
if (numberFormat) {
text = formatter.format(value, numberFormat);
}
else {
text = formatter.format(value, undefined, this.getPrivate("stepDecimalPlaces"));
}
return text;
}
_prepareAxisItems() {
const min = this.getPrivate("min");
const max = this.getPrivate("max");
if ($type.isNumber(min) && $type.isNumber(max)) {
const logarithmic = this.get("logarithmic");
const step = this.getPrivate("step");
const selectionMin = this.getPrivate("selectionMin");
const selectionMax = this.getPrivate("selectionMax") + step;
let value = selectionMin - step;
let differencePower = 1;
let minLog = min;
if (logarithmic) {
value = this._minLogAdjusted;
if (value < selectionMin) {
while (value < selectionMin) {
value += step;
}
}
minLog = value;
if (minLog <= 0) {
minLog = 1;
if (step < 1) {
minLog = step;
}
}
differencePower = Math.log(selectionMax - step) * Math.LOG10E - Math.log(minLog) * Math.LOG10E;
if (differencePower > 2) {
value = Math.pow(10, Math.log(minLog) * Math.LOG10E - 5);
}
}
/// minor grid
const renderer = this.get("renderer");
const minorLabelsEnabled = renderer.get("minorLabelsEnabled");
const minorGridEnabled = renderer.get("minorGridEnabled", minorLabelsEnabled);
let stepPower = Math.pow(10, Math.floor(Math.log(Math.abs(step)) * Math.LOG10E));
const stepAdjusted = Math.round(step / stepPower);
let minorGridCount = 2;
if ($math.round(stepAdjusted / 5, 10) % 1 == 0) {
minorGridCount = 5;
}
if ($math.round(stepAdjusted / 10, 10) % 1 == 0) {
minorGridCount = 10;
}
let minorStep = step / minorGridCount;
// end of minor grid
let i = 0;
let m = 0;
let previous = -Infinity;
while (value < selectionMax) {
let dataItem;
if (this.dataItems.length < i + 1) {
dataItem = new DataItem(this, undefined, {});
this._dataItems.push(dataItem);
this.processDataItem(dataItem);
}
else {
dataItem = this.dataItems[i];
}
this._createAssets(dataItem, []);
this._toggleDataItem(dataItem, true);
dataItem.setRaw("value", value);
const label = dataItem.get("label");
if (label) {
label.set("text", this._formatText(value));
}
this._prepareDataItem(dataItem);
let nextValue = value;
if (!logarithmic) {
nextValue += step;
}
else {
if (differencePower > 2) {
nextValue = Math.pow(10, Math.log(minLog) * Math.LOG10E + i - 5);
}
else {
nextValue += step;
}
}
// minor grid
if (minorGridEnabled) {
let minorValue = value + minorStep;
if (logarithmic) {
if (differencePower > 2) {
let minorMinMaxStep = this._adjustMinMax(value, nextValue, 10);
minorStep = minorMinMaxStep.step;
}
minorValue = value + minorStep;
}
while (minorValue < nextValue - step * 0.00000000001) {
let minorDataItem;
if (this.minorDataItems.length < m + 1) {
minorDataItem = new DataItem(this, undefined, {});
this.minorDataItems.push(minorDataItem);
this.processDataItem(minorDataItem);
}
else {
minorDataItem = this.minorDataItems[m];
}
this._createAssets(minorDataItem, ["minor"], true);
this._toggleDataItem(minorDataItem, true);
minorDataItem.setRaw("value", minorValue);
const minorLabel = minorDataItem.get("label");
if (minorLabel) {
if (minorLabelsEnabled) {
minorLabel.set("text", this._formatText(minorValue));
}
else {
minorLabel.setPrivate("visible", false);
}
}
this._prepareDataItem(minorDataItem);
minorValue += minorStep;
m++;
}
}
value = nextValue;
if (previous == value) {
break;
}
let stepPower = Math.pow(10, Math.floor(Math.log(Math.abs(step)) * Math.LOG10E));
if (stepPower < 1) {
// exponent is less then 1 too. Count decimals of exponent
let decCount = Math.round(Math.abs(Math.log(Math.abs(stepPower)) * Math.LOG10E)) + 2;
// round value to avoid floating point issues
value = $math.round(value, decCount);
}
i++;
previous = value;
}
for (let j = i; j < this.dataItems.length; j++) {
this._toggleDataItem(this.dataItems[j], false);
}
for (let j = m; j < this.minorDataItems.length; j++) {
this._toggleDataItem(this.minorDataItems[j], false);
}
$array.each(this.series, (series) => {
if (series.inited) {
series._markDirtyAxes();
}
});
this._updateGhost();
}
}
_prepareDataItem(dataItem, count) {
let renderer = this.get("renderer");
let value = dataItem.get("value");
let endValue = dataItem.get("endValue");
let position = this.valueToPosition(value);
let endPosition = position;
let fillEndPosition = this.valueToPosition(value + this.getPrivate("step"));
if ($type.isNumber(endValue)) {
endPosition = this.valueToPosition(endValue);
fillEndPosition = endPosition;
}
if (dataItem.get("isRange")) {
if (endValue == null) {
fillEndPosition = position;
}
}
let labelEndPosition = endPosition;
let labelEndValue = dataItem.get("labelEndValue");
if (labelEndValue != null) {
labelEndPosition = this.valueToPosition(labelEndValue);
}
renderer.updateLabel(dataItem.get("label"), position, labelEndPosition, count);
const grid = dataItem.get("grid");
renderer.updateGrid(grid, position, endPosition);
if (grid) {
if (value == this.get("baseValue", 0)) {
grid.addTag("base");
grid._applyThemes();
}
else if (grid.hasTag("base")) {
grid.removeTag("base");
grid._applyThemes();
}
}
renderer.updateTick(dataItem.get("tick"), position, labelEndPosition, count);
renderer.updateFill(dataItem.get("axisFill"), position, fillEndPosition);
this._processBullet(dataItem);
renderer.updateBullet(dataItem.get("bullet"), position, endPosition);
if (!dataItem.get("isRange")) {
const fillRule = this.get("fillRule");
if (fillRule) {
fillRule(dataItem);
}
}
}
_handleRangeChange() {
let selectionMin = this.positionToValue(this.get("start", 0));
let selectionMax = this.positionToValue(this.get("end", 1));
const gridCount = this.get("renderer").gridCount();
let minMaxStep = this._adjustMinMax(selectionMin, selectionMax, gridCount, true);
let stepDecimalPlaces = $utils.decimalPlaces(minMaxStep.step);
this.setPrivateRaw("stepDecimalPlaces", stepDecimalPlaces);
selectionMin = $math.round(selectionMin, stepDecimalPlaces);
selectionMax = $math.round(selectionMax, stepDecimalPlaces);
minMaxStep = this._adjustMinMax(selectionMin, selectionMax, gridCount, true);
let step = minMaxStep.step;
selectionMin = minMaxStep.min;
selectionMax = minMaxStep.max;
if (this.getPrivate("selectionMin") !== selectionMin || this.getPrivate("selectionMax") !== selectionMax || this.getPrivate("step") !== step) {
// do not change to setPrivate, will cause SO
this.setPrivateRaw("selectionMin", selectionMin);
this.setPrivateRaw("selectionMax", selectionMax);
this.setPrivateRaw("step", step);
}
}
/**
* Converts a relative position to a corresponding numeric value from axis
* scale.
*
* @param position Relative position
* @return Value
*/
positionToValue(position) {
const min = this.getPrivate("min");
const max = this.getPrivate("max");
if (!this.get("logarithmic")) {
return position * (max - min) + min;
}
else {
return Math.pow(Math.E, (position * ((Math.log(max) * Math.LOG10E - Math.log(min) * Math.LOG10E)) + Math.log(min) * Math.LOG10E) / Math.LOG10E);
}
}
/**
* Convers value to a relative position on axis.
*
* @param value Value
* @return Relative position
*/
valueToPosition(value) {
const min = this.getPrivate("min");
const max = this.getPrivate("max");
if (!this.get("logarithmic")) {
return (value - min) / (max - min);
}
else {
if (value <= 0) {
let treatZeroAs = this.get("treatZeroAs");
if ($type.isNumber(treatZeroAs)) {
value = treatZeroAs;
}
}
return (Math.log(value) * Math.LOG10E - Math.log(min) * Math.LOG10E) / ((Math.log(max) * Math.LOG10E - Math.log(min) * Math.LOG10E));
}
}
/**
* @ignore
*/
valueToFinalPosition(value) {
const min = this.getPrivate("minFinal");
const max = this.getPrivate("maxFinal");
if (!this.get("logarithmic")) {
return (value - min) / (max - min);
}
else {
if (value <= 0) {
let treatZeroAs = this.get("treatZeroAs");
if ($type.isNumber(treatZeroAs)) {
value = treatZeroAs;
}
}
return (Math.log(value) * Math.LOG10E - Math.log(min) * Math.LOG10E) / ((Math.log(max) * Math.LOG10E - Math.log(min) * Math.LOG10E));
}
}
/**
* Returns X coordinate in pixels corresponding to specific value.
*
* @param value Numeric value
* @param location Location
* @param baseValue Base value
* @return X coordinate
*/
getX(value, location, baseValue) {
value = baseValue + (value - baseValue) * location;
const position = this.valueToPosition(value);
return this._settings.renderer.positionToCoordinate(position);
}
/**
* Returns X coordinate in pixels corresponding to specific value.
*
* @param value Numeric value
* @param location Location
* @param baseValue Base value
* @return X coordinate
*/
getY(value, location, baseValue) {
value = baseValue + (value - baseValue) * location;
const position = this.valueToPosition(value);
return this._settings.renderer.positionToCoordinate(position);
}
/**
* @ignore
*/
getDataItemCoordinateX(dataItem, field, _cellLocation, axisLocation) {
return this._settings.renderer.positionToCoordinate(this.getDataItemPositionX(dataItem, field, _cellLocation, axisLocation));
}
/**
* @ignore
*/
getDataItemPositionX(dataItem, field, _cellLocation, axisLocation) {
let value = dataItem.get(field);
const stackToItem = dataItem.get("stackToItemX");
if (stackToItem) {
const series = dataItem.component;
value = value * axisLocation + series.getStackedXValueWorking(dataItem, field);
}
else {
value = this._baseValue + (value - this._baseValue) * axisLocation;
}
return this.valueToPosition(value);
}
/**
* @ignore
*/
getDataItemCoordinateY(dataItem, field, _cellLocation, axisLocation) {
return this._settings.renderer.positionToCoordinate(this.getDataItemPositionY(dataItem, field, _cellLocation, axisLocation));
}
/**
* @ignore
*/
getDataItemPositionY(dataItem, field, _cellLocation, axisLocation) {
let value = dataItem.get(field);
const stackToItem = dataItem.get("stackToItemY");
if (stackToItem) {
const series = dataItem.component;
value = value * axisLocation + series.getStackedYValueWorking(dataItem, field);
}
else {
value = this._baseValue + (value - this._baseValue) * axisLocation;
}
return this.valueToPosition(value);
}
/**
* Returns relative position of axis' `baseValue`.
*
* @return Base value position
*/
basePosition() {
return this.valueToPosition(this.baseValue());
}
/**
* Base value of the [[ValueAxis]], which determines positive and negative
* values.
*
* @return Base value
*/
baseValue() {
const min = Math.min(this.getPrivate("minFinal", -Infinity), this.getPrivate("selectionMin", -Infinity));
const max = Math.max(this.getPrivate("maxFinal", Infinity), this.getPrivate("selectionMax", Infinity));
let baseValue = this.get("baseValue", 0);
if (baseValue < min) {
baseValue = min;
}
if (baseValue > max) {
baseValue = max;
}
return baseValue;
}
/**
* @ignore
*/
cellEndValue(value) {
return value;
}
fixSmallStep(step) {
// happens because of floating point error
if (1 + step === 1) {
step *= 2;
return this.fixSmallStep(step);
}
return step;
}
_fixMin(min) {
return min;
}
_fixMax(max) {
return max;
}
_calculateTotals() {
if (this.get("calculateTotals")) {
let series = this.series[0];
if (series) {
let startIndex = series.startIndex();
if (series.dataItems.length > 0) {
if (startIndex > 0) {
startIndex--;
}
let endIndex = series.endIndex();
if (endIndex < series.dataItems.length) {
endIndex++;
}
let field;
let vc;
if (series.get("yAxis") == this) {
field = "valueY";
vc = "vcy";
}
else if (series.get("xAxis") == this) {
field = "valueX";
vc = "vcx";
}
let fieldWorking = field + "Working";
if (field) {
for (let i = startIndex; i < endIndex; i++) {
let sum = 0;
let total = 0;
$array.each(this.series, (series) => {
if (!series.get("excludeFromTotal")) {
let dataItem = series.dataItems[i];
if (dataItem) {
let value = dataItem.get(fieldWorking) * series.get(vc);
if (!$type.isNaN(value)) {
sum += value;
total += Math.abs(value);
}
}
}
});
$array.each(this.series, (series) => {
if (!series.get("excludeFromTotal")) {
let dataItem = series.dataItems[i];
if (dataItem) {
let value = dataItem.get(fieldWorking) * series.get(vc);
if (!$type.isNaN(value)) {
dataItem.set((field + "Total"), total);
dataItem.set((field + "Sum"), sum);
dataItem.set((field + "TotalPercent"), value / total * 100);
}
}
}
});
}
}
}
}
}
}
_getSelectionMinMax() {
const min = this.getPrivate("minFinal");
const max = this.getPrivate("maxFinal");
const minDefined = this.get("min");
const maxDefined = this.get("max");
let extraMin = this.get("extraMin", 0);
let extraMax = this.get("extraMax", 0);
if (this.get("logarithmic")) {
if (this.get("extraMin") == null) {
extraMin = 0.1;
}
if (this.get("extraMax") == null) {
extraMax = 0.2;
}
}
const gridCount = this.get("renderer").gridCount();
const selectionStrictMinMax = this.get("strictMinMaxSelection");
let strictMinMax = this.get("strictMinMax");
if ($type.isNumber(min) && $type.isNumber(max)) {
let selectionMin = max;
let selectionMax = min;
$array.each(this.series, (series) => {
if (!series.get("ignoreMinMax")) {
let seriesMin;
let seriesMax;
const outOfSelection = series.getPrivate("outOfSelection");
if (series.get("xAxis") === this) {
if (!outOfSelection) {
let minX = series.getPrivate("minX");
let maxX = series.getPrivate("maxX");
// solves #90085
if (series.startIndex() != 0 || series.endIndex() != series.dataItems.length) {
minX = undefined;
maxX = undefined;
}
seriesMin = series.getPrivate("selectionMinX", minX);
seriesMax = series.getPrivate("selectionMaxX", maxX);
}
}
else if (series.get("yAxis") === this) {
if (!outOfSelection) {
let minY = series.getPrivate("minY");
let maxY = series.getPrivate("maxY");
// solves #90085
if (series.startIndex() != 0 || series.endIndex() != series.dataItems.length) {
minY = undefined;
maxY = undefined;
}
seriesMin = series.getPrivate("selectionMinY", minY);
seriesMax = series.getPrivate("selectionMaxY", maxY);
}
}
if (!series.isHidden() && !series.isShowing()) {
if ($type.isNumber(seriesMin)) {
selectionMin = Math.min(selectionMin, seriesMin);
}
if ($type.isNumber(seriesMax)) {
selectionMax = Math.max(selectionMax, seriesMax);
}
}
}
});
this.axisRanges.each((range) => {
if (range.get("affectsMinMax")) {
let value = range.get("value");
if (value != null) {
selectionMin = Math.min(selectionMin, value);
selectionMax = Math.max(selectionMax, value);
}
value = range.get("endValue");
if (value != null) {
selectionMin = Math.min(selectionMin, value);
selectionMax = Math.max(selectionMax, value);
}
}
});
if (selectionMin > selectionMax) {
[selectionMin, selectionMax] = [selectionMax, selectionMin];
}
if ($type.isNumber(minDefined)) {
if (strictMinMax) {
selectionMin = minDefined;
}
else {
selectionMin = min;
}
}
else if (strictMinMax) {
if ($type.isNumber(this._minReal)) {
selectionMin = this._minReal;
}
}
if ($type.isNumber(maxDefined)) {
if (strictMinMax) {
selectionMax = maxDefined;
}
else {
selectionMax = max;
}
}
else if (strictMinMax) {
if ($type.isNumber(this._maxReal)) {
selectionMax = this._maxReal;
}
}
if (selectionMin === selectionMax) {
let smin = selectionMin;
selectionMin -= this._deltaMinMax;
selectionMax += this._deltaMinMax;
if (selectionMin < min) {
let d = smin - min;
if (d == 0) {
d = this._deltaMinMax;
}
selectionMin = smin - d;
selectionMax = smin + d;
strictMinMax = true;
}
let minMaxStep2 = this._adjustMinMax(selectionMin, selectionMax, gridCount, strictMinMax);
selectionMin = minMaxStep2.min;
selectionMax = minMaxStep2.max;
}
let selectionMinReal = selectionMin;
let selectionMaxReal = selectionMax;
selectionMin -= (selectionMax - selectionMin) * extraMin;
selectionMax += (selectionMax - selectionMin) * extraMax;
let minMaxStep = this._adjustMinMax(selectionMin, selectionMax, gridCount);
selectionMin = minMaxStep.min;
selectionMax = minMaxStep.max;
selectionMin = $math.fitToRange(selectionMin, min, max);
selectionMax = $math.fitToRange(selectionMax, min, max);
// do it for the second time !important
minMaxStep = this._adjustMinMax(selectionMin, selectionMax, gridCount, true);
if (!strictMinMax) {
selectionMin = minMaxStep.min;
selectionMax = minMaxStep.max;
}
const syncWithAxis = this.get("syncWithAxis");
if (syncWithAxis) {
minMaxStep = this._syncAxes(selectionMin, selectionMax, minMaxStep.step, syncWithAxis.getPrivate("selectionMinFinal", syncWithAxis.getPrivate("minFinal", 0)), syncWithAxis.getPrivate("selectionMaxFinal", syncWithAxis.getPrivate("maxFinal", 1)), syncWithAxis.getPrivate("selectionStepFinal", syncWithAxis.getPrivate("step", 1)));
selectionMin = minMaxStep.min;
selectionMax = minMaxStep.max;
}
if (strictMinMax) {
if ($type.isNumber(minDefined)) {
selectionMin = Math.max(selectionMin, minDefined);
}
if ($type.isNumber(maxDefined)) {
selectionMax = Math.min(selectionMax, maxDefined);
}
}
if (selectionStrictMinMax) {
selectionMin = selectionMinReal - (selectionMax - selectionMin) * extraMin;
selectionMax = selectionMaxReal + (selectionMax - selectionMin) * extraMax;
}
if (this.get("logarithmic")) {
if (selectionMin <= 0) {
selectionMin = selectionMinReal * (1 - Math.min(extraMin, 0.99));
}
if (selectionMin < min) {
selectionMin = min;
}
if (selectionMax > max) {
selectionMax = max;
}
}
let len = Math.min(20, Math.ceil(Math.log(this.getPrivate("maxZoomFactor", 100) + 1) / Math.LN10) + 2);
let start = $math.round(this.valueToFinalPosition(selectionMin), len);
let end = $math.round(this.valueToFinalPosition(selectionMax), len);
this.setPrivateRaw("selectionMinFinal", selectionMin);
this.setPrivateRaw("selectionMaxFinal", selectionMax);
this.setPrivateRaw("selectionStepFinal", minMaxStep.step);
this.zoom(start, end);
}
}
_getMinMax() {
let minDefined = this.get("min");
let maxDefined = this.get("max");
let min = Infinity;
let max = -Infinity;
let extraMin = this.get("extraMin", 0);
let extraMax = this.get("extraMax", 0);
if (this.get("logarithmic")) {
if (this.get("extraMin") == null) {
extraMin = 0.1;
}
if (this.get("extraMax") == null) {
extraMax = 0.2;
}
}
let minDiff = Infinity;
$array.each(this.series, (series) => {
if (!series.get("ignoreMinMax")) {
let seriesMin;
let seriesMax;
if (series.get("xAxis") === this) {
seriesMin = series.getPrivate("minX");
seriesMax = series.getPrivate("maxX");
}
else if (series.get("yAxis") === this) {
seriesMin = series.getPrivate("minY");
seriesMax = series.getPrivate("maxY");
}
if ($type.isNumber(seriesMin) && $type.isNumber(seriesMax)) {
min = Math.min(min, seriesMin);
max = Math.max(max, seriesMax);
let diff = seriesMax - seriesMin;
if (diff <= 0) {
diff = Math.abs(seriesMax / 100);
}
if (diff < minDiff) {
minDiff = diff;
}
}
}
});
this.axisRanges.each((range) => {
if (range.get("affectsMinMax")) {
let value = range.get("value");
if (value != null) {
min = Math.min(min, value);
max = Math.max(max, value);
}
value = range.get("endValue");
if (value != null) {
min = Math.min(min, value);
max = Math.max(max, value);
}
}
});
if (this.get("logarithmic")) {
let treatZeroAs = this.get("treatZeroAs");
if ($type.isNumber(treatZeroAs)) {
if (min <= 0) {
min = treatZeroAs;
}
}
if (min <= 0) {
new Error("Logarithmic value axis can not have values <= 0.");
}
}
if (min === 0 && max === 0) {
max = 0.9;
min = -0.9;
}
if ($type.isNumber(minDefined)) {
min = minDefined;
}
if ($type.isNumber(maxDefined)) {
max = maxDefined;
}
// meaning no min/max found on series/ranges and no min/max was defined
if (min === Infinity || max === -Infinity) {
this.setPrivate("minFinal", undefined);
this.setPrivate("maxFinal", undefined);
return;
}
const initialMin = min;
const initialMax = max;
// adapter
let minAdapted = this.adapters.fold("min", min);
let maxAdapted = this.adapters.fold("max", max);
if ($type.isNumber(minAdapted)) {
min = minAdapted;
}
if ($type.isNumber(maxAdapted)) {
max = maxAdapted;
}
// DateAxis does some magic here
min = this._fixMin(min);
max = this._fixMax(max);
// this happens if starLocation and endLocation are 0.5 and DateAxis has only one date
if (max - min <= 1 / Math.pow(10, 15)) {
if (max - min !== 0) {
this._deltaMinMax = (max - min) / 2;
}
else {
this._getDelta(max);
}
min -= this._deltaMinMax;
max += this._deltaMinMax;
}
// add extras
min -= (max - min) * extraMin;
max += (max - min) * extraMax;
if (this.get("logarithmic")) {
// don't let min go below 0 if real min is >= 0
if (min < 0 && initialMin >= 0) {
min = 0;
}
// don't let max go above 0 if real max is <= 0
if (max > 0 && initialMax <= 0) {
max = 0;
}
}
this._minReal = min;
this._maxReal = max;
let strictMinMax = this.get("strictMinMax");
let strictMinMaxSelection = this.get("strictMinMaxSelection", false);
if (strictMinMaxSelection) {
strictMinMax = strictMinMaxSelection;
}
let strict = strictMinMax;
if ($type.isNumber(maxDefined)) {
strict = true;
}
let gridCount = this.get("renderer").gridCount();
let minMaxStep = this._adjustMinMax(min, max, gridCount, strict);
min = minMaxStep.min;
max = minMaxStep.max;
// do it for the second time with strict true (importat!)
minMaxStep = this._adjustMinMax(min, max, gridCount, true);
min = minMaxStep.min;
max = minMaxStep.max;
// return min max if strict
if (strictMinMax) {
if ($type.isNumber(minDefined)) {
min = minDefined;
}
else {
min = this._minReal;
}
if ($type.isNumber(maxDefined)) {
max = maxDefined;
}
else {
max = this._maxReal;
}
if (max - min <= 0.00000001) {
min -= this._deltaMinMax;
max += this._deltaMinMax;
}
min -= (max - min) * extraMin;
max += (max - min) * extraMax;
}
minAdapted = this.adapters.fold("min", min);
maxAdapted = this.adapters.fold("max", max);
if ($type.isNumber(minAdapted)) {
min = minAdapted;
}
if ($type.isNumber(maxAdapted)) {
max = maxAdapted;
}
if (minDiff == Infinity) {
minDiff = (max - min);
}
// this is to avoid floating point number error
let decCount = Math.round(Math.abs(Math.log(Math.abs(max - min)) * Math.LOG10E)) + 5;
min = $math.round(min, decCount);
max = $math.round(max, decCount);
const syncWithAxis = this.get("syncWithAxis");
if (syncWithAxis) {
minMaxStep = this._syncAxes(min, max, minMaxStep.step, syncWithAxis.getPrivate("minFinal", syncWithAxis.getPrivate("min", 0)), syncWithAxis.getPrivate("maxFinal", syncWithAxis.getPrivate("max", 1)), syncWithAxis.getPrivate("step", 1));
min = minMaxStep.min;
max = minMaxStep.max;
}
this.setPrivateRaw("maxZoomFactor", Math.max(1, Math.ceil((max - min) / minDiff * this.get("maxZoomFactor", 100))));
this._fixZoomFactor();
if (this.get("logarithmic")) {
this._minLogAdjusted = min;
min = this._minReal;
max = this._maxReal;
if (min <= 0) {
min = initialMin * (1 - Math.min(extraMin, 0.99));
}
}
if ($type.isNumber(min) && $type.isNumber(max)) {
if (this.getPrivate("minFinal") !== min || this.getPrivate("maxFinal") !== max) {
this.setPrivate("minFinal", min);
this.setPrivate("maxFinal", max);
this._saveMinMax(min, max);
const duration = this.get("interpolationDuration", 0);
const easing = this.get("interpolationEasing");
this.animatePrivate({ key: "min", to: min, duration, easing });
this.animatePrivate({ key: "max", to: max, duration, easing });
}
}
}
_fixZoomFactor() {
}
_getDelta(max) {
// the number by which we need to raise 10 to get difference
let exponent = Math.log(Math.abs(max)) * Math.LOG10E;
// here we find a number which is power of 10 and has the same count of numbers as difference has
let power = Math.pow(10, Math.floor(exponent));
// reduce this number by 10 times
power = power / 10;
this._deltaMinMax = power;
}
_saveMinMax(_min, _max) {
}
_adjustMinMax(min, max, gridCount, strictMode) {
// will fail if 0
if (gridCount <= 1) {
gridCount = 1;
}
gridCount = Math.round(gridCount);
let initialMin = min;
let initialMax = max;
let difference = max - min;
// in case min and max is the same, use max
if (difference === 0) {
difference = Math.abs(max);
}
// the number by which we need to raise 10 to get difference
let exponent = Math.log(Math.abs(difference)) * Math.LOG10E;
// here we find a number which is power of 10 and has the same count of numbers as difference has
let power = Math.pow(10, Math.floor(exponent));
// reduce this number by 10 times
power = power / 10;
let extra = power;
if (strictMode) {
extra = 0;
}
// round down min
if (strictMode) {
min = Math.floor(min / power) * power;
// round up max
max = Math.ceil(max / power) * power;
}
else {
min = Math.ceil(min / power) * power - extra;
// round up max
max = Math.floor(max / power) * power + extra;
}
// don't let min go below 0 if real min is >= 0
if (min < 0 && initialMin >= 0) {
min = 0;
}
// don't let max go above 0 if real max is <= 0
if (max > 0 && initialMax <= 0) {
max = 0;
}
exponent = Math.log(Math.abs(difference)) * Math.LOG10E;
power = Math.pow(10, Math.floor(exponent));
power = power / 100; // used to be 10 in v4, but this caused issue that there could be limited number of grids with even very small minGridDistance
// approximate difference between two grid lines
let step = Math.ceil((difference / gridCount) / power) * power;
let stepPower = Math.pow(10, Math.floor(Math.log(Math.abs(step)) * Math.LOG10E));
// the step should divide by 2, 5, and 10.
let stepDivisor = Math.ceil(step / stepPower); // number 0 - 10
if (stepDivisor > 5) {
stepDivisor = 10;
}
else if (stepDivisor <= 5 && stepDivisor > 2) {
stepDivisor = 5;
}
// now get real step
step = Math.ceil(step / (stepPower * stepDivisor)) * stepPower * stepDivisor;
let maxPrecision = this.get("maxPrecision");
if ($type.isNumber(maxPrecision)) {
let ceiledStep = $math.ceil(step, maxPrecision);
if (maxPrecision < Number.MAX_VALUE && step !== ceiledStep) {
step = ceiledStep;
}
}
let decCount = 0;
// in case numbers are smaller than 1
if (stepPower < 1) {
// exponent is less then 1 too. Count decimals of exponent
decCount = Math.round(Math.abs(Math.log(Math.abs(stepPower)) * Math.LOG10E)) + 1;
// round step
step = $math.round(step, decCount);
}
// final min and max
let minCount = Math.floor(min / step);
min = $math.round(step * minCount, decCount);
let maxCount;
if (!strictMode) {
maxCount = Math.ceil(max / step);
}
else {
maxCount = Math.floor(max / step);
}
if (maxCount === minCount) {
maxCount++;
}
max = $math.round(step * maxCount, decCount);
if (max < initialMax) {
max = max + step;
}
if (min > initialMin) {
min = min - step;
}
step = this.fixSmallStep(step);
return { min: min, max: max, step: step };
}
/**
* Returns text to be used in an axis tooltip for specific relative position.
*
* @param position Position
* @return Tooltip text
*/
getTooltipText(position, _adjustPosition) {
const numberFormat = this.get("tooltipNumberFormat", this.get("numberFormat"));
const formatter = this.getNumberFormatter();
const extraDecimals = this.get("extraTooltipPrecision", 0);
const decimals = this.getPrivate("stepDecimalPlaces", 0) + extraDecimals;
const value = $math.round(this.positionToValue(position), decimals);
if (numberFormat) {
return formatter.format(value, numberFormat);
}
else {
return formatter.format(value, undefined, decimals);
}
}
/**
* Returns a data item from series that is closest to the `position`.
*
* @param series Series
* @param position Relative position
* @return Data item
*/
getSeriesItem(series, position) {
let fieldName = (this.getPrivate("name") + this.get("renderer").getPrivate("letter"));
let value = this.positionToValue(position);
let index = undefined;
let oldDiff;
$array.each(series.dataItems, (dataItem, i) => {
const diff = Math.abs(dataItem.get(fieldName) - value);
if (index === undefined || diff < oldDiff) {
index = i;
oldDiff = diff;
}
});
if (index != null) {
return series.dataItems[index];
}
}
/**
* Zooms the axis to specific `start` and `end` values.
*
* Optional `duration` specifies duration of zoom animation in milliseconds.
*
* @param start Start value
* @param end End value
* @param duration Duration in milliseconds
*/
zoomToValues(start, end, duration) {
const min = this.getPrivate("minFinal", 0);
const max = this.getPrivate("maxFinal", 0);
if (this.getPrivate("min") != null && this.getPrivate("max") != null) {
this.zoom((start - min) / (max - min), (end - min) / (max - min), duration);
}
}
/**
* Syncs with a target axis.
*
* @param min Min
* @param max Max
* @param step Step
*/
_syncAxes(min, max, step, syncMin, syncMax, syncStep) {
let axis = this.get("syncWithAxis");
if (axis) {
let count = Math.round(syncMax - syncMin) / syncStep;
let currentCount = Math.round((max - min) / step);
let gridCount = this.get("renderer").gridCount();
if ($type.isNumber(count) && $type.isNumber(currentCount)) {
let synced = false;
let c = 0;
let diff = (max - min) * 0.01;
let omin = min;
let omax = max;
let ostep = step;
while (synced != true) {
synced = this._checkSync(omin, omax, ostep, count);
c++;
if (c > 500) {
synced = true;
}
if (!synced) {
if (c / 3 == Math.round(c / 3)) {
omin = min - diff * c;
if (min >= 0 && omin < 0) {
omin = 0;
}
}
else {
omax = max + diff * c;
if (omax <= 0 && omax > 0) {
omax = 0;
}
}
let minMaxStep = this._adjustMinMax(omin, omax, gridCount, true);
omin = minMaxStep.min;
omax = minMaxStep.max;
ostep = minMaxStep.step;
}
else {
min = omin;
max = omax;
step = ostep;
}
}
}
}
return { min: min, max: max, step: step };
}
/**
* Returns `true` if axis needs to be resunced with some other axis.
*/
_checkSync(min, max, step, count) {
let currentCount = (max - min) / step;
for (let i = 1; i < count; i++) {
if ($math.round(currentCount / i, 1) == count || currentCount * i == count) {
return true;
}
}
return false;
}
/**
* Returns relative position between two grid lines of the axis.
*
* @return Position
*/
getCellWidthPosition() {
let max = this.getPrivate("selectionMax", this.getPrivate("max"));
let min = this.getPrivate("selectionMin", this.getPrivate("min"));
if ($type.isNumber(max) && $type.isNumber(min)) {
return this.getPrivate("step", 1) / (max - min);
}
return 0.05;
}
}
Object.defineProperty(ValueAxis, "className", {
enumerable: true,
configurable: true,
writable: true,
value: "ValueAxis"
});
Object.defineProperty(ValueAxis, "classNames", {
enumerable: true,
configurable: true,
writable: true,
value: Axis.classNames.concat([ValueAxis.className])
});
//# sourceMappingURL=ValueAxis.js.map