UNPKG

@devexperts/dxcharts-lite

Version:
118 lines (117 loc) 6.12 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 { ChartBaseElement } from '../../model/chart-base-element'; import { CanvasElement } from '../../canvas/canvas-bounds-container'; import { DragNDropXComponent } from '../dran-n-drop_helper/drag-n-drop-x.component'; // if you drag full X width from left to right - you will have x3 zoom, and vice-versa const FULL_X_WIDTH_ZOOM_FACTOR = 3; /** * Handles the mouse drag on X axis - to zoom the viewport horizontally. * @doc-tags scaling,zoom,viewport */ export class XAxisScaleHandler extends ChartBaseElement { constructor(scale, canvasInputListener, canvasBoundsContainer, chartPanComponent, chartModel, hitTest, hitTestCanvasModel) { super(); this.scale = scale; this.canvasInputListener = canvasInputListener; this.canvasBoundsContainer = canvasBoundsContainer; this.chartPanComponent = chartPanComponent; this.chartModel = chartModel; this.hitTest = hitTest; this.hitTestCanvasModel = hitTestCanvasModel; this.lastXStart = 0; this.lastXEnd = 0; this.lastXWidth = 0; this.lastXPxWidth = 0; this.onXDragStart = () => { this.lastXStart = this.scale.xStart; this.lastXEnd = this.scale.xEnd; this.lastXWidth = this.scale.xEnd - this.scale.xStart; const bounds = this.canvasBoundsContainer.getBounds(CanvasElement.X_AXIS); this.lastXPxWidth = bounds.width - this.canvasInputListener.currentPoint.x; // Stop redrawing hit test this.hitTestCanvasModel.hitTestDrawersPredicateSubject.next(false); }; this.onXDragTick = (dragInfo) => { let { delta: absoluteXDelta } = dragInfo; // mouse click or single tap drag if (!this.touches || this.touches.length === 1) { const newPxWidth = this.lastXPxWidth - absoluteXDelta; // cursor goes beyond x-axis - maximum scale is reached if (newPxWidth < 0) { return; } const xZoomMult = this.lastXPxWidth / newPxWidth; const newWidth = this.lastXWidth * xZoomMult; const newXStart = this.lastXStart + (this.lastXWidth - newWidth); this.scale.setXScale(newXStart, this.scale.xEnd); return; } // if multitouch - take the first two touch events and apply delta the following way: // the touch on the left keeps the initial delta because left => right gesture // the touch on the right has the reversed delta because the gesture is right => left if (this.touches.length > 1) { const left = Math.min(this.touches[0].clientX, this.touches[1].clientX); absoluteXDelta = left === this.touches[0].clientX ? absoluteXDelta : -absoluteXDelta; let xZoomMult; if (absoluteXDelta < 0) { xZoomMult = 1 / (1 + (-absoluteXDelta / this.lastXPxWidth) * (FULL_X_WIDTH_ZOOM_FACTOR - 1)); } else { xZoomMult = 1 + (absoluteXDelta / this.lastXPxWidth) * (FULL_X_WIDTH_ZOOM_FACTOR - 1); } const newXWidth = this.lastXWidth * xZoomMult; const delta = (newXWidth - this.lastXWidth) / 2; const newXStart = this.lastXStart - delta; const newXEnd = this.lastXEnd + delta; if (this.lastXStart !== newXStart || this.lastXEnd !== newXEnd) { this.scale.setXScale(newXStart, newXEnd); } } }; this.onXDragEnd = () => { // Continue redrawing hit test this.hitTestCanvasModel.hitTestDrawersPredicateSubject.next(true); }; this.setDblTapCallback = (cb) => (this.dblTapCallback = cb); this.setDblClickCallback = (cb) => (this.dblClickCallback = cb); this.dblClickCallback = () => chartModel.doBasicScale(); this.dblTapCallback = () => chartModel.doBasicScale(); const dragNDropXComponent = new DragNDropXComponent(hitTest, { onDragStart: this.onXDragStart, onDragTick: this.onXDragTick, onDragEnd: this.onXDragEnd, }, this.canvasInputListener, this.chartPanComponent, { dragPredicate: () => chartPanComponent.chartAreaPanHandler.chartPanningOptions.horizontal, }); this.addChildEntity(dragNDropXComponent); } /** * This method is used to activate the canvas input listener and add a subscription to it. * It calls the parent class's doActivate method and then subscribes to the canvasInputListener's observeDbClick method. * The subscription is added to the RxJS subscription list. * When the subscription is triggered, the doBasicScale method is called. * @protected * @returns {void} */ doActivate() { super.doActivate(); this.addRxSubscription(this.canvasInputListener.observeDbClick(this.hitTest).subscribe(() => this.dblClickCallback())); this.addRxSubscription(this.canvasInputListener.observeDbTap(this.hitTest).subscribe(() => { var _a; // apply dbl tap only if single finger taps are made if (this.touches && ((_a = this.touches) === null || _a === void 0 ? void 0 : _a.length) > 1) { this.touches = undefined; return; } this.dblTapCallback(); })); this.addRxSubscription(this.canvasInputListener.observeTouchStart(this.hitTest).subscribe(e => { this.touches = e.touches; })); this.addRxSubscription(this.chartModel.candlesPrependSubject.subscribe(({ prependedCandlesWidth }) => (this.lastXStart += prependedCandlesWidth))); } }