UNPKG

@inweb/markup

Version:
243 lines (200 loc) 8.16 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 { IMarkupEllipse, IMarkupEllipseParams } from "../IMarkupEllipse"; import { IWorldTransform } from "../IWorldTransform"; import { WorldTransform } from "../WorldTransform"; export class KonvaEllipse implements IMarkupEllipse { private _ref: Konva.Ellipse; private _worldTransformer: IWorldTransform; constructor(params: IMarkupEllipseParams, ref = null, worldTransformer = new WorldTransform()) { this._worldTransformer = worldTransformer; if (ref) { this._ref = ref; const wcsPosition = this._ref.getAttr("wcsPosition"); const radiusX = this._ref.getAttr("wcsRadiusX"); const radiusY = this._ref.getAttr("wcsRadiusY"); if (!wcsPosition) { this._ref.setAttr("wcsPosition", this._worldTransformer.screenToWorld({ x: ref.x(), y: ref.y() })); } if (!radiusX) { this._ref.setAttr( "wcsRadiusX", this._worldTransformer.screenToWorld({ x: ref.x() + ref.radiusX(), y: ref.y() }) ); } if (!radiusY) { this._ref.setAttr( "wcsRadiusY", this._worldTransformer.screenToWorld({ x: ref.x(), y: ref.y() + ref.radiusY() }) ); } return; } if (!params) params = {}; if (!params.position) params.position = { x: 0, y: 0 }; if (!params.radius) params.radius = { x: 25, y: 25 }; this._ref = new Konva.Ellipse({ stroke: params.color ?? "#ff0000", strokeWidth: params.lineWidth ?? 4, globalCompositeOperation: "source-over", lineCap: "round", lineJoin: "round", x: params.position.x, y: params.position.y, radiusX: params.radius.x, radiusY: params.radius.y, draggable: true, strokeScaleEnabled: false, }); this._ref.setAttr( "wcsPosition", this._worldTransformer.screenToWorld({ x: params.position.x, y: params.position.y }) ); this._ref.setAttr( "wcsRadiusX", this._worldTransformer.screenToWorld({ x: this._ref.x() + params.radius.x, y: this._ref.y() }) ); this._ref.setAttr( "wcsRadiusY", this._worldTransformer.screenToWorld({ x: this._ref.x(), y: this._ref.y() + params.radius.y }) ); this._ref.on("transform", (e) => { const attrs = e.target.attrs; if (attrs.rotation !== this._ref.rotation()) this._ref.rotation(attrs.rotation); const scaleByX = Math.abs(attrs.scaleX - 1) > 10e-6; const scaleByY = Math.abs(attrs.scaleY - 1) > 10e-6; let newRadiusX = this._ref.radiusX(); if (scaleByX) newRadiusX *= attrs.scaleX; let newRadiusY = this._ref.radiusY(); if (scaleByY) newRadiusY *= attrs.scaleY; const minRadiusX = 25; const minRadiusY = 25; if (newRadiusX < minRadiusX) newRadiusX = minRadiusX; if (newRadiusY < minRadiusY) newRadiusY = minRadiusY; if (e.evt.ctrlKey || e.evt.shiftKey) { if (scaleByX) { this._ref.radius({ x: newRadiusX, y: newRadiusX }); } else { this._ref.radius({ x: newRadiusY, y: newRadiusY }); } } else { this._ref.radius({ x: newRadiusX, y: newRadiusY }); } this._ref.scale({ x: 1, y: 1 }); }); this._ref.on("transformend", (e) => { const absoluteTransform = this._ref.getStage().getAbsoluteTransform(); const position = absoluteTransform.point({ x: this._ref.x(), y: this._ref.y() }); this._ref.setAttr("wcsPosition", this._worldTransformer.screenToWorld(position)); const radiusX = absoluteTransform.point({ x: this._ref.x() + this._ref.radiusX(), y: this._ref.y() }); this._ref.setAttr("wcsRadiusX", this._worldTransformer.screenToWorld(radiusX)); const radiusY = absoluteTransform.point({ x: this._ref.x(), y: this._ref.y() + this._ref.radiusY() }); this._ref.setAttr("wcsRadiusY", this._worldTransformer.screenToWorld(radiusY)); }); this._ref.on("dragend", (e) => { const absoluteTransform = this._ref.getStage().getAbsoluteTransform(); const position = absoluteTransform.point({ x: this._ref.x(), y: this._ref.y() }); this._ref.setAttr("wcsPosition", this._worldTransformer.screenToWorld(position)); const radiusX = absoluteTransform.point({ x: this._ref.x() + this._ref.radiusX(), y: this._ref.y() }); this._ref.setAttr("wcsRadiusX", this._worldTransformer.screenToWorld(radiusX)); const radiusY = absoluteTransform.point({ x: this._ref.x(), y: this._ref.y() + this._ref.radiusY() }); this._ref.setAttr("wcsRadiusY", this._worldTransformer.screenToWorld(radiusY)); }); this._ref.id(this._ref._id.toString()); } getPosition(): { x: number; y: number } { return this._ref.position(); } setPosition(x: number, y: number): void { this._ref.setPosition({ x, y }); this._ref.setAttr("wcsPosition", this._worldTransformer.screenToWorld({ x, y })); } getRadiusX(): number { return this._ref.radiusX(); } setRadiusX(r: number): void { this._ref.radiusX(r); this._ref.setAttr("wcsRadiusX", this._worldTransformer.screenToWorld({ x: this._ref.x() + r, y: this._ref.y() })); } getRadiusY(): number { return this._ref.radiusY(); } setRadiusY(r: number): void { this._ref.radiusY(r); this._ref.setAttr("wcsRadiusY", this._worldTransformer.screenToWorld({ x: this._ref.x(), y: this._ref.y() + r })); } getLineWidth(): number { return this._ref.strokeWidth(); } setLineWidth(size: number): void { this._ref.strokeWidth(size); } ref() { return this._ref; } id(): string { return this._ref.id(); } enableMouseEditing(value: boolean): void { this._ref.draggable(value); } type(): string { return "Ellipse"; } getColor(): string { return this._ref.stroke() as string; } setColor(hex: string): void { 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; } updateScreenCoordinates(): void { let screenPosition = this._worldTransformer.worldToScreen(this._ref.getAttr("wcsPosition")); let radiusX = this._worldTransformer.worldToScreen(this._ref.getAttr("wcsRadiusX")); let radiusY = this._worldTransformer.worldToScreen(this._ref.getAttr("wcsRadiusY")); let invert = this._ref.getStage().getAbsoluteTransform().copy(); invert = invert.invert(); const position = invert.point({ x: screenPosition.x, y: screenPosition.y }); this._ref.position({ x: position.x, y: position.y }); this._ref.radius({ x: Math.abs(invert.point(radiusX).x - position.x), y: Math.abs(invert.point(radiusY).y - position.y), }); } }