devexpress-gantt
Version:
DevExpress Gantt Control
99 lines (91 loc) • 4.36 kB
text/typescript
import { Point } from "@devexpress/utils/lib/geometry/point";
import { EvtUtils } from "@devexpress/utils/lib/utils/evt";
import { Metrics } from "@devexpress/utils/lib/geometry/metrics";
import { TaskAreaStateBase } from "./TaskAreaStateBase";
import { TaskAreaStateEventNames } from "./TaskAreaStateEventNames";
const PINCH_CHANGE_DISTANCE = 3;
const MOUSE_ZOOM_LOCK_TIMEOUT = 50;
const TOUCH_ZOOM_LOCK_TIMEOUT = 1000;
export class TaskAreaZoomState extends TaskAreaStateBase {
private _isInZooming = false;
private prevDistance: number;
public onMouseWheel(evt: WheelEvent): void {
if(evt.ctrlKey) {
evt.preventDefault();
evt.stopPropagation();
if(!this._isInZooming)
this.processZoom(evt, EvtUtils.getWheelDelta(evt) > 0, MOUSE_ZOOM_LOCK_TIMEOUT);
}
}
protected onDocumentPointerUpInternal(evt: PointerEvent): void { this.onEndZoom(evt); }
protected onDocumentPointerMoveInternal(evt: PointerEvent): void { this.onTouchZoom(evt); }
protected onTouchEndInternal(evt: TouchEvent): void { this.onEndZoom(evt); }
protected onTouchMoveInternal(evt: TouchEvent): void { this.onTouchZoom(evt); }
protected onTouchZoom(evt: TouchEvent | PointerEvent): void {
evt.stopPropagation();
evt.preventDefault();
if(!this._isInZooming) {
const distance = this.getTouchDistance(evt);
this.prevDistance ??= distance;
const diff = this.prevDistance - distance;
if(Math.abs(diff) > PINCH_CHANGE_DISTANCE) {
this.processZoom(evt, diff > 0, TOUCH_ZOOM_LOCK_TIMEOUT);
this.prevDistance = distance;
}
}
}
protected processZoom(evt: Event, increase: boolean, lockTimeout: number): void {
this._isInZooming = true;
setTimeout(() => { this._isInZooming = false; }, lockTimeout);
const eventKey = increase ? TaskAreaStateEventNames.TASK_AREA_ZOOM_IN : TaskAreaStateEventNames.TASK_AREA_ZOOM_OUT;
this.raiseEvent(eventKey, evt, null, { leftPos: this.getLeftPosition(evt) });
}
protected onEndZoom(evt: Event): void {
this.prevDistance = null;
this.raiseEvent(TaskAreaStateEventNames.STATE_EXIT, evt);
}
private getTouchDistance(evt: TouchEvent | PointerEvent) {
const points = this.GetTouchPoints(evt);
return this.getDistance(points[0], points[1]);
}
private GetTouchPoints(evt: Event): Point[] {
if(this.isTouchEvent(evt)) {
const touches = (evt as TouchEvent).touches;
return [
new Point(touches[0].pageX, touches[0].pageY),
new Point(touches[1].pageX, touches[1].pageY)
];
}
const pointers = this.raiseEvent(TaskAreaStateEventNames.GET_POINTERS_INFO, evt);
return [
new Point(pointers[0]?.pageX, pointers[0]?.pageY),
new Point(pointers[1]?.pageX, pointers[1]?.pageY)
];
}
private getDistance(a: Point, b: Point): number {
return Metrics.euclideanDistance(a, b);
}
protected getLeftPosition(evt: Event): number {
let leftPos = 0;
if(this.isTouchEvent(evt) || this.isPointerEvent(evt))
leftPos = this.getZoomMiddlePoint(evt).x;
else if(this.isMouseEvent(evt))
leftPos = this.getMouseZoomLeftPos(<MouseEvent>evt);
return leftPos;
}
private getMouseZoomLeftPos(evt: MouseEvent): number {
const ref = this.raiseEvent(TaskAreaStateEventNames.GET_COORDINATES_REF_POINT) as Point;
return EvtUtils.getEventX(evt) - ref.x;
}
private getZoomMiddlePoint(evt: Event): Point {
const ref = this.raiseEvent(TaskAreaStateEventNames.GET_COORDINATES_REF_POINT) as Point;
const points = this.GetTouchPoints(evt);
const point1 = this.convertScreenToChartCoordinates(points[0], ref);
const point2 = this.convertScreenToChartCoordinates(points[1], ref);
return new Point(
(point1.x + point2.x) / 2,
(point1.y + point2.y) / 2
);
}
private convertScreenToChartCoordinates(p: Point, ref: Point): Point { return new Point(p.x - ref.x, p.y - ref.y); }
}