From ba92c7fe2599f75f81e50fbaa0c26d83773d562f Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 5 Nov 2024 09:18:01 +0100 Subject: [PATCH] Improve engine design. --- src/wireframes/components/CustomDragLayer.tsx | 2 +- src/wireframes/components/EditorView.tsx | 2 +- src/wireframes/engine/interface.ts | 33 +++------ src/wireframes/engine/svg/engine.stories.tsx | 44 ++++++------ src/wireframes/engine/svg/item.ts | 70 +++++++------------ src/wireframes/engine/svg/line.ts | 4 +- src/wireframes/engine/svg/object.ts | 23 ++---- src/wireframes/engine/svg/rect-or-ellipse.ts | 12 +--- src/wireframes/engine/svg/text.ts | 14 ++-- src/wireframes/model/assets-state.ts | 2 +- src/wireframes/model/transform.ts | 2 +- src/wireframes/renderer/Editor.tsx | 2 +- src/wireframes/renderer/ItemsLayer.tsx | 51 ++++++++++++-- src/wireframes/renderer/SelectionAdorner.tsx | 13 ++-- src/wireframes/renderer/TransformAdorner.tsx | 63 +++++++++-------- .../renderer/interaction-overlays.ts | 4 +- src/wireframes/shapes/ShapeRenderer.tsx | 2 +- 17 files changed, 166 insertions(+), 177 deletions(-) diff --git a/src/wireframes/components/CustomDragLayer.tsx b/src/wireframes/components/CustomDragLayer.tsx index 82f9e31..c2bb05d 100644 --- a/src/wireframes/components/CustomDragLayer.tsx +++ b/src/wireframes/components/CustomDragLayer.tsx @@ -6,7 +6,7 @@ */ import { useDragLayer, XYCoord } from 'react-dnd'; -import { ShapePlugin } from '../interface'; +import { ShapePlugin } from '@app/wireframes/interface'; import { getViewBox, ShapeRenderer } from '../shapes/ShapeRenderer'; import './CustomDragLayer.scss'; diff --git a/src/wireframes/components/EditorView.tsx b/src/wireframes/components/EditorView.tsx index 42e6ea3..9200b69 100644 --- a/src/wireframes/components/EditorView.tsx +++ b/src/wireframes/components/EditorView.tsx @@ -12,10 +12,10 @@ import { NativeTypes } from 'react-dnd-html5-backend'; import { findDOMNode } from 'react-dom'; import { Canvas, loadImagesToClipboardItems, useClipboard, useEventCallback, ViewBox } from '@app/core'; import { useAppDispatch } from '@app/store'; +import { ShapeSource } from '@app/wireframes/interface'; import { addShape, changeItemsAppearance, Diagram, getDiagram, getDiagramId, getEditor, getMasterDiagram, getSelection, PluginRegistry, selectItems, Transform, transformItems, useStore } from '@app/wireframes/model'; import { Editor } from '@app/wireframes/renderer/Editor'; import { DiagramRef, ItemsRef } from '../model/actions/utils'; -import { ShapeSource } from './../interface'; import { useContextMenu } from './context-menu'; import './EditorView.scss'; diff --git a/src/wireframes/engine/interface.ts b/src/wireframes/engine/interface.ts index 9434eed..80f4ce0 100644 --- a/src/wireframes/engine/interface.ts +++ b/src/wireframes/engine/interface.ts @@ -88,7 +88,7 @@ export interface EngineRectOrEllipse extends EngineObject { fill(value: string): void; // Renders with position, size and rotation. - plot(x: number, y: number, w: number, h: number, rotation?: number, rx?: number, ry?: number): void; + plot(args: { x: number; y: number; w: number; h: number; rotation?: number; rx?: number; ry?: number }): void; } export interface EngineRect extends EngineRectOrEllipse { @@ -101,8 +101,8 @@ export interface EngineLine extends EngineObject { // The color of the line. color(value: string): void; - // Renders the line from (x1, y1) to (x2, y2) if the object is a line. - plot(x1: number, y1: number, x2: number, y2: number, width: number): void; + // Renders the line from (x1, y1) to (x2, y2). + plot(args: { x1: number; y1: number; x2: number; y2: number; width: number }): void; } export interface EngineText extends EngineObject { @@ -122,15 +122,12 @@ export interface EngineText extends EngineObject { text(value: string): void; // Defines the dimensions. - plot(x: number, y: number, w: number, h: number, padding: number): void; + plot(args: { x: number; y: number; w: number; h: number; padding: number }): void; } export interface EngineObject { // Defines the cursor for the object. - cursor(value: string): void; - - // Defines the cursor angle. - cursorAngle(value: number): void; + cursor(value: string | number): void; // Removes the element from the parent. remove(): void; @@ -144,26 +141,14 @@ export interface EngineObject { // Disable the object. disable(): void; - // Gets the tag by value. - tag(key: string): T; - - // Sets the tag by value. - tag(key: string, value: T): void; - // Sets or gets the label. label(value?: string): string; } -export interface EngineItem { +export interface EngineItem extends EngineObject { // Removes the element from the parent. - remove(): void; - - // Invalidates the item. - invalidate(item: DiagramItem): void; - - // Checks if the item has the correct index. - checkIndex(index: number): boolean; + detach(): void; - // Renders a temporary preview. - preview(item: DiagramItem | null): void; + // Renders the item. + plot(item: DiagramItem | null): void; } \ No newline at end of file diff --git a/src/wireframes/engine/svg/engine.stories.tsx b/src/wireframes/engine/svg/engine.stories.tsx index 093bd0f..067f3f4 100644 --- a/src/wireframes/engine/svg/engine.stories.tsx +++ b/src/wireframes/engine/svg/engine.stories.tsx @@ -54,16 +54,16 @@ const HitTest = () => { const layer = engine.layer('layer1'); const rect1 = layer.rect(); + rect1.fill('blue'); rect1.strokeColor('red'); rect1.strokeWidth(2); - rect1.fill('blue'); - rect1.plot(100, 150, 300, 200, 45); + rect1.plot({ x: 100, y: 150, w: 300, h: 200, rotation: 45 }); const rect2 = layer.rect(); + rect2.fill('yellow'); rect2.strokeColor('green'); rect2.strokeWidth(2); - rect2.fill('yellow'); - rect2.plot(600, 150, 300, 200); + rect2.plot({ x: 600, y: 150, w: 300, h: 200 }); const listener: Listener = { onMouseMove: (event) => { @@ -106,10 +106,10 @@ export const Rect = () => { const layer = engine.layer('layer1'); const rect = layer.rect(); + rect.fill('blue'); rect.strokeColor('red'); rect.strokeWidth(2); - rect.fill('blue'); - rect.plot(100, 150, 300, 200); + rect.plot({ x: 100, y: 150, w: 300, h: 200 }); }} /> ); @@ -122,10 +122,10 @@ export const Ellipse = () => { const layer = engine.layer('layer1'); const ellipse = layer.ellipse(); + ellipse.fill('blue'); ellipse.strokeColor('red'); ellipse.strokeWidth(2); - ellipse.fill('blue'); - ellipse.plot(100, 150, 300, 200); + ellipse.plot({ x: 100, y: 150, w: 300, h: 200 }); }} /> ); @@ -139,15 +139,15 @@ export const Line1 = () => { const line1 = layer.line(); line1.color('red'); - line1.plot(100, 150, 200, 250, 1); + line1.plot({ x1: 100, y1: 150, x2: 200, y2: 250, width: 1 }); const line2 = layer.line(); line2.color('blue'); - line2.plot(140, 150, 240, 250, 2); + line1.plot({ x1: 140, y1: 150, x2: 240, y2: 250, width: 1 }); const line3 = layer.line(); line3.color('green'); - line3.plot(180, 150, 280, 250, 4); + line1.plot({ x1: 180, y1: 150, x2: 280, y2: 250, width: 1 }); }} /> ); @@ -161,19 +161,19 @@ export const Text = () => { const text1 = layer.text(); text1.color('white'); + text1.fill('black'); text1.fontFamily('inherit'); text1.fontSize('16px'); - text1.fill('black'); text1.text('Hello SVG'); - text1.plot(50, 100, 200, 60, 20); + text1.plot({ x: 50, y: 100, w: 200, h: 60, padding: 20 }); const text2 = layer.text(); text2.color('white'); + text2.fill('red'); text2.fontFamily('inherit'); text2.fontSize('16px'); - text2.fill('red'); text2.text('Hello SVG'); - text2.plot(50, 200, 200, 100, 20); + text1.plot({ x: 50, y: 200, w: 200, h: 60, padding: 20 }); }} /> ); @@ -187,21 +187,21 @@ export const Cursors = () => { const move = layer.text(); move.color('white'); + move.cursor('move'); + move.fill('black'); move.fontFamily('inherit'); move.fontSize('16px'); - move.fill('black'); - move.text('Move'); - move.cursor('move'); - move.plot(50, 100, 200, 60, 20); + move.text('move'); + move.plot({ x: 50, y: 100, w: 200, h: 60, padding: 20 }); const resize = layer.text(); resize.color('white'); + resize.cursor('n-resize'); + resize.fill('red'); resize.fontFamily('inherit'); resize.fontSize('16px'); - resize.fill('red'); resize.text('resize'); - resize.cursor('n-resize'); - resize.plot(50, 200, 200, 100, 20); + resize.plot({ x: 50, y: 200, w: 200, h: 60, padding: 20 }); }} /> ); diff --git a/src/wireframes/engine/svg/item.ts b/src/wireframes/engine/svg/item.ts index b584afa..e3d4839 100644 --- a/src/wireframes/engine/svg/item.ts +++ b/src/wireframes/engine/svg/item.ts @@ -9,17 +9,21 @@ import * as svg from '@svgdotjs/svg.js'; import { Rect2 } from '@app/core'; import { ShapePlugin } from '@app/wireframes/interface'; import { DiagramItem } from '@app/wireframes/model'; +import { EngineItem } from './../interface'; +import { SvgObject } from './object'; import { SvgRenderer } from './renderer'; import { linkToSvg, SvgHelper } from './utils'; -export class SvgItem { - private readonly container: svg.G; +export class SvgItem extends SvgObject implements EngineItem { + private readonly group: svg.G; private readonly selector: svg.Rect; - private previewShape: DiagramItem | null = null; private currentShape: DiagramItem | null = null; - private currentIndex = -1; private isRendered = false; + protected get root() { + return this.group; + } + public get shape() { return this.currentShape; } @@ -29,64 +33,42 @@ export class SvgItem { public readonly renderer: SvgRenderer, public readonly plugin: ShapePlugin, ) { + super(); this.selector = new svg.Rect().fill('#ffffff').opacity(0.001); - this.container = new svg.G(); - this.container.add(this.selector); - - linkToSvg(this, this.container); + this.group = new svg.G(); + this.group.add(this.selector); + linkToSvg(this, this.group); } - public remove() { - // Always remove them so we can add the shapes back in the right order. - this.container?.remove(); + public detach() { + this.remove(); } - public checkIndex(index: number) { - const result = this.currentIndex >= 0 && this.currentIndex !== index; - - this.currentIndex = index; - - return result; - } - - public preview(previewShape: DiagramItem | null) { - if (this.previewShape === previewShape) { - return; - } - - const shapeToRender = previewShape || this.currentShape; - - if (!shapeToRender) { - return; - } - - this.renderCore(shapeToRender); - this.previewShape = previewShape; - } - - public invalidate(shape: DiagramItem) { + public plot(shape: DiagramItem) { if (this.currentShape === shape && this.isRendered) { - this.layer.add(this.container); + this.addToLayer(); return; } this.renderCore(shape); - // For new elements we might have to add them. - if (!this.container.parent()) { - this.layer.add(this.container); - } - + this.addToLayer(); this.currentShape = shape; } + private addToLayer() { + if (!this.group.parent()) { + this.layer.add(this.group); + } + } + private renderCore(item: DiagramItem) { const localRect = new Rect2(0, 0, item.transform.size.x, item.transform.size.y); const previousContainer = this.renderer.getContainer(); try { - this.renderer.setContainer(this.container, 1); + this.renderer.setContainer(this.group, 1); this.plugin.render({ renderer2: this.renderer, rect: localRect, shape: item }); @@ -102,7 +84,7 @@ export class SvgItem { private arrangeContainer(item: DiagramItem) { const to = item.transform; - SvgHelper.transformBy(this.container, { + SvgHelper.transformBy(this.group, { x: to.position.x - 0.5 * to.size.x, y: to.position.y - 0.5 * to.size.y, w: to.size.x, @@ -112,7 +94,7 @@ export class SvgItem { rotation: to.rotation.degree, }); - this.container.opacity(item.opacity); + this.group.opacity(item.opacity); } private arrangeSelector(localRect: Rect2) { diff --git a/src/wireframes/engine/svg/line.ts b/src/wireframes/engine/svg/line.ts index 433dcfa..6a6cee3 100644 --- a/src/wireframes/engine/svg/line.ts +++ b/src/wireframes/engine/svg/line.ts @@ -26,7 +26,9 @@ export class SvgLine extends SvgObject implements EngineLine { this.shape.stroke(value); } - public plot(x1: number, y1: number, x2: number, y2: number, width: number): void { + public plot(args: { x1: number; y1: number; x2: number; y2: number; width: number }): void { + const { x1, y1, x2, y2, width } = args; + this.shape.plot(x1, y1, x2, y2).stroke({ width }); } diff --git a/src/wireframes/engine/svg/object.ts b/src/wireframes/engine/svg/object.ts index ccd3a99..4886995 100644 --- a/src/wireframes/engine/svg/object.ts +++ b/src/wireframes/engine/svg/object.ts @@ -12,12 +12,12 @@ import { EngineObject } from './../interface'; export abstract class SvgObject implements EngineObject { protected abstract get root(): svg.Element; - public cursor(value: string): void { - (this.root.node as any)['cursor'] = value; - } - - public cursorAngle(value: number): void { - (this.root.node as any)['cursorAngle'] = value; + public cursor(value: string | number): void { + if (Types.isNumber(value)) { + (this.root.node as any)['cursorAngle'] = value; + } else { + (this.root.node as any)['cursor'] = value; + } } public show() { @@ -36,17 +36,6 @@ export abstract class SvgObject implements EngineObject { this.root.remove(); } - public tag(key: string, value?: T): T { - const tagKey = `tag_${key}`; - - if (Types.isUndefined(value)) { - return (this as any)[tagKey] as T; - } else { - (this as any)[tagKey] = value; - return value; - } - } - public label(value?: string): string { if (value) { this.root.id(value); diff --git a/src/wireframes/engine/svg/rect-or-ellipse.ts b/src/wireframes/engine/svg/rect-or-ellipse.ts index 83b3d81..c69b3c6 100644 --- a/src/wireframes/engine/svg/rect-or-ellipse.ts +++ b/src/wireframes/engine/svg/rect-or-ellipse.ts @@ -34,15 +34,7 @@ export class SvgRectOrEllipse extends SvgObject implements EngineRect { this.shape.fill(value); } - public plot(x: number, y: number, w: number, h: number, rotation?: number, rx?: number, ry?: number): void { - SvgHelper.transformBy(this.shape, { - x, - y, - w, - h, - rotation, - rx, - ry, - }, false, true); + public plot(args: { x: number; y: number; w: number; h: number; rotation?: number; rx?: number; ry?: number }): void { + SvgHelper.transformBy(this.shape, args, false, true); } } \ No newline at end of file diff --git a/src/wireframes/engine/svg/text.ts b/src/wireframes/engine/svg/text.ts index 19e490d..10d4dab 100644 --- a/src/wireframes/engine/svg/text.ts +++ b/src/wireframes/engine/svg/text.ts @@ -53,11 +53,10 @@ export class SvgText extends SvgObject implements EngineText { this.textInner.textContent = value; } - public plot(x: number, y: number, w: number, h: number, padding: number): void { - SvgHelper.transformBy(this.container, { - x, - y, - }); + public plot(args: { x: number; y: number; w: number; h: number; padding: number }): void { + const { w, h, padding } = args; + + SvgHelper.transformBy(this.container, args); SvgHelper.transformBy(this.textElement, { x: padding, @@ -66,9 +65,6 @@ export class SvgText extends SvgObject implements EngineText { h: h - 2 * padding, }); - SvgHelper.transformBy(this.background, { - w: w, - h: h, - }); + SvgHelper.transformBy(this.background, { w, h }); } } \ No newline at end of file diff --git a/src/wireframes/model/assets-state.ts b/src/wireframes/model/assets-state.ts index 3924841..d9e6482 100644 --- a/src/wireframes/model/assets-state.ts +++ b/src/wireframes/model/assets-state.ts @@ -5,9 +5,9 @@ * Copyright (c) Sebastian Stehle. All rights reserved. */ +import { ShapePlugin } from '@app/wireframes/interface'; import { ICONS_FONT_AWESOME } from './../../icons/font_awesome_unified'; import { ICONS_MATERIAL_DESIGN } from './../../icons/material_icons_unified'; -import { ShapePlugin } from './../interface'; import { PluginRegistry } from './registry'; export interface AssetInfo { diff --git a/src/wireframes/model/transform.ts b/src/wireframes/model/transform.ts index a7ca9ea..abc77b3 100644 --- a/src/wireframes/model/transform.ts +++ b/src/wireframes/model/transform.ts @@ -8,7 +8,7 @@ /* eslint-disable no-multi-assign */ import { Rect2, Rotation, Vec2 } from '@app/core/utils'; -import { Constraint } from './../interface'; +import { Constraint } from '@app/wireframes/interface'; const EPSILON = 0.1; diff --git a/src/wireframes/renderer/Editor.tsx b/src/wireframes/renderer/Editor.tsx index ebb1962..ff0a806 100644 --- a/src/wireframes/renderer/Editor.tsx +++ b/src/wireframes/renderer/Editor.tsx @@ -119,7 +119,7 @@ export const Editor = React.memo((props: EditorProps) => { }, []); React.useEffect(() => { - backgroundRect?.plot(0, 0, viewSize.x, viewSize.y); + backgroundRect?.plot({ x: 0, y: 0, w: viewSize.x, h: viewSize.y }); }, [backgroundRect, viewSize]); React.useEffect(() => { diff --git a/src/wireframes/renderer/ItemsLayer.tsx b/src/wireframes/renderer/ItemsLayer.tsx index 14bd461..8d4dc72 100644 --- a/src/wireframes/renderer/ItemsLayer.tsx +++ b/src/wireframes/renderer/ItemsLayer.tsx @@ -34,7 +34,7 @@ export const ItemsLayer = React.memo((props: ItemsLayerProps) => { } = props; const shapesRendered = React.useRef(onRender); - const shapeRefsById = React.useRef<{ [id: string]: EngineItem }>({}); + const shapeRefsById = React.useRef>({}); const itemIds = diagram?.rootIds; const items = diagram?.items; @@ -91,12 +91,12 @@ export const ItemsLayer = React.memo((props: ItemsLayerProps) => { for (const shape of allShapes) { if (!references[shape.id]) { const plugin = PluginRegistry.get(shape.renderer)?.plugin; - + if (!plugin) { throw new Error(`Cannot find renderer for ${shape.renderer}.`); } - references[shape.id] = diagramLayer.item(plugin); + references[shape.id] = new ItemWithPreview(diagramLayer.item(plugin)); } } @@ -111,12 +111,12 @@ export const ItemsLayer = React.memo((props: ItemsLayerProps) => { // If the index of at least once shape has changed we have to remove them all to render them in the correct order. if (hasIdChanged) { for (const ref of Object.values(references)) { - ref.remove(); + ref.detach(); } } for (const shape of allShapes) { - references[shape.id].invalidate(shape); + references[shape.id].plot(shape); } if (shapesRendered.current) { @@ -140,3 +140,44 @@ export const ItemsLayer = React.memo((props: ItemsLayerProps) => { return null; }); + +class ItemWithPreview { + private shapePreview: DiagramItem | null = null; + private shapeStatic: DiagramItem | null = null; + private currentIndex = -1; + + constructor( + private readonly engineItem: EngineItem, + ) { + } + + public plot(shape: DiagramItem) { + this.shapeStatic = shape; + this.shapePreview = null; + this.render(); + } + + public preview(shape: DiagramItem | null) { + this.shapePreview = shape; + this.render(); + } + + public checkIndex(index: number) { + const result = this.currentIndex >= 0 && this.currentIndex !== index; + + this.currentIndex = index; + return result; + } + + public detach() { + this.engineItem.detach(); + } + + public remove() { + this.engineItem.remove(); + } + + private render() { + this.engineItem.plot(this.shapePreview || this.shapeStatic); + } +} diff --git a/src/wireframes/renderer/SelectionAdorner.tsx b/src/wireframes/renderer/SelectionAdorner.tsx index 763159a..3536a7b 100644 --- a/src/wireframes/renderer/SelectionAdorner.tsx +++ b/src/wireframes/renderer/SelectionAdorner.tsx @@ -200,12 +200,13 @@ export class SelectionAdorner extends React.Component imp } protected transformShape(shape: EngineRect, position: Vec2, size: Vec2, offset: number, rotation = 0) { - shape.plot( - position.x - 0.5 * offset, - position.y - 0.5 * offset, - size.x + offset, - size.y + offset, - rotation); + shape.plot({ + x: position.x - 0.5 * offset, + y: position.y - 0.5 * offset, + w: size.x + offset, + h: size.y + offset, + rotation, + }); if (size.x > 2 && size.y > 2) { shape.show(); diff --git a/src/wireframes/renderer/TransformAdorner.tsx b/src/wireframes/renderer/TransformAdorner.tsx index 4c2af8d..895b5bc 100644 --- a/src/wireframes/renderer/TransformAdorner.tsx +++ b/src/wireframes/renderer/TransformAdorner.tsx @@ -265,7 +265,7 @@ export class TransformAdorner extends React.PureComponent this.manipulationMode = Mode.Rotate; } else { this.manipulationMode = Mode.Resize; - this.manipulationOffset = hitItem.tag('offset'); + this.manipulationOffset = (hitItem as any)['offset'] as Vec2; } } @@ -492,7 +492,7 @@ export class TransformAdorner extends React.PureComponent const adornerHalfSize = adornerSize / 2; for (const resizeShape of this.resizeShapes) { - const offset = resizeShape.tag('offset'); + const offset = (resizeShape as any)['offset'] as Vec2; const visible = (offset.x === 0 || this.canResizeX) && @@ -505,40 +505,40 @@ export class TransformAdorner extends React.PureComponent resizeShape.show(); resizeShape.strokeWidth(stroke); - resizeShape.plot( - transformPosition.x - adornerHalfSize + offset.x * (transformSize.x + adornerHalfSize), // x - transformPosition.y - adornerHalfSize + offset.y * (transformSize.y + adornerHalfSize), // y - adornerSize, // w - adornerSize, // w - transformRotation, // r - transformPosition.x, // ry - transformPosition.y, // ry - ); + resizeShape.plot({ + x: transformPosition.x - adornerHalfSize + offset.x * (transformSize.x + adornerHalfSize), + y: transformPosition.y - adornerHalfSize + offset.y * (transformSize.y + adornerHalfSize), + w: adornerSize, + h: adornerSize, + rotation: transformRotation, + rx: transformPosition.x, + ry: transformPosition.y, + }); } this.rotateShape.show(); this.rotateShape.strokeWidth(stroke); - this.rotateShape.plot( - transformPosition.x - adornerHalfSize, // x - transformPosition.y - adornerHalfSize - transformSize.y * 0.5 - 30 / this.props.zoom, // y - adornerSize, // w - adornerSize, // w - transformRotation, // r - transformPosition.x, // ry - transformPosition.y, // ry - ); + this.rotateShape.plot({ + x: transformPosition.x - adornerHalfSize, + y: transformPosition.y - adornerHalfSize - transformSize.y * 0.5 - 30 / this.props.zoom, + w: adornerSize, + h: adornerSize, + rotation: transformRotation, + rx: transformPosition.x, + ry: transformPosition.y, + }); this.moveShape.show(); this.moveShape.strokeWidth(stroke); - this.moveShape.plot( - transformPosition.x - 0.5 * transformSize.x, // x - transformPosition.y - 0.5 * transformSize.y, // y - transformSize.x, // w - transformSize.y, // w - transformRotation, // r - transformPosition.x, // ry - transformPosition.y, // ry - ); + this.moveShape.plot({ + x: transformPosition.x - 0.5 * transformSize.x, + y: transformPosition.y - 0.5 * transformSize.y, + w: transformSize.x, + h: transformSize.y, + rotation: transformRotation, + rx: transformPosition.x, + ry: transformPosition.y, + }); } private hideShapes() { @@ -570,12 +570,13 @@ export class TransformAdorner extends React.PureComponent for (let i = 0; i < xs.length; i++) { const resizeShape = this.props.layer.rect(); - resizeShape.cursorAngle(as[i]); + resizeShape.cursor(as[i]); resizeShape.fill(TRANSFORMER_FILL_COLOR); resizeShape.strokeColor(TRANSFORMER_STROKE_COLOR); resizeShape.strokeWidth(1); - resizeShape.tag('offset', new Vec2(xs[i], ys[i])); this.resizeShapes.push(resizeShape); + + (resizeShape as any)['offset'] = new Vec2(xs[i], ys[i]); } } diff --git a/src/wireframes/renderer/interaction-overlays.ts b/src/wireframes/renderer/interaction-overlays.ts index 4d6306a..4131c43 100644 --- a/src/wireframes/renderer/interaction-overlays.ts +++ b/src/wireframes/renderer/interaction-overlays.ts @@ -107,7 +107,7 @@ export class InteractionOverlays { line.show(); } - line.plot(x1, y1, x2, y2, width); + line.plot({ x1, y1, x2, y2, width }); line.color(color); this.indexLines++; } @@ -154,7 +154,7 @@ export class InteractionOverlays { label.fill(color); label.fontFamily('monospace'); label.fontSize(sizeInPx(fontSize / this.zoom)); - label.plot(x, y, w, h, padding); + label.plot({ x, y, w, h, padding }); label.text(text); // Increment by one because we create one group per label. diff --git a/src/wireframes/shapes/ShapeRenderer.tsx b/src/wireframes/shapes/ShapeRenderer.tsx index b1e1e15..aa1b601 100644 --- a/src/wireframes/shapes/ShapeRenderer.tsx +++ b/src/wireframes/shapes/ShapeRenderer.tsx @@ -96,7 +96,7 @@ export const ShapeRenderer = React.memo(React.forwardRef