UNPKG

@devexperts/dxcharts-lite

Version:
277 lines (276 loc) 12.7 kB
/* * 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 { Subject } from 'rxjs'; import { CanvasElement } from '../../canvas/canvas-bounds-container'; import { ChartBaseElement } from '../../model/chart-base-element'; import { uuid } from '../../utils/uuid.utils'; import { resolveColorForArea, resolveColorForBar, resolveColorForBaseLine, resolveColorForCandle, resolveColorForHistogram, resolveColorForLine, resolveColorForScatterPlot, resolveColorForTrendAndHollow, resolveDefaultColorForLabel, } from './label-color.functions'; import { LabelsGroups } from './price_labels/y-axis-labels.model'; import { YAxisScaleHandler } from './y-axis-scale.handler'; import { YAxisModel } from './y-axis.model'; import { merge as mergeObj } from '../../utils/merge.utils'; import { cloneUnsafe } from '../../utils/object.utils'; /** * Y axis component. Contains all Y axis related logic. */ export class YAxisComponent extends ChartBaseElement { constructor(eventBus, config, mainCanvasModel, canvasModel, scale, canvasInputListeners, canvasBoundsContainer, chartPanComponent, cursors, valueFormatter, dataSeriesProvider, paneUUID, extentIdx, hitTestCanvasModel, chartResizeHandler, initialState) { super(); this.eventBus = eventBus; this.config = config; this.mainCanvasModel = mainCanvasModel; this.canvasModel = canvasModel; this.scale = scale; this.canvasInputListeners = canvasInputListeners; this.canvasBoundsContainer = canvasBoundsContainer; this.chartPanComponent = chartPanComponent; this.cursors = cursors; this.paneUUID = paneUUID; this.extentIdx = extentIdx; this.hitTestCanvasModel = hitTestCanvasModel; this.chartResizeHandler = chartResizeHandler; this.labelsColorByChartTypeMap = {}; this.axisTypeSetSubject = new Subject(); this.axisAlignSetSubject = new Subject(); this.axisAlignMovedSubject = new Subject(); /* This function assigns a callback to be executed when a double-click event is detected. * It accepts one parameter `cb`, which is a callback function. * When a double-click event occurs, the specified callback function `cb` will be invoked. * By default it calls auto scale on YAxis */ this.setDblClickCallback = (cb) => this.yAxisScaleHandler.setDblClickCallback(cb); /* This function assigns a callback to be executed when a double-tap event is detected. * Similar to the dblclick function, it takes one parameter `cb`, which is a callback function. * This function ensures that the callback `cb` is called whenever a double-tap event is triggered. * By default it calls auto scale on YAxis */ this.setDblTapCallback = (cb) => this.yAxisScaleHandler.setDblTapCallback(cb); const initialStateCopy = initialState ? cloneUnsafe(initialState) : {}; this.state = mergeObj(initialStateCopy, config.components.yAxis, { overrideExisting: false, addIfMissing: true, }); //#region init yAxisScaleHandler this.yAxisScaleHandler = new YAxisScaleHandler(eventBus, this.state, chartPanComponent, scale, canvasInputListeners, canvasBoundsContainer, canvasBoundsContainer.getBoundsHitTest(CanvasElement.PANE_UUID_Y_AXIS(paneUUID, extentIdx)), hitTestCanvasModel); this.addChildEntity(this.yAxisScaleHandler); //#endregion this.model = new YAxisModel(this.paneUUID, eventBus, this.state, canvasBoundsContainer, canvasModel, scale, valueFormatter, dataSeriesProvider, extentIdx, this.chartResizeHandler); this.addChildEntity(this.model); this.updateCursor(); this.registerDefaultLabelColorResolvers(); } setExtentIdx(extentIdx) { this.extentIdx = extentIdx; this.model.extentIdx = extentIdx; this.yAxisScaleHandler.deactivate(); this.removeChildEntity(this.yAxisScaleHandler); this.yAxisScaleHandler = new YAxisScaleHandler(this.eventBus, this.state, this.chartPanComponent, this.scale, this.canvasInputListeners, this.canvasBoundsContainer, this.canvasBoundsContainer.getBoundsHitTest(CanvasElement.PANE_UUID_Y_AXIS(this.paneUUID, extentIdx)), this.hitTestCanvasModel); this.addChildEntity(this.yAxisScaleHandler); } /** * Registers default label color resolvers for different chart types. * @private * @function * @name registerDefaultLabelColorResolver * @returns {void} */ registerDefaultLabelColorResolvers() { this.registerLabelColorResolver('candle', resolveColorForCandle); this.registerLabelColorResolver('bar', resolveColorForBar); this.registerLabelColorResolver('line', resolveColorForLine); this.registerLabelColorResolver('area', resolveColorForArea); this.registerLabelColorResolver('scatterPlot', resolveColorForScatterPlot); this.registerLabelColorResolver('histogram', resolveColorForHistogram); this.registerLabelColorResolver('baseline', resolveColorForBaseLine); this.registerLabelColorResolver('trend', resolveColorForTrendAndHollow); this.registerLabelColorResolver('hollow', resolveColorForTrendAndHollow); } doActivate() { this.addRxSubscription(this.scale.beforeStartAnimationSubject.subscribe(() => this.state.type === 'percent' && this.scale.haltAnimation())); } updateCursor() { if (this.state.type === 'percent') { this.cursors.setCursorForCanvasEl(CanvasElement.PANE_UUID_Y_AXIS(this.paneUUID, this.extentIdx), this.state.resizeDisabledCursor); } else { this.cursors.setCursorForCanvasEl(CanvasElement.PANE_UUID_Y_AXIS(this.paneUUID, this.extentIdx), this.state.cursor); } } /** * Updates labels visual appearance on canvas */ updateOrderedLabels(adjustYAxisWidth = false) { this.model.fancyLabelsModel.updateLabels(adjustYAxisWidth); } /** * Registers a label color resolver for a specific chart type. * * @param {BarType} chartType - The type of chart for which the label color resolver is being registered. * @param {LabelColorResolver} resolver - The function that will be used to resolve the color of the labels for the specified chart type. * @returns {void} */ registerLabelColorResolver(chartType, resolver) { this.labelsColorByChartTypeMap[chartType] = resolver; } /** * Returns a function that resolves the color for a label based on the type of data series. * @param {DataSeriesType} candlesType - The type of data series. * @returns {Function} - A function that resolves the color for a label. * If there is no color mapping for the given data series type, it returns the default color resolver function. */ getLabelsColorResolver(candlesType) { var _a; return (_a = this.labelsColorByChartTypeMap[candlesType]) !== null && _a !== void 0 ? _a : resolveDefaultColorForLabel; } //#region public methods /** * You can add a custom labels provider for additional labels on YAxis (like for drawings, symbol last price, studies, etc..) * @param groupName - a group in which labels position recalculation algorithm will be applied, usually it's subchart name * @param provider * @param id */ registerYAxisLabelsProvider(provider, groupName = LabelsGroups.MAIN, id = uuid()) { this.model.fancyLabelsModel.registerYAxisLabelsProvider(groupName, provider, id); return id; } /** * An easier way to manage custom y-axis labels, than y-axis labels providers. * However, overlapping avoidance is not supported * deprecated because of naming, use updateCustomYAxisLabel instead * @param name * @param label */ addSimpleYAxisLabel(name, label) { this.model.fancyLabelsModel.customLabels[name] = label; this.canvasModel.fireDraw(); } /** * Update custom y-axis label * @param name * @param label */ updateCustomYAxisLabel(name, label) { this.model.fancyLabelsModel.customLabels[name] = label; this.canvasModel.fireDraw(); } /** * @param name */ deleteSimpleYAxisLabel(name) { delete this.model.fancyLabelsModel.customLabels[name]; this.canvasModel.fireDraw(); } getAxisType() { return this.state.type; } /** * Unregister a Y axis labels provider from the specified group. * @param {string} groupName - The name of the group from which to unregister the provider. Defaults to LabelsGroups.MAIN. * @param {string} id - The ID of the provider to unregister. * @returns {string} - The ID of the unregistered provider. */ unregisterYAxisLabelsProvider(groupName = LabelsGroups.MAIN, id) { this.model.fancyLabelsModel.unregisterYAxisLabelsProvider(groupName, id); return id; } getBounds() { return this.canvasBoundsContainer.getBounds(CanvasElement.PANE_UUID_Y_AXIS(this.paneUUID, this.extentIdx)); } /** * If custom pane has y-axis it has to register width contributor to correctly calculate overall y-axis width. * @param contributor */ registerYAxisWidthContributor(contributor) { this.canvasBoundsContainer.yAxisBoundsContainer.registerYAxisWidthContributor(contributor); } /** * Sets the type of axis: percent, regular or logarithmic. * @param type - the type of axis */ setAxisType(type) { if (type !== this.state.type) { this.state.type = type; this.config.components.yAxis.type = type; this.axisTypeSetSubject.next(type); this.scale.autoScale(true); this.model.fancyLabelsModel.updateLabels(true); this.updateCursor(); this.mainCanvasModel.fireDraw(); } } /** * Change YAxis position to left or to right * @param align */ setYAxisAlign(align) { this.state.align = align; this.canvasBoundsContainer.updateYAxisWidths(); this.axisAlignSetSubject.next(align); this.eventBus.fireDraw(); } /** * Controls visibility of the y-axis (additionally disable/enable component) */ setVisible(isVisible) { this.state.visible = isVisible; this.config.components.yAxis.visible = isVisible; isVisible ? this.activate() : this.deactivate(); this.model.fancyLabelsModel.updateLabels(); this.model.baseLabelsModel.updateLabels(); } /** * If visible, when you can see the y-axis on the chart */ isVisible() { return this.state.visible; } /** * Controls lockPriceToBarRatio of the y-axis */ setLockPriceToBarRatio(value = false) { this.scale.setLockPriceToBarRatio(value); } /** * Changes the visual type of particular label. * @param type - label type * @param mode - visual mode */ changeLabelMode(type, mode) { this.state.labels.settings[type].mode = mode; this.model.fancyLabelsModel.updateLabels(); } /** * Changes the visual type of particular label. * @param type - label type * @param mode - visual mode */ changeLabelAppearance(type, mode) { this.state.labels.settings[type].type = mode; this.model.fancyLabelsModel.updateLabels(); } /** * Sets the inverse price scale mode. Inverts Y axis vertically. * Inversion also works for candles, drawings and overlay studies. * @param inverse - true or false */ togglePriceScaleInverse(inverse = false) { this.scale.state.inverse = inverse; this.scale.inverseY = inverse; this.model.fancyLabelsModel.updateLabels(); this.scale.scaleInversedSubject.next(inverse); this.canvasModel.fireDraw(); } /** * Changes the visibility of the labels' descriptions. * @param {boolean} descVisibility - A boolean value indicating whether the descriptions should be visible or not. * @returns {void} */ changeLabelsDescriptionVisibility(descVisibility) { this.state.labels.descriptions = descVisibility; // recalculating labels is not needed, so just redraw YAxis this.canvasModel.fireDraw(); } }