UNPKG

@inweb/markup

Version:
232 lines (195 loc) 6.81 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 Konva from "konva"; import { IMarkupLine, IMarkupLineParams, MarkupLineType } from "../IMarkupLine"; import { IWorldTransform } from "../IWorldTransform"; import { WorldTransform } from "../WorldTransform"; const LineTypeSpecs = new Map<string, number[]>([ ["solid", []], ["dot", [30, 30, 0.001, 30]], ["dash", [30, 30]], ]); export class KonvaLine implements IMarkupLine { private _ref: Konva.Line; private _worldTransformer: IWorldTransform; constructor(params: IMarkupLineParams, ref = null, worldTransformer = new WorldTransform()) { this._worldTransformer = worldTransformer; if (ref) { this._ref = ref; let wcsPoints = this._ref.getAttr("wcsPoints"); if (!wcsPoints) { wcsPoints = []; let points = this._ref.points(); let wcsPoint; for (let i = 0; i < points.length; i += 2) { wcsPoint = this._worldTransformer.screenToWorld({ x: points[i], y: points[i + 1] }); wcsPoints.push({ x: wcsPoint.x, y: wcsPoint.y, z: wcsPoint.z }); } this._ref.setAttr("wcsPoints", wcsPoints); } return; } if (!params) params = {}; if (!params.points) params.points = [ { x: 0, y: 0 }, { x: 100, y: 100 }, ]; const konvaPoints = []; const wcsPoints = []; params.points.forEach((point) => { konvaPoints.push(point.x, point.y); let wcsPoint = this._worldTransformer.screenToWorld({ x: point.x, y: point.y }); wcsPoints.push({ x: wcsPoint.x, y: wcsPoint.y, z: wcsPoint.z }); }); this._ref = new Konva.Line({ stroke: params.color ?? "#ff0000", strokeWidth: params.width ?? 4, globalCompositeOperation: "source-over", lineCap: "round", lineJoin: "round", points: konvaPoints, draggable: true, strokeScaleEnabled: false, dash: LineTypeSpecs.get(params.type) || [], }); this._ref.setAttr("wcsPoints", wcsPoints); this._ref.on("transform", (e) => { const attrs = e.target.attrs; if (attrs.rotation !== this._ref.rotation()) this._ref.rotation(attrs.rotation); }); this._ref.on("transformend", (e) => { const absoluteTransform = this._ref.getAbsoluteTransform(); let wcsPoints = []; let points = this._ref.points(); let wcsPoint; for (let i = 0; i < points.length; i += 2) { const position = absoluteTransform.point({ x: points[i], y: points[i + 1] }); wcsPoint = this._worldTransformer.screenToWorld({ x: position.x, y: position.y }); wcsPoints.push({ x: wcsPoint.x, y: wcsPoint.y, z: wcsPoint.z }); } this._ref.setAttr("wcsPoints", wcsPoints); }); this._ref.on("dragend", (e) => { const absoluteTransform = this._ref.getAbsoluteTransform(); let wcsPoints = []; let points = this._ref.points(); let wcsPoint; for (let i = 0; i < points.length; i += 2) { const position = absoluteTransform.point({ x: points[i], y: points[i + 1] }); wcsPoint = this._worldTransformer.screenToWorld({ x: position.x, y: position.y }); wcsPoints.push({ x: wcsPoint.x, y: wcsPoint.y, z: wcsPoint.z }); } this._ref.setAttr("wcsPoints", wcsPoints); }); this._ref.id(this._ref._id.toString()); } ref() { return this._ref; } id(): string { return this._ref.id(); } enableMouseEditing(value: boolean): void { this._ref.draggable(value); } type(): string { return "Line"; } getColor(): string { return this._ref.stroke() as string; } setColor(hex: string) { this._ref.stroke(hex); } getRotation(): number { return this._ref.rotation(); } setRotation(degrees: number): void { this._ref.rotation(degrees); } getZIndex(): number { return this._ref.zIndex(); } setZIndex(zIndex: number): void { this._ref.zIndex(zIndex); } delete(): void { this._ref.destroy(); this._ref = null; } getPoints(): number[] { return this._ref.points(); } setLineWidth(size: number) { this._ref.strokeWidth(size); } getLineWidth(): number { return this._ref.strokeWidth(); } getLineType(): string { const typeSpecs = this._ref.dash() || []; let type: MarkupLineType; switch (typeSpecs) { case LineTypeSpecs.get("dot"): type = "dot"; break; case LineTypeSpecs.get("dash"): type = "dash"; break; default: type = "solid"; break; } return type; } setLineType(type: string) { const specs = LineTypeSpecs.get(type); if (specs) this._ref.dash(specs); } addPoints(points: [{ x: number; y: number }]) { let newPoints = this._ref.points(); let wcsPoints = this._ref.getAttr("wcsPoints"); points.forEach((point) => { newPoints = newPoints.concat([point.x, point.y]); let wcsPoint = this._worldTransformer.screenToWorld(point); wcsPoints.push(wcsPoint); }); this._ref.points(newPoints); } updateScreenCoordinates(): void { let wcsPoints = this._ref.getAttr("wcsPoints"); let points = []; let invert = this._ref.getAbsoluteTransform().copy(); invert = invert.invert(); wcsPoints.forEach((point) => { let screenPoint = this._worldTransformer.worldToScreen(point); screenPoint = invert.point({ x: screenPoint.x, y: screenPoint.y }); points.push(screenPoint.x); points.push(screenPoint.y); }); this._ref.points([]); this._ref.points(points); this._ref.clearCache(); } }