UNPKG

@devexperts/dxcharts-lite

Version:
158 lines (157 loc) 6.95 kB
/* * Copyright (C) 2019 - 2026 Devexperts Solutions IE Limited * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. * If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. */ /* * Copyright (C) 2019 - 2025 Devexperts Solutions IE Limited * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. * If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { CanvasElement, CHART_UUID } from '../../../canvas/canvas-bounds-container'; import { ChartBaseElement } from '../../../model/chart-base-element'; import { DataSeriesModel, VisualSeriesPoint, defaultValueFormatter, } from '../../../model/data-series.model'; import { mergeHighLow } from '../../../model/scaling/auto-scale.model'; import { uuid } from '../../../utils/uuid.utils'; import { createYExtentFormatters } from '../../chart/price-formatters/price.formatter'; export class YExtentComponent extends ChartBaseElement { constructor(config, paneUUID, idx, paneComponent, chartBaseModel, canvasBoundsContainer, hitTestController, dynamicObjectsCanvasModel, scale, createYAxisComponent, dragNDrop, dataSeries = new Set(), formatters = { regular: defaultValueFormatter, }) { super(); this.config = config; this.paneUUID = paneUUID; this.idx = idx; this.paneComponent = paneComponent; this.chartBaseModel = chartBaseModel; this.canvasBoundsContainer = canvasBoundsContainer; this.hitTestController = hitTestController; this.dynamicObjectsCanvasModel = dynamicObjectsCanvasModel; this.scale = scale; this.dragNDrop = dragNDrop; this.dataSeries = dataSeries; this.formatters = formatters; this.getYAxisBounds = () => { return this.canvasBoundsContainer.getBounds(CanvasElement.PANE_UUID_Y_AXIS(this.paneUUID, this.idx)); }; this.yAxisHT = this.canvasBoundsContainer.getBoundsHitTest(CanvasElement.PANE_UUID_Y_AXIS(this.paneUUID, this.idx)); this.toVisualPoints = (points) => points.map(p => new VisualSeriesPoint(this.chartBaseModel.dataFromTimestamp(p.timestamp).centerUnit, p.close)); this.toY = (value) => { var _a, _b; return (_b = (_a = this.mainDataSeries) === null || _a === void 0 ? void 0 : _a.view.toY(value)) !== null && _b !== void 0 ? _b : 1; }; this.valueFormatter = (value, dataSeries) => { if (!this.formatters[this.yAxis.getAxisType()]) { return this.formatters.regular(value); } const { regular, percent, logarithmic } = this.formatters; switch (this.yAxis.getAxisType()) { case 'regular': return this.formatters.regular(value); case 'percent': return percent ? percent(value, dataSeries) : regular(value); case 'logarithmic': return logarithmic ? logarithmic(value) : regular(value); default: return this.regularFormatter(value); } }; this.addChildEntity(scale); this.setValueFormatters(createYExtentFormatters(this, config)); this.yAxis = createYAxisComponent(this.valueFormatter.bind(this), () => this.mainDataSeries); this.addChildEntity(this.yAxis); } doDeactivate() { super.doDeactivate(); this.dataSeries.forEach(ds => { this.paneComponent.seriesRemovedSubject.next(ds); ds.deactivate(); }); } /** * Returns the bounds of the scale model. * @returns {Bounds} The bounds of the scale model. */ getBounds() { return this.scale.getBounds(); } getBaseline() { var _a, _b; return (_b = (_a = this.mainDataSeries) === null || _a === void 0 ? void 0 : _a.getBaseline()) !== null && _b !== void 0 ? _b : 1; } /** * Creates a new DataSeriesModel object. * @returns {DataSeriesModel} - The newly created DataSeriesModel object. */ createDataSeries() { const series = new DataSeriesModel(this, uuid(), this.hitTestController.getNewDataSeriesHitTestId()); series.toVisualPoints = this.toVisualPoints; return series; } /** * Adds a new data series to the chart. * @param {DataSeriesModel} series - The data series to be added. * @returns {void} */ addDataSeries(series) { this.dataSeries.add(series); if (this.dataSeries.size === 1) { this.mainDataSeries = series; } else if (this.paneComponent.yExtentComponents.length > 1 && this.paneUUID !== CHART_UUID) { this.mainDataSeries = series; const ds = Array.from(this.paneComponent.mainExtent.dataSeries); this.paneComponent.mainExtent.mainDataSeries = ds[ds.length - 1]; } this.paneComponent.updateView(); this.paneComponent.seriesAddedSubject.next(series); } /** * Removes a data series from the chart. * * @param {DataSeriesModel} series - The data series to be removed. * @returns {void} */ removeDataSeries(series) { this.dataSeries.delete(series); this.paneComponent.updateView(); this.paneComponent.seriesRemovedSubject.next(series); } get regularFormatter() { return this.formatters.regular; } /** * Sets the pane value formatters for the current instance. * @param {YExtentFormatters} formatters - The pane value formatters to be set. */ setValueFormatters(formatters) { this.formatters = formatters; } /** * Returns the regular value from Y coordinate. * @param {number} y - The Y coordinate. * @returns {number} - The regular value. */ regularValueFromY(y) { var _a, _b; return (_b = (_a = this.mainDataSeries) === null || _a === void 0 ? void 0 : _a.view.priceFromY(y)) !== null && _b !== void 0 ? _b : this.scale.fromY(y); } } export const createDefaultYExtentHighLowProvider = (extent) => ({ isHighLowActive: () => true, calculateHighLow: state => { const allDataSeries = Array.from(extent.dataSeries); const activeDataSeries = allDataSeries.filter(ds => ds.highLowProvider.isHighLowActive()); const seriesToUse = activeDataSeries.length > 0 ? activeDataSeries : allDataSeries; if (seriesToUse.length === 0) { return { low: 0, high: 100 }; } const highLows = seriesToUse .map(ds => ds.highLowProvider.calculateHighLow(state)) .filter(hl => hl.high >= hl.low); if (highLows.length === 0) { return { low: 0, high: 100 }; } return mergeHighLow(highLows); }, });