@inweb/viewer-visualize
Version:
JavaScript library for rendering CAD and BIM files in a browser using VisualizeJS
290 lines (251 loc) • 9.18 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.
///////////////////////////////////////////////////////////////////////////////
import { Viewer } from "../../Viewer";
import { OdBaseDragger } from "../Common/OdBaseDragger";
import { MeasureLineItem } from "./MeasureLineItem";
import { IOptions } from "@inweb/viewer-core";
function renameUnit(table, unit) {
return table[unit] || unit;
}
export class MeasureLineDragger extends OdBaseDragger {
protected lineThickness: number;
protected gripingRadius: number;
protected firstPoint: number[];
protected secondPoint: number[];
protected items: MeasureLineItem[];
protected m_overlayElement: HTMLElement;
protected previewMeasureLine: MeasureLineItem;
protected conversionFactor: number;
protected rulerUnitTable: any;
protected rulerUnit: string;
protected rulerPrecision: any;
constructor(subject: Viewer) {
super(subject);
this.lineThickness = 2;
this.press = false;
this.gripingRadius = 5.0;
this.firstPoint = null;
this.secondPoint = null;
this.rulerUnitTable = {
Millimeters: "mm",
Centimeters: "cm",
Meters: "m",
Feet: "ft",
Inches: "in",
Yards: "yd",
Kilometers: "km",
Miles: "mi",
Micrometers: "µm",
Mils: "mil",
MicroInches: "µin",
Default: "unit",
};
this.rulerUnit = subject.options.rulerUnit ?? "Default";
this.rulerPrecision = subject.options.rulerPrecision ?? "Default";
this.items = [];
this.canvasEvents.push("resize", "optionsChange");
}
override initialize(): void {
super.initialize();
this.m_overlayElement = document.createElement("div");
this.m_overlayElement.style.background = "rgba(0,0,0,0)";
this.m_overlayElement.style.position = "fixed";
this.m_overlayElement.style.zIndex = "1";
this.m_overlayElement.style.pointerEvents = "none";
document.body.appendChild(this.m_overlayElement);
this.subject.addEventListener("optionschange", this.optionsChange);
this.resize();
}
override dispose(): void {
super.dispose();
this.m_overlayElement.remove();
this.subject.removeEventListener("optionschange", this.optionsChange);
}
override updatePreview(): void {
this.items.forEach((item) => item.update());
}
resize(): void {
const rect = this.m_module.canvas.getBoundingClientRect();
this.m_overlayElement.style.top = `${rect.top}px`;
this.m_overlayElement.style.left = `${rect.left}px`;
this.m_overlayElement.style.width = `${rect.width}px`;
this.m_overlayElement.style.height = `${rect.height}px`;
}
getSnapPointRadius(): number {
const view = this.getViewer().activeView;
const corners = view.viewDcCorners();
const pt1 = corners.lowerLeft;
const pt2 = corners.upperRight;
pt2[0] -= pt1[0];
pt2[1] -= pt1[1];
return Math.min(pt2[0], pt2[1]) / 120;
}
override start(x: number, y: number): void {
this.createNewMeasureIfNeed();
const point = this.getViewer().getSnapPoint(x, y, this.gripingRadius);
if (point) {
this.firstPoint = point;
this.previewMeasureLine.setStartPoint(this.firstPoint);
}
}
override drag(x: number, y: number): void {
this.createNewMeasureIfNeed();
const point = this.getViewer().getSnapPoint(x, y, this.gripingRadius);
if (this.isDragging) {
if (point) {
if (this.firstPoint) {
this.secondPoint = point;
this.previewMeasureLine.setStartPoint(this.firstPoint);
this.previewMeasureLine.setEndPoint(this.secondPoint, true);
} else {
this.firstPoint = point;
this.previewMeasureLine.setStartPoint(this.firstPoint);
}
} else {
this.secondPoint = null;
this.previewMeasureLine.clear();
this.previewMeasureLine.setStartPoint(this.firstPoint);
this.previewMeasureLine.setEndPoint(this.getViewer().screenToWorld(x, y), false);
}
} else {
if (point) {
this.previewMeasureLine.setStartPoint(point);
} else {
this.previewMeasureLine.clear();
}
}
}
override end(): void {
if (this.firstPoint && this.secondPoint) {
const newLineMeasure = this.createMeasureLine();
newLineMeasure.setStartPoint(this.firstPoint);
newLineMeasure.setEndPoint(this.secondPoint, true);
}
this.firstPoint = null;
this.secondPoint = null;
this.previewMeasureLine.clear();
}
createNewMeasureIfNeed(): void {
if (!this.previewMeasureLine) {
this.previewMeasureLine = this.createMeasureLine();
}
}
createMeasureLine(): MeasureLineItem {
const viewer = this.m_module.getViewer();
const item = new MeasureLineItem(this.m_overlayElement, viewer, this.m_module);
item.lineThickness = this.lineThickness || item.lineThickness;
const isDefaultUnit = this.rulerUnit === "Default";
const isDefaultPrecision = this.rulerPrecision === "Default";
item.setUnit(renameUnit(this.rulerUnitTable, isDefaultUnit ? viewer.getUnit() : this.rulerUnit));
if (!isDefaultUnit) {
const fromUnit = this.getKUnitByName(viewer.getUnit());
const toUnit = this.getKUnitByName(this.subject.options.rulerUnit);
const multiplier = viewer.getUnitsConversionCoef(fromUnit, toUnit);
this.conversionFactor = 1 / multiplier;
item.setConversionFactor(this.conversionFactor);
} else {
item.setConversionFactor(1.0);
}
if (!isDefaultPrecision) {
item.setPrecision(this.rulerPrecision);
} else {
item.setPrecision(2);
}
this.items.push(item);
return item;
}
optionsChange(event): void {
const options: IOptions = event.data;
const toUnitName = options.rulerUnit ?? "Default";
const toPrecision = options.rulerPrecision ?? "Default";
const unitChanged = this.rulerUnit !== toUnitName;
const precisionChanged = this.rulerPrecision !== toPrecision;
if (!unitChanged && !precisionChanged) return;
this.rulerUnit = toUnitName;
this.rulerPrecision = toPrecision;
const drawingUnit = this.m_module.getViewer().getUnit();
const eToUnit = this.getKUnitByName(toUnitName);
const eFromUnit = this.getKUnitByName(drawingUnit);
this.items.forEach((item) => {
if (unitChanged) {
if (toUnitName === "Default") {
item.setUnit(renameUnit(this.rulerUnitTable, drawingUnit));
item.setConversionFactor(1.0);
} else {
item.setUnit(renameUnit(this.rulerUnitTable, toUnitName));
const multiplier = this.m_module.getViewer().getUnitsConversionCoef(eFromUnit, eToUnit);
this.conversionFactor = 1 / multiplier;
item.setConversionFactor(this.conversionFactor);
}
}
if (precisionChanged) {
if (toPrecision === "Default") {
item.setPrecision(2);
} else {
item.setPrecision(toPrecision);
}
}
});
}
getKUnitByName(unitName: string): any {
let eUnit = this.m_module.Units.kUserDefined;
switch (unitName) {
case "Millimeters":
eUnit = this.m_module.Units.kMillimeters;
break;
case "Centimeters":
eUnit = this.m_module.Units.kCentimeters;
break;
case "Meters":
eUnit = this.m_module.Units.kMeters;
break;
case "Feet":
eUnit = this.m_module.Units.kFeet;
break;
case "Inches":
eUnit = this.m_module.Units.kInches;
break;
case "Yards":
eUnit = this.m_module.Units.kYards;
break;
case "Kilometers":
eUnit = this.m_module.Units.kKilometers;
break;
case "Miles":
eUnit = this.m_module.Units.kMiles;
break;
case "Micrometers":
eUnit = this.m_module.Units.kMicrometers;
break;
case "Mils":
eUnit = this.m_module.Units.kMils;
break;
case "MicroInches":
eUnit = this.m_module.Units.kMicroInches;
break;
default:
break;
}
return eUnit;
}
}