UNPKG

@devexperts/dxcharts-lite

Version:
118 lines (117 loc) 6.55 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 { merge } from 'rxjs'; import { filter, pairwise } from 'rxjs/operators'; import { ChartBaseElement } from '../../model/chart-base-element'; import { CanvasElement } from '../../canvas/canvas-bounds-container'; import { EVENT_RESIZED } from '../../events/events'; import { NavigationMapDrawer } from './navigation-map.drawer'; import { NavigationMapMoveHandler } from './navigation-map-move.handler'; import { floor } from '../../utils/math.utils'; /** * Navigation map component for chart. * Controls navigation map in the bottom. */ export class NavigationMapComponent extends ChartBaseElement { constructor(eventBus, chartModel, canvasModel, config, canvasInputListeners, canvasBoundsContainer, drawingManager, formatterFactory, chartPanComponent, cursorHandler) { super(); this.eventBus = eventBus; this.chartModel = chartModel; this.canvasModel = canvasModel; this.config = config; this.canvasInputListeners = canvasInputListeners; this.canvasBoundsContainer = canvasBoundsContainer; this.chartPanComponent = chartPanComponent; this.visualCandles = []; const navigationMapDrawer = new NavigationMapDrawer(config, chartModel, canvasModel, canvasBoundsContainer, formatterFactory, () => this.visualCandles); drawingManager.addDrawer(navigationMapDrawer, CanvasElement.N_MAP_CHART); this.navigationMapMoveHandler = new NavigationMapMoveHandler(this.eventBus, this.chartModel, this.chartModel.scale, this.canvasInputListeners, this.canvasBoundsContainer, this.chartPanComponent); cursorHandler.setCursorForCanvasEl(CanvasElement.N_MAP_CHART, config.components.navigationMap.cursors.chart); cursorHandler.setCursorForCanvasEl(CanvasElement.N_MAP_BTN_L, config.components.navigationMap.cursors.buttonLeft); cursorHandler.setCursorForCanvasEl(CanvasElement.N_MAP_BTN_R, config.components.navigationMap.cursors.buttonRight); cursorHandler.setCursorForCanvasEl(CanvasElement.N_MAP_KNOT_L, config.components.navigationMap.cursors.leftResizer); cursorHandler.setCursorForCanvasEl(CanvasElement.N_MAP_KNOT_R, config.components.navigationMap.cursors.rightResizer); cursorHandler.setCursorForCanvasEl(CanvasElement.N_MAP_SLIDER_WINDOW, config.components.navigationMap.cursors.slider); } /** * Method to activate the chart. It subscribes to the observables of the chartModel and canvasBoundsContainer. * It also subscribes to the xChanged observable of the chartModel's scaleModel and filters the values to check * if the previous viewport had no-candles area and current viewport contains only candles or if the current viewport * has no-candles area. If the navigationMap component is visible, it makes visual candles and fires the draw event * of the canvasModel. */ doActivate() { super.doActivate(); this.addRxSubscription(merge(this.chartModel.observeCandlesChanged(), this.canvasBoundsContainer.observeBoundsChanged(CanvasElement.N_MAP), this.chartModel.scale.xChanged.pipe(pairwise(), filter(([prevScale, curScale]) => { // TODO rework const itemsCount = 0; //this.chartModel.scale.getItemsCount(); const prev = prevScale.start < 0 || prevScale.end > itemsCount; const cur = curScale.start < 0 || curScale.end > itemsCount; // trigger recalculation visual candles for nav map if previous viewport had // no-candles area and current viewport contains only candles. // OR if current viewport has no-candles area. return (prev && !cur) || cur; }))).subscribe(() => { if (this.config.components.navigationMap.visible) { this.visualCandles = this.makeVisualCandles(); this.canvasModel.fireDraw(); } })); } /** * This function generates an array of visual candles based on the data provided by the chartModel. * It calculates the maximum and minimum values of the candles and maps them to the canvas bounds. * @returns {Array<[number, number]>} An array of tuples containing the x and y coordinates of each visual candle. */ makeVisualCandles() { var _a; const candles = this.chartModel.getCandles(); if (!candles.length) { return []; } const firstId = this.chartModel.mainCandleSeries.dataIdxStart; const lastId = this.chartModel.mainCandleSeries.dataIdxEnd; const leftSideOffsetVisible = Math.round(Math.max(-firstId, 0)); // take into account left offset and a new rule using which we can scroll to right, so only two candles on left are visible const len = Math.max(this.chartModel.getCandlesCountWithRightOffset(), lastId) + leftSideOffsetVisible; let max = Number.NEGATIVE_INFINITY; let min = Number.POSITIVE_INFINITY; const nMapChart = this.canvasBoundsContainer.getBounds(CanvasElement.N_MAP_CHART); const width = nMapChart.width; const res = []; let candleClose = 0; let x; let idx; for (x = 0; x < width; x++) { idx = floor((x * len) / width) - leftSideOffsetVisible; if (idx in candles) { res[x] = candles[idx].close; candleClose = (_a = res[x]) !== null && _a !== void 0 ? _a : 0; max = Math.max(max, candleClose); min = Math.min(min, candleClose); } else { res[x] = 0; } } max -= min; return res.map((y, x) => { return [x + nMapChart.x, ((max + min - y) * nMapChart.height) / max + nMapChart.y]; }); } /** * Sets the visibility of the navigation map component. * @param {boolean} visible - Whether the navigation map component should be visible or not. Default is true. */ setVisible(visible = true) { var _a; if ((_a = this.config.components) === null || _a === void 0 ? void 0 : _a.navigationMap) { this.config.components.navigationMap.visible = visible; this.eventBus.fire(EVENT_RESIZED); this.canvasModel.fireDraw(); } } }