@devexperts/dxcharts-lite
Version:
158 lines (157 loc) • 6.95 kB
JavaScript
/*
* 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);
},
});