@inweb/viewer-visualize
Version:
JavaScript library for rendering CAD and BIM files in a browser using VisualizeJS
255 lines (204 loc) • 7.63 kB
text/typescript
///////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
// All rights reserved.
//
// This software and its documentation and related materials are owned by
// the Alliance. The software may only be incorporated into application
// programs owned by members of the Alliance, subject to a signed
// Membership Agreement and Supplemental Software License Agreement with the
// Alliance. The structure and organization of this software are the valuable
// trade secrets of the Alliance and its suppliers. The software is also
// protected by copyright law and international treaty provisions. Application
// programs incorporating this software must include the following statement
// with their copyright notices:
//
// This application incorporates Open Design Alliance software pursuant to a
// license agreement with Open Design Alliance.
// Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
// All rights reserved.
//
// By use of this software, its documentation or related materials, you
// acknowledge and accept the above terms.
///////////////////////////////////////////////////////////////////////////////
/* eslint-disable no-unused-vars */
import { CANVAS_EVENTS } from "@inweb/viewer-core";
import { Viewer } from "../../Viewer";
import { Point2d } from "./Geometry";
import { OdaGeAction } from "./OdaGeAction";
const CLICK_DELTA = 5;
const INTERACTIVITY_FPS = 24;
export class OdBaseDragger extends OdaGeAction {
protected subject: Viewer;
protected needInputText: boolean;
protected mouseDownPosition: Point2d;
protected autoSelect: boolean;
protected onmessage: (event: any) => boolean;
protected canvasEvents: string[];
protected isDragging: boolean;
protected press: boolean;
public name: string;
constructor(subject: Viewer) {
super(subject.visualizeJs);
this.subject = subject;
this.needInputText = false;
this.mouseDownPosition = { x: 0, y: 0 };
this.autoSelect = false;
this.onmessage = (event) => this.subject.emitEvent(event);
this.canvasEvents = CANVAS_EVENTS;
}
public initialize(): void {
this.canvasEvents = this.canvasEvents.filter((x) => typeof this[x] === "function");
this.canvasEvents.forEach((x) => (this[x] = this[x].bind(this)));
this.canvasEvents.forEach((x) => this.subject.on(x, this[x]));
this.getViewer().setEnableAutoSelect(!!this.autoSelect);
}
public dispose(): void {
this.canvasEvents.forEach((x) => this.subject.off(x, this[x]));
}
protected relativeCoords(event: MouseEvent): Point2d {
return { x: event.offsetX * window.devicePixelRatio, y: event.offsetY * window.devicePixelRatio };
}
protected pointerdown(ev: PointerEvent): void {
if (!ev.isPrimary || OdBaseDragger.isGestureActive) {
return;
}
(ev.target as HTMLElement).setPointerCapture(ev.pointerId);
const relCoord = this.relativeCoords(ev);
this.isDragging = true;
this.mouseDownPosition = { x: relCoord.x, y: relCoord.y };
this.start(relCoord.x, relCoord.y, ev.clientX, ev.clientY);
this.subject.update();
}
protected pointerup(ev: PointerEvent): void {
if (OdBaseDragger.needSkipPointerUp) {
return;
}
if (!ev.isPrimary) {
return;
}
(ev.target as HTMLElement).releasePointerCapture(ev.pointerId);
const relCoord = this.relativeCoords(ev);
this.end(relCoord.x, relCoord.y, ev.clientX, ev.clientY);
this.isDragging = false;
this.subject.update();
}
protected pointercancel(ev: PointerEvent): void {
if (!ev.isPrimary) {
return;
}
this.m_module.canvas.dispatchEvent(new PointerEvent("pointerup", ev));
}
protected pointermove(ev: PointerEvent): void {
if (!ev.isPrimary || OdBaseDragger.isGestureActive) {
return;
}
const relCoord = this.relativeCoords(ev);
this.drag(relCoord.x, relCoord.y, ev.clientX, ev.clientY);
if (this.isDragging) {
this.subject.update();
}
}
protected click(ev: MouseEvent): void {
const viewer = this.getViewer();
const relCoord = this.relativeCoords(ev);
const x = relCoord.x;
const y = relCoord.y;
const isNotDragging =
Math.abs(x - this.mouseDownPosition.x) < CLICK_DELTA && Math.abs(y - this.mouseDownPosition.y) < CLICK_DELTA;
if (viewer && viewer.getEnableAutoSelect() && isNotDragging) {
viewer.unselect();
viewer.select(x, y, x, y);
this.subject.update();
const selectionSet = viewer.getSelected();
const handles = this.subject.getSelected();
this.onmessage({ type: "select", data: selectionSet, handles });
}
}
protected dblclick(ev: MouseEvent): void {
const viewer = this.getViewer();
const relCoord = this.relativeCoords(ev);
const x = relCoord.x;
const y = relCoord.y;
const device = viewer.getActiveDevice();
const clickView = device.viewAt([x, y]);
if (clickView && !clickView.active) {
viewer.activeView = clickView;
clickView.delete();
this.subject.update();
} else {
if (viewer && viewer.getEnableAutoSelect()) {
const pSelected = viewer.getSelected();
if (!pSelected.isNull() && pSelected.numItems() !== 0) {
const itr = pSelected.getIterator();
const entity = itr.getEntity();
viewer.zoomToEntity(entity);
this.onmessage({ type: "zoomtoentity", data: entity });
this.subject.update();
this.deleteAll([itr, entity]);
}
}
}
device.delete();
}
protected start(x: number, y: number, absoluteX = 0, absoluteY = 0): void {}
protected drag(x: number, y: number, absoluteX = 0, absoluteY = 0): void {}
protected end(x: number, y: number, absoluteX = 0, absoluteY = 0): void {}
protected beginInteractivity = () => {
const viewer = this.getViewer();
const view = viewer.activeView;
if (view["beginInteractivity"]) {
view.beginInteractivity(INTERACTIVITY_FPS);
this.subject.update();
}
view.delete();
};
protected endInteractivity = () => {
const viewer = this.getViewer();
const view = viewer.activeView;
if (view["endInteractivity"]) {
view.endInteractivity();
const device = this.getViewer().getActiveDevice();
const canvas = this.m_module.canvas;
device.invalidate([0, 0, canvas.width, canvas.height]);
device.delete();
this.subject.update();
}
view.delete();
};
protected getActiveMarkupEntity(entityName: string): any {
return this.subject.addMarkupEntity(entityName);
}
private syncOverlayView(): any {
return this.subject.syncOverlay();
}
protected deleteAll(objects): void {
for (const obj of objects) {
obj?.delete?.();
}
}
public updatePreview(): void {}
private static _isGestureActive = false;
protected static set isGestureActive(value: boolean) {
if (OdBaseDragger._isGestureActive === value) {
return;
}
OdBaseDragger._isGestureActive = value;
if (OdBaseDragger._isGestureActive) {
OdBaseDragger.needSkipPointerUp = true;
}
}
protected static get isGestureActive() {
return OdBaseDragger._isGestureActive;
}
private static _needSkipPointerUp = false;
private static get needSkipPointerUp() {
if (OdBaseDragger._needSkipPointerUp) {
OdBaseDragger.needSkipPointerUp = false;
return true;
}
return false;
}
private static set needSkipPointerUp(value: boolean) {
OdBaseDragger._needSkipPointerUp = value;
}
}