UNPKG

@inweb/viewer-visualize

Version:

JavaScript library for rendering CAD and BIM files in a browser using VisualizeJS

285 lines (242 loc) 11.3 kB
/////////////////////////////////////////////////////////////////////////////// // 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 * as utils from "./MeasureUtils"; export class MeasureLineItem { protected htmlElemStartPoint: HTMLElement; protected htmlElemEndPoint: HTMLElement; protected htmlElemLine: HTMLElement; protected htmlElemTitle: HTMLElement; protected startPoint: number[]; protected endPoint: number[]; protected scale: number; protected unit: string; protected precision: any; protected size: number; protected style: CSSStyleDeclaration; protected viewer: any; protected moduleInstance: any; protected targetElement: HTMLElement; protected isFinishDraw: boolean; public lineThickness: number; constructor(targetElement: HTMLElement, viewer: any, moduleInstance: any) { this.htmlElemStartPoint = null; this.htmlElemEndPoint = null; this.htmlElemLine = null; this.htmlElemTitle = null; this.startPoint = null; this.endPoint = null; this.scale = 1.0; this.unit = ""; this.precision = 2; this.size = 10.0; this.lineThickness = 2; this.style = { border: "2px solid #FFFFFF", background: "#009bff", color: "white", boxShadow: "0 0 10px rgba(0,0,0,0.5)", } as CSSStyleDeclaration; this.htmlElemStartPoint = utils.createHtmlElementIfNeed(this.htmlElemStartPoint, targetElement, "ruler-start"); this.htmlElemEndPoint = utils.createHtmlElementIfNeed(this.htmlElemEndPoint, targetElement, "ruler-end"); this.htmlElemLine = utils.createHtmlElementIfNeed(this.htmlElemLine, targetElement, "ruler-line"); this.htmlElemTitle = utils.createHtmlElementIfNeed(this.htmlElemTitle, targetElement, "ruler-value"); this.viewer = viewer; this.moduleInstance = moduleInstance; this.targetElement = targetElement; this.isFinishDraw = false; } drawMeasureLine(): void { const pointSize = this.size; const rect = this.moduleInstance.canvas.getBoundingClientRect(); // draw start point if (this.startPoint) { this.htmlElemStartPoint = utils.createHtmlElementIfNeed( this.htmlElemStartPoint, this.targetElement, "ruler-start" ); const pScreenStart = utils.worldToScreen(this.startPoint, this.moduleInstance, this.viewer); if (utils.isInsideRect(pScreenStart, rect.width, rect.height)) { this.htmlElemStartPoint.style.display = "block"; this.htmlElemStartPoint.style.cursor = "pointer"; this.htmlElemStartPoint.style.position = "absolute"; this.htmlElemStartPoint.style.top = `${pScreenStart.y - pointSize / 2}px`; this.htmlElemStartPoint.style.left = `${pScreenStart.x - pointSize / 2}px`; this.htmlElemStartPoint.style.borderRadius = `${pointSize}px`; this.htmlElemStartPoint.style.border = this.style.border; this.htmlElemStartPoint.style.background = this.style.background; this.htmlElemStartPoint.style.zIndex = "2"; this.htmlElemStartPoint.style.width = `${pointSize}px`; this.htmlElemStartPoint.style.height = `${pointSize}px`; this.htmlElemStartPoint.style.boxShadow = this.style.boxShadow; } else { this.htmlElemStartPoint.style.display = "none"; } } // draw end point if (this.endPoint && this.isFinishDraw) { this.htmlElemEndPoint = utils.createHtmlElementIfNeed(this.htmlElemEndPoint, this.targetElement, "ruler-end"); const pScreenEnd = utils.worldToScreen(this.endPoint, this.moduleInstance, this.viewer); if (utils.isInsideRect(pScreenEnd, rect.width, rect.height)) { this.htmlElemEndPoint.style.display = "block"; this.htmlElemEndPoint.style.cursor = "pointer"; this.htmlElemEndPoint.style.position = "absolute"; this.htmlElemEndPoint.style.top = `${pScreenEnd.y - pointSize / 2}px`; this.htmlElemEndPoint.style.left = `${pScreenEnd.x - pointSize / 2}px`; this.htmlElemEndPoint.style.borderRadius = `${pointSize}px`; this.htmlElemEndPoint.style.border = this.style.border; this.htmlElemEndPoint.style.background = this.style.background; this.htmlElemEndPoint.style.zIndex = "2"; this.htmlElemEndPoint.style.width = `${pointSize}px`; this.htmlElemEndPoint.style.height = `${pointSize}px`; this.htmlElemEndPoint.style.boxShadow = this.style.boxShadow; } else { this.htmlElemEndPoint.style.display = "none"; } } if (this.endPoint && this.startPoint) { const point1 = utils.worldToScreen(this.startPoint, this.moduleInstance, this.viewer); const point2 = utils.worldToScreen(this.endPoint, this.moduleInstance, this.viewer); const { p1, p2, angle, width } = utils.getDataForDrawLineWithFixed(point1, point2, rect.width, rect.height); const dx = p2.x - p1.x; const dy = p2.y - p1.y; const height = this.lineThickness; if (utils.isInsideRect(p1, rect.width, rect.height) && utils.isInsideRect(p2, rect.width, rect.height)) { this.htmlElemLine = utils.createHtmlElementIfNeed(this.htmlElemLine, this.targetElement, "ruler-line"); this.htmlElemLine.style.display = "block"; this.htmlElemLine.style.cursor = "pointer"; this.htmlElemLine.style.position = "absolute"; this.htmlElemLine.style.top = `${p1.y}px`; this.htmlElemLine.style.left = `${p1.x}px`; this.htmlElemLine.style.width = `${width}px`; this.htmlElemLine.style.transform = `rotate(${angle}deg)`; this.htmlElemLine.style.transformOrigin = `0px ${height / 2}px`; this.htmlElemLine.style.boxShadow = this.style.boxShadow; this.htmlElemLine.style.border = "none"; this.htmlElemLine.style.background = this.style.background; this.htmlElemLine.style.zIndex = "1"; this.htmlElemLine.style.height = `${height}px`; const distance = this.getDistance(); const pX = p1.x + dx / 2; const pY = p1.y + dy / 2; this.htmlElemTitle = utils.createHtmlElementIfNeed(this.htmlElemTitle, this.targetElement, "ruler-value"); this.htmlElemTitle.style.display = "block"; this.htmlElemTitle.style.cursor = "pointer"; this.htmlElemTitle.style.font = "10px"; this.htmlElemTitle.style.color = "white"; this.htmlElemTitle.style.position = "Absolute"; this.htmlElemTitle.style.top = `${pY}px`; this.htmlElemTitle.style.left = `${pX}px`; this.htmlElemTitle.style.transform = "translate(-50%, -50%)"; this.htmlElemTitle.style.borderRadius = "5px"; this.htmlElemTitle.style.boxShadow = this.style.boxShadow; this.htmlElemTitle.style.border = "none"; this.htmlElemTitle.style.background = this.style.background; this.htmlElemTitle.style.zIndex = "3"; this.htmlElemTitle.style.padding = "2px"; this.htmlElemTitle.style.textAlign = "center"; this.htmlElemTitle.innerHTML = this.formatDistance(distance); } else { this.htmlElemLine.style.display = "none"; this.htmlElemTitle.style.display = "none"; } } } getDistance(): number { let distance = utils.getDistance(this.startPoint, this.endPoint, this.moduleInstance); if (Math.abs(this.scale) > 1e-10) distance /= this.scale; return distance; } calculatePrecision(value: number) { const distance = Math.abs(value); if (distance >= 1000) return 0; if (distance >= 10) return 1; if (distance >= 0.1) return 2; if (distance >= 0.001) return 3; return distance > 0 ? Math.floor(-Math.log10(distance)) + 1 : 2; } formatDistance(distance: number): string { let digits: number; if (this.precision === "Auto") digits = this.calculatePrecision(distance); else if (Number.isFinite(this.precision)) digits = this.precision; else digits = parseFloat(this.precision); if (!Number.isFinite(digits)) digits = 2; else if (digits < 0) digits = 0; else if (digits > 10) digits = 10; let result = distance.toFixed(digits); if (this.precision === "Auto") result = result.replace(/\.0+$/, "").replace(/\.$/, ""); if (+result !== distance) result = "~ " + result; return `${result} ${this.unit}`; } setStartPoint(gePoint: number[]): void { this.startPoint = gePoint; this.drawMeasureLine(); } setEndPoint(gePoint: number[], isFinish: boolean): void { this.isFinishDraw = isFinish === undefined ? true : isFinish; this.endPoint = gePoint; this.drawMeasureLine(); } update(): void { this.drawMeasureLine(); } setSize(size: number): void { this.size = size; this.drawMeasureLine(); } clear(): void { this.endPoint = null; this.startPoint = null; this.htmlElemStartPoint = utils.destroyHtmlElement(this.htmlElemStartPoint, this.targetElement); this.htmlElemEndPoint = utils.destroyHtmlElement(this.htmlElemEndPoint, this.targetElement); this.htmlElemLine = utils.destroyHtmlElement(this.htmlElemLine, this.targetElement); this.htmlElemTitle = utils.destroyHtmlElement(this.htmlElemTitle, this.targetElement); } setUnit(unit: string): void { this.unit = unit; this.drawMeasureLine(); } setConversionFactor(scale: number): void { this.scale = scale; this.drawMeasureLine(); } setPrecision(precision: any): void { this.precision = precision; this.drawMeasureLine(); } setStyle(style: CSSStyleDeclaration): void { this.style = style; this.drawMeasureLine(); } setSelectionReactor(reactor: any): void { utils.onSetCallback(this.htmlElemStartPoint, reactor ? reactor.onStartPoint : null); utils.onSetCallback(this.htmlElemEndPoint, reactor ? reactor.onEndPoint : null); utils.onSetCallback(this.htmlElemTitle, reactor ? reactor.onTitle : null); } setSelectability(enable: boolean): void { utils.onSetSelectivity(this.htmlElemStartPoint, enable); utils.onSetSelectivity(this.htmlElemEndPoint, enable); utils.onSetSelectivity(this.htmlElemLine, enable); utils.onSetSelectivity(this.htmlElemTitle, enable); } }