UNPKG

@amcharts/amcharts4

Version:
1,134 lines 44.2 kB
/** * Category axis module */ import { __extends } from "tslib"; /** * ============================================================================ * IMPORTS * ============================================================================ * @hidden */ import { Axis, AxisDataItem } from "./Axis"; import { AxisRendererX } from "./AxisRendererX"; import { AxisRendererY } from "./AxisRendererY"; import { registry } from "../../core/Registry"; import { Dictionary } from "../../core/utils/Dictionary"; import { CategoryAxisBreak } from "./CategoryAxisBreak"; import * as $math from "../../core/utils/Math"; import * as $type from "../../core/utils/Type"; import * as $iter from "../../core/utils/Iterator"; /** * ============================================================================ * DATA ITEM * ============================================================================ * @hidden */ /** * Defines a [[DataItem]] for [[CategoryAxis]]. * * @see {@link DataItem} */ var CategoryAxisDataItem = /** @class */ (function (_super) { __extends(CategoryAxisDataItem, _super); /** * Constructor */ function CategoryAxisDataItem() { var _this = _super.call(this) || this; _this.seriesDataItems = {}; _this.className = "CategoryAxisDataItem"; _this.text = "{category}"; _this.locations.category = 0; _this.locations.endCategory = 1; _this.deltaPosition = 0; _this.applyTheme(); return _this; } Object.defineProperty(CategoryAxisDataItem.prototype, "category", { /** * @return Category */ get: function () { if (this._adapterO) { if (this._adapterO.isEnabled("category")) { return this._adapterO.apply("category", this.properties.category); } } return this.properties.category; }, /** * Category. * * @param value Category */ set: function (value) { var oldCategory = this.properties.category; this.setProperty("category", value); if ($type.hasValue(oldCategory) && oldCategory != value) { if (this.component) { this.component.validateDataElement(this); } } }, enumerable: true, configurable: true }); Object.defineProperty(CategoryAxisDataItem.prototype, "endCategory", { /** * @return End category */ get: function () { return this.properties.endCategory; }, /** * End category. * * Used for items that span several categories, like [[CategoryAxisBreak]]. * * @param value End category */ set: function (value) { this.setProperty("endCategory", value); }, enumerable: true, configurable: true }); Object.defineProperty(CategoryAxisDataItem.prototype, "deltaPosition", { get: function () { return this.properties.deltaCoordinate; }, set: function (value) { if (value != this.properties.deltaCoordinate) { this.setProperty("deltaCoordinate", value); if (this.component) { this.component.invalidateDataItems(); this.component.invalidateSeries(); } } }, enumerable: true, configurable: true }); return CategoryAxisDataItem; }(AxisDataItem)); export { CategoryAxisDataItem }; /** * ============================================================================ * MAIN CLASS * ============================================================================ * @hidden */ /** * Used to create a category-based axis for the chart. * * ```TypeScript * // Create the axis * let xAxis = chart.xAxes.push(new am4charts.CategoryAxis()); * * // Set settings * xAxis.title.text = "Clients"; * ``` * ```JavaScript * // Create the axis * var valueAxis = chart.xAxes.push(new am4charts.CategoryAxis()); * * // Set settings * valueAxis.title.text = "Clients"; * ``` * ```JSON * "xAxes": [{ * "type": "CategoryAxis", * "title": { * "text": "Clients" * } * }] * ``` * * @see {@link ICategoryAxisEvents} for a list of available Events * @see {@link ICategoryAxisAdapters} for a list of available Adapters * @important */ var CategoryAxis = /** @class */ (function (_super) { __extends(CategoryAxis, _super); /** * Constructor */ function CategoryAxis() { var _this = // Init _super.call(this) || this; /** * A collection that holds Axis' data items sorted by each category. */ _this.dataItemsByCategory = new Dictionary(); _this.className = "CategoryAxis"; // Set field name _this.axisFieldName = "category"; _this._lastDataItem = _this.createDataItem(); _this._lastDataItem.component = _this; _this._disposers.push(_this._lastDataItem); // Apply theme _this.applyTheme(); var dataItemsByCategory = _this.dataItemsByCategory; _this.addDisposer(_this.mainDataSet.events.on("removed", function (event) { dataItemsByCategory.removeKey(event.oldValue.category); })); return _this; } /** * Returns a new/empty [[DataItem]] of the type appropriate for this object. * * @see {@link DataItem} * @return Data Item */ CategoryAxis.prototype.createDataItem = function () { return new CategoryAxisDataItem(); }; /** * Returns a new/empty [[AxisBreak]] of the appropriate type. * * @return Axis break */ CategoryAxis.prototype.createAxisBreak = function () { return new CategoryAxisBreak(); }; /** * Processes a related series' data item. * * @ignore Exclude from docs * @todo Description * @param dataItem Data item */ CategoryAxis.prototype.processSeriesDataItem = function (dataItem, axisLetter) { _super.prototype.processSeriesDataItem.call(this, dataItem, axisLetter); var category = dataItem["category" + this.axisLetter]; if ($type.hasValue(category)) { var categoryAxisDataItem = this.dataItemsByCategory.getKey(category); if (categoryAxisDataItem) { var seriesId = dataItem.component.uid; var seriesDataItems = categoryAxisDataItem.seriesDataItems[seriesId]; if (!seriesDataItems) { seriesDataItems = []; categoryAxisDataItem.seriesDataItems[seriesId] = seriesDataItems; } seriesDataItems.push(dataItem); } } else { dataItem.component.dataItems.remove(dataItem); } }; /** * Validates the data range. * * @ignore Exclude from docs * @todo Description (review) */ CategoryAxis.prototype.validateDataRange = function () { var _this = this; _super.prototype.validateDataRange.call(this); $iter.each(this._series.iterator(), function (series) { if ((series.xAxis instanceof CategoryAxis) && (series.yAxis instanceof CategoryAxis)) { series.invalidateDataRange(); } else { var startIndex = _this.positionToIndex(_this.start); var endIndex = _this.positionToIndex(_this.end); if (endIndex >= _this.dataItems.length) { endIndex--; } var seriesId = series.uid; var minIndex = void 0; var maxIndex = void 0; for (var i = startIndex; i <= endIndex; i++) { var axisDataItem = _this.dataItems.getIndex(i); if (axisDataItem) { var seriesDataItems = axisDataItem.seriesDataItems[seriesId]; if (seriesDataItems) { for (var i_1 = 0; i_1 < seriesDataItems.length; i_1++) { var seriesDataItem = seriesDataItems[i_1]; if (seriesDataItem) { var index = seriesDataItem.index; if (!$type.isNumber(minIndex) || index < minIndex) { minIndex = index; } if (!$type.isNumber(maxIndex) || index > maxIndex) { maxIndex = index; } } } } } } if ($type.isNumber(minIndex)) { series.startIndex = minIndex; } else { series.start = _this.start; } if ($type.isNumber(maxIndex)) { series.endIndex = maxIndex + 1; } else { series.end = _this.end; } // range might not change, but axis breaks might. if (_this._axisBreaks && _this._axisBreaks.length > 0) { series.invalidateDataRange(); } } }); }; /** * Validates the whole axis. Causes it to redraw. * * @ignore Exclude from docs * @todo Description (review) */ CategoryAxis.prototype.validate = function () { var _this = this; _super.prototype.validate.call(this); var dataCount = this.dataItems.length; var startIndex = $math.fitToRange(Math.floor(this.start * dataCount - 1), 0, dataCount); var endIndex = $math.fitToRange(Math.ceil(this.end * dataCount), 0, dataCount); if (this.renderer.invalid) { this.renderer.validate(); } // find frequency at which we'll show items var maxCount = this.renderer.axisLength / Math.max(this.renderer.minGridDistance, 1 / Number.MAX_SAFE_INTEGER); var frequency = Math.min(this.dataItems.length, Math.ceil((endIndex - startIndex) / maxCount)); this._startIndex = Math.floor(startIndex / frequency) * frequency; this._endIndex = Math.ceil(this.end * dataCount); this.fixAxisBreaks(); if (this._startIndex == this._endIndex) { this._endIndex++; } this._frequency = frequency; if (this.axisLength <= 0) { return; } this.maxZoomFactor = this.dataItems.length; if (this.dataItems.length <= 0) { this.maxZoomFactor = 1; } this.resetIterators(); // it's important to use protected variables here, as getters will return 0 - length // TODO use iterator instead // @ todo: not solved cat axis item fading startIndex = $math.max(0, this._startIndex - this._frequency); endIndex = $math.min(this.dataItems.length, this._endIndex + this._frequency); var itemIndex = 0; for (var i = 0; i < startIndex; i++) { var dataItem = this.dataItems.getIndex(i); dataItem.__disabled = true; } for (var i = endIndex, len = this.dataItems.length; i < len; i++) { var dataItem = this.dataItems.getIndex(i); dataItem.__disabled = true; } for (var i = startIndex; i < endIndex; i++) { if (i < this.dataItems.length) { var dataItem = this.dataItems.getIndex(i); if (i / this._frequency == Math.round(i / this._frequency)) { var axisBreak = this.isInBreak(i); if (!axisBreak) { this.appendDataItem(dataItem); this.validateDataElement(dataItem, itemIndex); } itemIndex++; } else { //previously we disabled all before, but this is better for cpu //this.validateDataElement(dataItem, itemIndex); // helps to solve shrinking // not good - creates all items dataItem.__disabled = true; } } } this.appendDataItem(this._lastDataItem); this.validateDataElement(this._lastDataItem, itemIndex + 1, this.dataItems.length); if (this._axisBreaks) { var axisBreaks = this._axisBreaks; axisBreaks.each(function (axisBreak) { var adjustedStartValue = axisBreak.adjustedStartValue; var adjustedEndValue = axisBreak.adjustedEndValue; if ($math.intersect({ start: adjustedStartValue, end: adjustedEndValue }, { start: _this._startIndex, end: _this._endIndex })) { for (var b = adjustedStartValue; b <= adjustedEndValue; b++) { var dataItem = _this.dataItems.getIndex(b); dataItem.__disabled = true; } var frequency_1 = $math.fitToRange(Math.ceil(_this._frequency / axisBreak.breakSize), 1, adjustedEndValue - adjustedStartValue); var itemIndex_1 = 0; if (axisBreak.breakSize > 0) { // TODO use iterator instead for (var b = adjustedStartValue; b <= adjustedEndValue; b = b + frequency_1) { var dataItem = _this.dataItems.getIndex(b); dataItem.__disabled = false; _this.appendDataItem(dataItem); _this.validateDataElement(dataItem, itemIndex_1); itemIndex_1++; } } } }); } this.validateBreaks(); this.validateAxisRanges(); this.ghostLabel.invalidate(); // solves font issue this.renderer.invalidateLayout(); }; /** * [validateDataElement description] * * @ignore Exclude from docs * @todo Description * @param dataItem [description] * @param itemIndex [description] */ CategoryAxis.prototype.validateDataElement = function (dataItem, itemIndex, index) { _super.prototype.validateDataElement.call(this, dataItem); dataItem.itemIndex = this._axisItemCount; this._axisItemCount++; //dataItem.__disabled = false; var renderer = this.renderer; if (!$type.isNumber(index)) { index = this.categoryToIndex(dataItem.category); } var endIndex = this.categoryToIndex(dataItem.endCategory); if (!$type.isNumber(endIndex)) { endIndex = index; } var position = this.indexToPosition(index, dataItem.locations.category); var endPosition = this.indexToPosition(endIndex, dataItem.locations.endCategory); dataItem.position = position; var fillEndIndex; var fillPosition; var fillEndPosition; if (dataItem.isRange) { fillEndIndex = endIndex; fillPosition = this.indexToPosition(index, dataItem.locations.category); fillEndPosition = this.indexToPosition(fillEndIndex, dataItem.locations.endCategory); } dataItem.point = renderer.positionToPoint(position); var tick = dataItem.tick; if (tick && !tick.disabled) { renderer.updateTickElement(tick, position, endPosition); } var grid = dataItem.grid; if (grid && !grid.disabled) { renderer.updateGridElement(grid, position, endPosition); } var label = dataItem.label; if (label && !label.disabled) { // theorethically this might result problems if category text changes, the range text won't change. But otherwise range.label.text = "custom text" won't work, which is not intuitive. if (!dataItem.isRange || label.text == undefined) { dataItem.text = dataItem.text; } renderer.updateLabelElement(label, position, endPosition); if ((renderer instanceof AxisRendererY && dataItem.label.measuredWidth > this.ghostLabel.measuredWidth) || (renderer instanceof AxisRendererX && dataItem.label.measuredHeight > this.ghostLabel.measuredHeight)) { if (dataItem.label.html) { this.ghostLabel.html = dataItem.label.currentText; } else { this.ghostLabel.text = dataItem.label.currentText; } } } var fill = dataItem.axisFill; if (fill && !fill.disabled) { if (!dataItem.isRange) { fillEndIndex = index + this._frequency; fillPosition = this.indexToPosition(index, fill.location); fillEndPosition = this.indexToPosition(fillEndIndex, fill.location); } renderer.updateFillElement(fill, fillPosition, fillEndPosition); if (!dataItem.isRange) { this.fillRule(dataItem, itemIndex); } } if (dataItem.bullet) { renderer.updateBullet(dataItem.bullet, position, endPosition); } var mask = dataItem.mask; if (mask) { renderer.updateFillElement(mask, fillPosition, fillEndPosition); } }; /** * @ignore */ CategoryAxis.prototype.disposeData = function () { this.dataItemsByCategory.clear(); _super.prototype.disposeData.call(this); }; /** * Processes the axis data item. * * @ignore Exclude from docs * @param dataItem Data item * @param dataContext The raw data that corresponds to this data item */ CategoryAxis.prototype.processDataItem = function (dataItem, dataContext) { if (dataItem) { // creat a collection for fast access _super.prototype.processDataItem.call(this, dataItem, dataContext); // check if such category already exists //let existingDataItem: CategoryAxisDataItem = this.dataItemsByCategory.getKey(dataItem.category); //if (existingDataItem && existingDataItem != dataItem) { // this.dataItems.remove(existingDataItem); //} if ($type.hasValue(dataItem.category)) { this.dataItemsByCategory.setKey(dataItem.category, dataItem); } } }; CategoryAxis.prototype.getDataItem = function (dataContext) { var category = (dataContext[this.dataFields.category]); if ($type.hasValue(category)) { var dataItem = this.dataItemsByCategory.getKey(category); if (dataItem) { return dataItem; } else { return this.dataItems.create(); } } }; /** * Converts a category index to an actual screen coordinate on the axis. * * `location` identifies relative location within category. 0 - beginning, * 0.5 - middle, 1 - end, and anything inbetween. * * @param index Index * @param location Location (0-1) * @return Position (px) */ CategoryAxis.prototype.indexToPosition = function (index, location) { if (!$type.isNumber(location)) { location = 0.5; } var startIndex = this.startIndex; var endIndex = this.endIndex; var difference = this.adjustDifference(startIndex, endIndex); var startLocation = this.startLocation; var endLocation = this.endLocation; difference -= startLocation; difference -= (1 - endLocation); if (this._axisBreaks) { var axisBreaks = this._axisBreaks; $iter.eachContinue(axisBreaks.iterator(), function (axisBreak) { var breakStartIndex = axisBreak.adjustedStartValue; var breakEndIndex = axisBreak.adjustedEndValue; if (index < startIndex || !$type.isNumber(breakStartIndex) || !$type.isNumber(breakEndIndex)) { return false; } if ($math.intersect({ start: breakStartIndex, end: breakEndIndex }, { start: startIndex, end: endIndex })) { breakStartIndex = Math.max(startIndex, breakStartIndex); breakEndIndex = Math.min(endIndex, breakEndIndex); var breakSize = axisBreak.breakSize; // value to the right of break end if (index > breakEndIndex) { startIndex += (breakEndIndex - breakStartIndex) * (1 - breakSize); } // value to the left of break start else if (index < breakStartIndex) { } // value within break else { index = breakStartIndex + (index - breakStartIndex) * breakSize; } } return true; }); } var deltaPosition = 0; var dataItem = this.dataItems.getIndex(index); if (dataItem) { deltaPosition = dataItem.deltaPosition; } return $math.round(deltaPosition + (index + location - startLocation - startIndex) / difference, 5); }; /** * Converts a string category name to relative position on axis. * * `location` identifies relative location within category. 0 - beginning, * 0.5 - middle, 1 - end, and anything inbetween. * * @param category Category name * @param location Location (0-1) * @return Position */ CategoryAxis.prototype.categoryToPosition = function (category, location) { var index = this.categoryToIndex(category); return this.indexToPosition(index, location); }; /** * Converts a string category name to a orientation point (x, y, angle) on axis * * `location` identifies relative location within category. 0 - beginning, * 0.5 - middle, 1 - end, and anything inbetween. * @param category Category name * @param location Location (0-1) * @return Orientation point */ CategoryAxis.prototype.categoryToPoint = function (category, location) { var position = this.categoryToPosition(category, location); var point = this.renderer.positionToPoint(position); var angle = this.renderer.positionToAngle(position); return { x: point.x, y: point.y, angle: angle }; }; /** * Converts a string category name to a orientation point (x, y, angle) on axis * * `location` identifies relative location within category. 0 - beginning, * 0.5 - middle, 1 - end, and anything inbetween. * @param category Category name * @param location Location (0-1) * @return Orientation point */ CategoryAxis.prototype.anyToPoint = function (category, location) { return this.categoryToPoint(category, location); }; /** * Converts a string category name to relative position on axis. * * An alias to `categoryToPosition()`. * * @param category Category name * @param location Location (0-1) * @return Relative position */ CategoryAxis.prototype.anyToPosition = function (category, location) { return this.categoryToPosition(category, location); }; /** * Converts named category to an index of data item it corresponds to. * * @param category Category * @return Data item index */ CategoryAxis.prototype.categoryToIndex = function (category) { if ($type.hasValue(category)) { var dataItem = this.dataItemsByCategory.getKey(category); if (dataItem) { return dataItem.index; } } }; /** * Zooms the axis to specific named ctaegories. * * @param startCategory Start category * @param endCategory End category */ CategoryAxis.prototype.zoomToCategories = function (startCategory, endCategory) { this.zoomToIndexes(this.categoryToIndex(startCategory), this.categoryToIndex(endCategory) + 1); }; /** * [getAnyRangePath description] * * @ignore Exclude from docs * @todo Description * @param start [description] * @param end [description] * @param startLocation [description] * @param endLocation [description] * @return [description] */ CategoryAxis.prototype.getAnyRangePath = function (start, end, startLocation, endLocation) { var startPos = this.categoryToPosition(start, startLocation); var endPos = this.categoryToPosition(end, endLocation); return this.getPositionRangePath(startPos, endPos); // Base class (Axis) gets range shape from AxisRenderer }; /** * Takes an absolute position (px) within axis and adjust it to a specific * `location` within category it corresponds to. * * @param position Source position (px) * @param location Location within category (0-1) * @return Adjusted position (px) */ CategoryAxis.prototype.roundPosition = function (position, location) { var index = this.positionToIndex(position); return this.indexToPosition(index, location); }; /** * Finds and returns first series data item with specific category * @param series Target series * @param category Category * @return XYSeriesDataItem data item */ CategoryAxis.prototype.getFirstSeriesDataItem = function (series, category) { for (var i = 0; i < series.dataItems.length; i++) { var dataItem = series.dataItems.getIndex(i); if (series.xAxis == this) { if (dataItem.categoryX == category) { return dataItem; } } if (series.yAxis == this) { if (dataItem.categoryY == category) { return dataItem; } } } }; /** * Finds and returns last series data item with specific category. * @param series Target series * @param category Category * @return XYSeriesDataItem data item */ CategoryAxis.prototype.getLastSeriesDataItem = function (series, category) { for (var i = series.dataItems.length - 1; i >= 0; i--) { var dataItem = series.dataItems.getIndex(i); if (series.xAxis == this) { if (dataItem.categoryX == category) { return dataItem; } } if (series.yAxis == this) { if (dataItem.categoryY == category) { return dataItem; } } } }; // todo: optimize CategoryAxis.prototype.getSeriesDataItemByCategory = function (category, series) { var _this = this; var seriesDataItem; series.dataItems.each(function (dataItem) { if (series.xAxis == _this) { if (dataItem.categoryX == category) { seriesDataItem = dataItem; } } else if (series.yAxis == _this) { if (dataItem.categoryY == category) { seriesDataItem = dataItem; } } }); return seriesDataItem; }; /** * Returns a data item from Series that corresponds to a specific absolute * position on the Axis. * * @param series Target series * @param position Position (px) * @return XYSeriesDataItem data item */ CategoryAxis.prototype.getSeriesDataItem = function (series, position, findNearest) { var _this = this; if ($type.isNumber(position)) { var index_1 = this.positionToIndex(position); if (index_1 >= this.dataItems.length) { index_1--; } var dataItem = this.dataItems.getIndex(index_1); if (dataItem) { var category_1 = dataItem.category; var sdi_1; var seriesDataItem = series.dataItems.getIndex(index_1); if (seriesDataItem) { if (series.xAxis == this) { if (seriesDataItem.categoryX == category_1) { return seriesDataItem; } } if (series.yAxis == this) { if (seriesDataItem.categoryY == category_1) { return seriesDataItem; } } } series.dataItems.each(function (dataItem) { if (series.xAxis == _this) { if (dataItem.categoryX == category_1) { if (!sdi_1) { sdi_1 = dataItem; } if (Math.abs(index_1 - sdi_1.index) > Math.abs(index_1 - dataItem.index)) { sdi_1 = dataItem; } } } if (series.yAxis == _this) { if (dataItem.categoryY == category_1) { if (!sdi_1) { sdi_1 = dataItem; } if (Math.abs(index_1 - sdi_1.index) > Math.abs(index_1 - dataItem.index)) { sdi_1 = dataItem; } } } }); //@todo if (findNearest) { } return sdi_1; } } }; /** * Returns the X coordinate for series' data item. * * @ignore Exclude from docs * @todo Description (review) * @param dataItem Data item * @param key Category * @param location Location (0-1) * @return X coordinate (px) */ CategoryAxis.prototype.getX = function (dataItem, key, location, stackKey, range) { var position = this.getPositionX(dataItem, key, location, stackKey, range); if ($type.isNaN(position)) { return this.basePoint.x; } else { return this.renderer.positionToPoint(position).x; } }; /** * Returns relative position on axis for series' data item. * * @since 4.5.14 * @param dataItem Data item * @param key Category * @param location Location (0-1) * @return Relative position */ CategoryAxis.prototype.getPositionX = function (dataItem, key, location, stackKey, range) { var position; if ($type.hasValue(key)) { position = this.categoryToPosition(dataItem.categories[key], location); } if (range) { position = $math.fitToRange(position, range.start, range.end); } return position; }; /** * Returns the Y coordinate for series' data item. * * @ignore Exclude from docs * @todo Description (review) * @param dataItem Data item * @param key Category * @param location Location (0-1) * @return Y coordinate (px) */ CategoryAxis.prototype.getY = function (dataItem, key, location, stackKey, range) { var position = this.getPositionY(dataItem, key, location, stackKey, range); if ($type.isNaN(position)) { return this.basePoint.y; } else { return this.renderer.positionToPoint(position).y; } }; /** * Returns relative position on axis for series' data item. * * @since 4.5.14 * @param dataItem Data item * @param key Category * @param location Location (0-1) * @return Relative position */ CategoryAxis.prototype.getPositionY = function (dataItem, key, location, stackKey, range) { var position; if ($type.hasValue(key)) { position = this.categoryToPosition(dataItem.categories[key], location); } if (range) { position = $math.fitToRange(position, range.start, range.end); } return position; }; /** * Returns an angle for series data item. * * @ignore Exclude from docs * @todo Description (review) * @param dataItem Data item * @param key Category * @param location Location (0-1) * @param stackKey Stack key (?) * @param range Range to fit in * @return Angle */ CategoryAxis.prototype.getAngle = function (dataItem, key, location, stackKey, range) { var position = this.categoryToPosition(dataItem.categories[key], location); if (range) { position = $math.fitToRange(position, range.start, range.end); } return this.positionToAngle(position); }; /** * Returns an absolute pixel coordinate of the start of the cell (category), * that specific position value falls into. * * @ignore Exclude from docs * @todo Description (review) * @param position Position (px) * @return Cell start position (px) */ CategoryAxis.prototype.getCellStartPosition = function (position) { return this.roundPosition(position, 0); }; /** * Returns an absolute pixel coordinate of the end of the cell (category), * that specific position value falls into. * * @ignore Exclude from docs * @todo Description (review) * @param position Position (px) * @return Cell end position (px) */ CategoryAxis.prototype.getCellEndPosition = function (position) { return this.roundPosition(position, 1); }; /** * Returns text to show in a category tooltip, based on specific position * within axis. * * @ignore Exclude from docs * @param position Position (px) * @return Label (category) */ CategoryAxis.prototype.getTooltipText = function (position) { var dataItem = this.dataItems.getIndex(this.positionToIndex(position)); if (dataItem) { this.tooltipDataItem = dataItem; this.tooltip.dataItem = dataItem; if (this.tooltipText) { return this.tooltipText; } if (!this._adapterO) { return dataItem.category; } else { return this._adapterO.apply("getTooltipText", dataItem.category); } } }; /** * Returns an index of the category that corresponds to specific pixel * position within axis. * * @param position Position (px) * @return Category index */ CategoryAxis.prototype.positionToIndex = function (position) { position = $math.round(position, 10); if (position < 0) { position = 0; } if (position > 1) { position = 1; } var startIndex = this.startIndex; var endIndex = this.endIndex; var difference = endIndex - startIndex - this.startLocation - (1 - this.endLocation); position += 1 / difference * this.startLocation; var index = null; if (this._axisBreaks) { var axisBreaks = this._axisBreaks; // in case we have some axis breaks $iter.eachContinue(axisBreaks.iterator(), function (axisBreak) { var breakStartPosition = axisBreak.startPosition; var breakEndPosition = axisBreak.endPosition; var breakStartIndex = axisBreak.adjustedStartValue; var breakEndIndex = axisBreak.adjustedEndValue; breakStartIndex = $math.max(breakStartIndex, startIndex); breakEndIndex = $math.min(breakEndIndex, endIndex); var breakSize = axisBreak.breakSize; difference -= (breakEndIndex - breakStartIndex) * (1 - breakSize); // position to the right of break end if (position > breakEndPosition) { startIndex += (breakEndIndex - breakStartIndex) * (1 - breakSize); } // position to the left of break start else if (position < breakStartPosition) { } // value within break else { var breakPosition = (position - breakStartPosition) / (breakEndPosition - breakStartPosition); index = breakStartIndex + Math.round(breakPosition * (breakEndIndex - breakStartIndex)); return false; } return true; }); } if (!$type.isNumber(index)) { index = Math.floor(position * difference + startIndex); } if (index >= this.dataItems.length) { index = this.dataItems.length - 1; } // not good, when panning out of bounds, each time one less item gets selected //if (index >= endIndex) { // index--; //} return index; }; /** * Returns category based on position. * * Please note that `position` represents position within axis which may be * zoomed and not correspond to Cursor's `position`. * * To convert Cursor's `position` to Axis' `position` use `toAxisPosition()` method. * * This is a synonim of `getPositionLabel()` implemented here for consistentcy. * * @since 4.3.8 * @see {@link https://www.amcharts.com/docs/v4/tutorials/tracking-cursors-position-via-api/#Tracking_Cursor_s_position} For more information about cursor tracking. * @param position Relative position on axis (0-1) * @return Position label */ CategoryAxis.prototype.positionToCategory = function (position) { return this.getPositionLabel(position); }; /** * Returns category based on position. * * Please note that `position` represents position within axis which may be * zoomed and not correspond to Cursor's `position`. * * To convert Cursor's `position` to Axis' `position` use `toAxisPosition()` method. * * @see {@link https://www.amcharts.com/docs/v4/tutorials/tracking-cursors-position-via-api/#Tracking_Cursor_s_position} For more information about cursor tracking. * @param position Relative position on axis (0-1) * @return Position label */ CategoryAxis.prototype.getPositionLabel = function (position) { var dataItem = this.dataItems.getIndex(this.positionToIndex(position)); if (dataItem) { return dataItem.category; } }; Object.defineProperty(CategoryAxis.prototype, "basePoint", { /** * Coordinates of the actual axis start. * * @ignore Exclude from docs * @return Base point */ get: function () { // This makes base grid to be drawn at the end of the axis and adds extra // grid which we need to nicely close the chart. return this.renderer.positionToPoint(1); }, enumerable: true, configurable: true }); /** * Initializes Axis' renderer. * * @ignore Exclude from docs */ CategoryAxis.prototype.initRenderer = function () { _super.prototype.initRenderer.call(this); var renderer = this.renderer; renderer.baseGrid.disabled = true; }; Object.defineProperty(CategoryAxis.prototype, "frequency", { /** * Current frequency of labels of the axis. * * Normally it would be 1, but when labels start to be hidden due * to `minGridDistance` this read-only property will increase. * * @readonly * @since 4.2.0 * @return Label frequency */ get: function () { return this._frequency; }, enumerable: true, configurable: true }); Object.defineProperty(CategoryAxis.prototype, "sortBySeries", { /** * @return Sort categories? */ get: function () { return this.getPropertyValue("sortBySeries"); }, /** * If set to a reference of [[ColumnSeries]] the categories will be sorted * by actual values. * * The categories are ordered in descending order (from highest values to * lowest). To reverse the order, use axis renderer's `inversed` setting. * E.g.: * * ```TypeScript * categoryAxis.sortBySeries = series; * categoryAxis.renderer.inversed = true; * ``` * ```JavaScript * categoryAxis.sortBySeries = series; * categoryAxis.renderer.inversed = true; * ``` * ```JSON * { * // ... * "xAxes": [{ * // ... * "sortBySeries": "s1", * "renderer": { * // ... * "inversed": true * } * }] * } * ``` * * @since 4.8.7 * @param value Sort categories? */ set: function (value) { this.setPropertyValue("sortBySeries", value, true); }, enumerable: true, configurable: true }); /** * Processes JSON-based config before it is applied to the object. * * @ignore Exclude from docs * @param config Config */ CategoryAxis.prototype.processConfig = function (config) { if (config) { if ($type.hasValue(config.sortBySeries) && $type.isString(config.sortBySeries)) { if (this.map.hasKey(config.sortBySeries)) { config.sortBySeries = this.map.getKey(config.sortBySeries); } else { this.addDelayedMap("sortBySeries", config.sortBySeries); delete config.sortBySeries; } } } _super.prototype.processConfig.call(this, config); }; return CategoryAxis; }(Axis)); export { CategoryAxis }; /** * Register class, so that it can be instantiated using its name from * anywhere. * * @ignore */ registry.registeredClasses["CategoryAxis"] = CategoryAxis; registry.registeredClasses["CategoryAxisDataItem"] = CategoryAxisDataItem; //# sourceMappingURL=CategoryAxis.js.map