@devexperts/dxcharts-lite
Version:
121 lines (120 loc) • 5.71 kB
JavaScript
/*
* 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, DEFAULT_MIN_PANE_HEIGHT, } from '../../canvas/canvas-bounds-container';
import { ChartBaseElement } from '../../model/chart-base-element';
import { DragNDropYComponent } from '../dran-n-drop_helper/drag-n-drop-y.component';
// if you drag full Y height from top to bottom - you will have x3 zoom, and vice-versa
const FULL_Y_HEIGHT_ZOOM_FACTOR = 10;
/**
* Handles the mouse drag on Y axis - to zoom the viewport vertically.
* @doc-tags scaling,zoom,viewport
*/
export class YAxisScaleHandler extends ChartBaseElement {
constructor(bus, config, panning, scale, canvasInputListener, bounds, hitTest, hitTestCanvasModel) {
super();
this.bus = bus;
this.config = config;
this.scale = scale;
this.canvasInputListener = canvasInputListener;
this.bounds = bounds;
this.hitTest = hitTest;
this.hitTestCanvasModel = hitTestCanvasModel;
this.yAxisDragEndSubject = new Subject();
this.lastYStart = 0;
this.lastYEnd = 0;
this.lastYHeight = 0;
this.lastYPxHeight = 0;
this.onYDragStart = () => {
// halt previous scale animation if drag is started
this.scale.haltAnimation();
this.lastYStart = this.scale.yStart;
this.lastYEnd = this.scale.yEnd;
this.lastYHeight = this.scale.yEnd - this.scale.yStart;
this.lastYPxHeight = Math.max(this.bounds.getBounds(CanvasElement.Y_AXIS).height, DEFAULT_MIN_PANE_HEIGHT);
// Stop redrawing hit test
this.hitTestCanvasModel.hitTestDrawersPredicateSubject.next(false);
};
this.onYDragTick = (dragInfo) => {
let { delta: absoluteYDelta } = dragInfo;
// check how many touch events are at the axis
// if multitouch - take the first two and apply delta the following way:
// the touch above keeps the initial delta because top => bottom gesture
// the touch below has the reversed delta because the gesture is bottom => top
if (this.touches && this.touches.length > 1) {
const top = Math.min(this.touches[0].clientY, this.touches[1].clientY);
absoluteYDelta = top === this.touches[0].clientY ? absoluteYDelta : -absoluteYDelta;
}
// 1/3..3
let zoomYMult;
if (absoluteYDelta < 0) {
// 1/3..1
zoomYMult = 1 / (1 + (-absoluteYDelta / this.lastYPxHeight) * (FULL_Y_HEIGHT_ZOOM_FACTOR - 1));
}
else {
// 1..3
zoomYMult = 1 + (absoluteYDelta / this.lastYPxHeight) * (FULL_Y_HEIGHT_ZOOM_FACTOR - 1);
}
const newYHeight = this.lastYHeight * zoomYMult;
const delta = (newYHeight - this.lastYHeight) / 2;
const newYStart = this.lastYStart - delta;
const newYEnd = this.lastYEnd + delta;
if (this.lastYStart !== newYStart || this.lastYEnd !== newYEnd) {
this.scale.setYScale(newYStart, newYEnd);
this.scale.state.auto = false;
this.bus.fireDraw();
}
};
this.onYDragEnd = () => {
this.yAxisDragEndSubject.next();
// Continue redrawing hit test
this.hitTestCanvasModel.hitTestDrawersPredicateSubject.next(true);
};
this.setDblTapCallback = (cb) => (this.dblTapCallback = cb);
this.setDblClickCallback = (cb) => (this.dblClickCallback = cb);
this.dblClickCallback = () => scale.autoScale(true);
this.dblTapCallback = () => scale.autoScale(true);
// drag to Y-scale and double click to auto scale
if (config.customScale) {
const dragNDropYComponent = new DragNDropYComponent(hitTest, {
onDragTick: this.onYDragTick,
onDragStart: this.onYDragStart,
onDragEnd: this.onYDragEnd,
}, canvasInputListener, panning, {
dragPredicate: () => panning.chartAreaPanHandler.chartPanningOptions.vertical && config.type !== 'percent',
});
this.addChildEntity(dragNDropYComponent);
this.dragNDropYComponent = dragNDropYComponent;
}
}
isDragging() {
if (!this.dragNDropYComponent) {
return false;
}
return Math.abs(this.dragNDropYComponent.draggedPixels) > 0;
}
doActivate() {
if (this.config.customScaleDblClick) {
this.addRxSubscription(this.canvasInputListener.observeDbClick(this.hitTest).subscribe(() => {
this.dblClickCallback();
this.bus.fireDraw();
}));
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.bus.fireDraw();
}));
this.addRxSubscription(this.canvasInputListener.observeTouchStart(this.hitTest).subscribe(e => {
this.touches = e.touches;
}));
}
}
}