Skip to content

Commit

Permalink
Improve engine design.
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastianStehle committed Nov 5, 2024
1 parent b25f9be commit ba92c7f
Show file tree
Hide file tree
Showing 17 changed files with 166 additions and 177 deletions.
2 changes: 1 addition & 1 deletion src/wireframes/components/CustomDragLayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
2 changes: 1 addition & 1 deletion src/wireframes/components/EditorView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
33 changes: 9 additions & 24 deletions src/wireframes/engine/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand All @@ -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;
Expand All @@ -144,26 +141,14 @@ export interface EngineObject {
// Disable the object.
disable(): void;

// Gets the tag by value.
tag<T>(key: string): T;

// Sets the tag by value.
tag<T>(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;
}
44 changes: 22 additions & 22 deletions src/wireframes/engine/svg/engine.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -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 });
}}
/>
);
Expand All @@ -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 });
}}
/>
);
Expand All @@ -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 });
}}
/>
);
Expand All @@ -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 });
}}
/>
);
Expand All @@ -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 });
}}
/>
);
Expand Down
70 changes: 26 additions & 44 deletions src/wireframes/engine/svg/item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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 });

Expand All @@ -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,
Expand All @@ -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) {
Expand Down
4 changes: 3 additions & 1 deletion src/wireframes/engine/svg/line.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
}

Expand Down
23 changes: 6 additions & 17 deletions src/wireframes/engine/svg/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -36,17 +36,6 @@ export abstract class SvgObject implements EngineObject {
this.root.remove();
}

public tag<T>(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);
Expand Down
Loading

0 comments on commit ba92c7f

Please sign in to comment.