Merged PR 366: Refactor Canvas, SVG and Viewer parameters

This commit is contained in:
Eric Nguyen 2023-02-17 16:20:31 +00:00
parent d40f97ad6f
commit b2644a039e
4 changed files with 139 additions and 98 deletions

View file

@ -1,15 +1,79 @@
import React, { useEffect, useRef } from 'react'; import React, { useEffect, useRef } from 'react';
import { type IPoint } from '../../Interfaces/IPoint'; import { type IPoint } from '../../Interfaces/IPoint';
import { BAR_WIDTH } from '../Bar/Bar'; import { BAR_WIDTH } from '../Bar/Bar';
import { SelectorMode } from '../SVG/SVG';
import { type DrawParams } from '../Viewer/Viewer';
import { RenderContainers, RenderSymbols } from './Renderer';
import { RenderContainerSelector } from './SelectorContainer';
import { RenderSymbolSelector } from './SelectorSymbol';
interface ICanvasProps { interface ICanvasProps {
className?: string
width: number width: number
height: number height: number
draw: (context: CanvasRenderingContext2D, frameCount: number, scale: number, translatePos: IPoint) => void
className?: string
style?: React.CSSProperties style?: React.CSSProperties
drawParams: DrawParams
}; };
function Draw(
ctx: CanvasRenderingContext2D,
frameCount: number,
scale: number,
translatePos: IPoint,
{
mainContainer,
selectorMode,
selectedContainer,
selectedSymbol,
containers,
symbols
}: DrawParams
): void {
if (mainContainer === undefined) {
return;
}
const topDim = mainContainer.properties.y;
const leftDim = mainContainer.properties.x;
const rightDim = mainContainer.properties.x + mainContainer.properties.width;
const bottomDim = mainContainer.properties.y + mainContainer.properties.height;
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.save();
ctx.setTransform(scale, 0, 0, scale, translatePos.x, translatePos.y);
ctx.fillStyle = '#000000';
// Draw containers and symbol dimensions
RenderContainers(
ctx,
mainContainer,
containers,
leftDim, bottomDim, topDim, rightDim, scale);
// Draw symbols and symbol dimensions
RenderSymbols(ctx, symbols, scale);
// Draw selector
switch (selectorMode) {
case SelectorMode.Containers:
RenderContainerSelector(ctx, frameCount, {
containers,
scale,
selected: selectedContainer
});
break;
case SelectorMode.Symbols:
RenderSymbolSelector(ctx, frameCount, {
symbols,
scale,
selected: selectedSymbol
});
break;
}
ctx.restore();
}
function UseCanvas( function UseCanvas(
draw: (context: CanvasRenderingContext2D, draw: (context: CanvasRenderingContext2D,
frameCount: number, frameCount: number,
@ -128,8 +192,21 @@ interface Viewer {
viewerHeight: number viewerHeight: number
} }
export function Canvas({ width, height, draw, style, className }: ICanvasProps): JSX.Element { export function Canvas({
const canvasRef = UseCanvas(draw); className,
width,
height,
style,
drawParams
}: ICanvasProps): JSX.Element {
const canvasRef = UseCanvas((
...CanvasProps
) => {
Draw(
...CanvasProps,
drawParams
);
});
const [{ viewerWidth, viewerHeight }, setViewer] = React.useState<Viewer>({ const [{ viewerWidth, viewerHeight }, setViewer] = React.useState<Viewer>({
viewerWidth: width, viewerWidth: width,

View file

@ -68,11 +68,11 @@ export function RenderContainerDimensions(
export function RenderSymbols( export function RenderSymbols(
ctx: CanvasRenderingContext2D, ctx: CanvasRenderingContext2D,
current: IHistoryState, symbols: Map<string, ISymbolModel>,
scale: number scale: number
): void { ): void {
let count = 0; let count = 0;
current.symbols.forEach((symbol: ISymbolModel) => { symbols.forEach((symbol: ISymbolModel) => {
RenderSymbol(ctx, symbol, scale); RenderSymbol(ctx, symbol, scale);
if (!symbol.showDimension) { if (!symbol.showDimension) {

View file

@ -1,14 +1,13 @@
import * as React from 'react'; import * as React from 'react';
import { ReactSVGPanZoom, type Tool, TOOL_PAN, type Value, ALIGN_CENTER } from 'react-svg-pan-zoom'; import { ReactSVGPanZoom, type Tool, TOOL_PAN, type Value, ALIGN_CENTER } from 'react-svg-pan-zoom';
import { Container } from './Elements/Container'; import { Container } from './Elements/Container';
import { IContainerModel } from '../../Interfaces/IContainerModel';
import { SelectorContainer } from './Elements/SelectorContainer/SelectorContainer'; import { SelectorContainer } from './Elements/SelectorContainer/SelectorContainer';
import { MAX_FRAMERATE } from '../../utils/default'; import { MAX_FRAMERATE } from '../../utils/default';
import { SymbolLayer } from './Elements/SymbolLayer'; import { SymbolLayer } from './Elements/SymbolLayer';
import { type ISymbolModel } from '../../Interfaces/ISymbolModel';
import { DimensionLayer } from './Elements/DimensionLayer'; import { DimensionLayer } from './Elements/DimensionLayer';
import { SelectorSymbol } from './Elements/SelectorSymbol/SelectorSymbol'; import { SelectorSymbol } from './Elements/SelectorSymbol/SelectorSymbol';
import { IToolbarProps, Toolbar } from './SVGReactPanZoom/ui-toolbar/toolbar'; import { type IToolbarProps, Toolbar } from './SVGReactPanZoom/ui-toolbar/toolbar';
import { type DrawParams } from '../Viewer/Viewer';
interface ISVGProps { interface ISVGProps {
className?: string className?: string
@ -16,12 +15,7 @@ interface ISVGProps {
viewerHeight: number viewerHeight: number
width: number width: number
height: number height: number
containers: Map<string, IContainerModel> drawParams: DrawParams
children: IContainerModel
selectedContainer?: IContainerModel
symbols: Map<string, ISymbolModel>
selectedSymbol?: ISymbolModel
selectorMode: SelectorMode
selectContainer: (containerId: string) => void selectContainer: (containerId: string) => void
} }
@ -34,6 +28,14 @@ export enum SelectorMode {
export const ID = 'svg'; export const ID = 'svg';
export function SVG(props: ISVGProps): JSX.Element { export function SVG(props: ISVGProps): JSX.Element {
const {
mainContainer,
selectorMode,
selectedContainer,
selectedSymbol,
containers,
symbols
} = props.drawParams;
const [tool, setTool] = React.useState<Tool>(TOOL_PAN); const [tool, setTool] = React.useState<Tool>(TOOL_PAN);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const [value, setValue] = React.useState<Value>({} as Value); const [value, setValue] = React.useState<Value>({} as Value);
@ -59,27 +61,27 @@ export function SVG(props: ISVGProps): JSX.Element {
}; };
const children: React.ReactNode | React.ReactNode[] = <Container const children: React.ReactNode | React.ReactNode[] = <Container
key={`container-${props.children.properties.id}`} key={`container-${mainContainer.properties.id}`}
containers={props.containers} containers={containers}
model={props.children} model={mainContainer}
depth={0} depth={0}
scale={scale} scale={scale}
selectContainer={props.selectContainer} selectContainer={props.selectContainer}
/>; />;
function Selector(): JSX.Element { function Selector(): JSX.Element {
switch (props.selectorMode) { switch (selectorMode) {
case SelectorMode.Containers: case SelectorMode.Containers:
return <SelectorContainer return <SelectorContainer
containers={props.containers} containers={containers}
scale={scale} scale={scale}
selected={props.selectedContainer} selected={selectedContainer}
/>; />;
case SelectorMode.Symbols: case SelectorMode.Symbols:
return <SelectorSymbol return <SelectorSymbol
symbols={props.symbols} symbols={symbols}
scale={scale} scale={scale}
selected={props.selectedSymbol} selected={selectedSymbol}
/>; />;
default: default:
return <></>; return <></>;
@ -132,8 +134,13 @@ export function SVG(props: ISVGProps): JSX.Element {
> >
<svg {...properties}> <svg {...properties}>
{children} {children}
<DimensionLayer containers={props.containers} symbols={props.symbols} scale={scale} root={props.children} /> <DimensionLayer
<SymbolLayer scale={scale} symbols={props.symbols} /> containers={containers}
symbols={symbols}
scale={scale}
root={mainContainer}
/>
<SymbolLayer scale={scale} symbols={symbols} />
<Selector /> <Selector />
</svg> </svg>
</ReactSVGPanZoom> </ReactSVGPanZoom>

View file

@ -1,44 +1,48 @@
import * as React from 'react'; import * as React from 'react';
import { type IContainerModel } from '../../Interfaces/IContainerModel'; import { type IContainerModel } from '../../Interfaces/IContainerModel';
import { type IHistoryState } from '../../Interfaces/IHistoryState'; import { type IHistoryState } from '../../Interfaces/IHistoryState';
import { type IPoint } from '../../Interfaces/IPoint';
import { USE_EXPERIMENTAL_CANVAS_API } from '../../utils/default'; import { USE_EXPERIMENTAL_CANVAS_API } from '../../utils/default';
import { FindContainerById, MakeRecursionDFSIterator } from '../../utils/itertools'; import { FindContainerById } from '../../utils/itertools';
import { BAR_WIDTH } from '../Bar/Bar'; import { BAR_WIDTH } from '../Bar/Bar';
import { Canvas } from '../Canvas/Canvas'; import { Canvas } from '../Canvas/Canvas';
import { RenderContainerSelector } from '../Canvas/SelectorContainer';
import { SelectorMode, SVG } from '../SVG/SVG'; import { SelectorMode, SVG } from '../SVG/SVG';
import { useState } from 'react'; import { useState } from 'react';
import { type ISymbolModel } from '../../Interfaces/ISymbolModel'; import { type ISymbolModel } from '../../Interfaces/ISymbolModel';
import { RenderContainers, RenderContainerDimensions, RenderSymbols } from '../Canvas/Renderer';
import { RenderContainer } from '../Canvas/Container';
import { RenderSymbolSelector } from '../Canvas/SelectorSymbol';
interface IViewerProps { interface IViewerProps {
className: string className: string
current: IHistoryState current: IHistoryState
selectedContainer: IContainerModel | undefined selectedContainer: IContainerModel | undefined
selectContainer: (containerId: string) => void
selectedSymbol: ISymbolModel | undefined selectedSymbol: ISymbolModel | undefined
margin: number margin: number
isComponentsOpen: boolean isComponentsOpen: boolean
isSymbolsOpen: boolean isSymbolsOpen: boolean
selectContainer: (containerId: string) => void
}
export interface DrawParams {
mainContainer: IContainerModel
selectorMode: SelectorMode
selectedContainer: IContainerModel | undefined
selectedSymbol: ISymbolModel | undefined
containers: Map<string, IContainerModel>
symbols: Map<string, ISymbolModel>
}
function computeWidth(margin: number): number {
return window.innerWidth - (window.innerWidth < 768 ? BAR_WIDTH : margin);
} }
export function Viewer({ export function Viewer({
className, className,
current, current,
selectedContainer, selectedContainer,
selectContainer,
selectedSymbol, selectedSymbol,
margin, margin,
isComponentsOpen, isComponentsOpen,
isSymbolsOpen isSymbolsOpen,
selectContainer
}: IViewerProps): JSX.Element { }: IViewerProps): JSX.Element {
function computeWidth(margin: number): number {
return window.innerWidth - (window.innerWidth < 768 ? BAR_WIDTH : margin);
}
const [windowSize, setWindowSize] = useState([ const [windowSize, setWindowSize] = useState([
computeWidth(margin), computeWidth(margin),
window.innerHeight window.innerHeight
@ -79,63 +83,22 @@ export function Viewer({
selectorMode = SelectorMode.Symbols; selectorMode = SelectorMode.Symbols;
} }
if (USE_EXPERIMENTAL_CANVAS_API) { const drawParams: DrawParams = {
function Draw(
ctx: CanvasRenderingContext2D,
frameCount: number,
scale: number,
translatePos: IPoint
): void {
if (mainContainer === undefined) {
return;
}
const topDim = mainContainer.properties.y;
const leftDim = mainContainer.properties.x;
const rightDim = mainContainer.properties.x + mainContainer.properties.width;
const bottomDim = mainContainer.properties.y + mainContainer.properties.height;
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.save();
ctx.setTransform(scale, 0, 0, scale, translatePos.x, translatePos.y);
ctx.fillStyle = '#000000';
// Draw containers and symbol dimensions
RenderContainers(
ctx,
mainContainer, mainContainer,
current.containers, selectorMode,
leftDim, bottomDim, topDim, rightDim, scale); selectedContainer,
selectedSymbol,
// Draw symbols and symbol dimensions
RenderSymbols(ctx, current, scale);
// Draw selector
switch (selectorMode) {
case SelectorMode.Containers:
RenderContainerSelector(ctx, frameCount, {
containers: current.containers, containers: current.containers,
scale, symbols: current.symbols
selected: selectedContainer };
});
break;
case SelectorMode.Symbols:
RenderSymbolSelector(ctx, frameCount, {
symbols: current.symbols,
scale,
selected: selectedSymbol
});
break;
}
ctx.restore(); if (USE_EXPERIMENTAL_CANVAS_API) {
}
return ( return (
<Canvas <Canvas
draw={Draw} className={className}
className={`ml-16 ${className}`}
width={window.innerWidth - BAR_WIDTH} width={window.innerWidth - BAR_WIDTH}
height={window.innerHeight} height={window.innerHeight}
drawParams={drawParams}
/> />
); );
} }
@ -147,14 +110,8 @@ export function Viewer({
viewerHeight={windowSize[1]} viewerHeight={windowSize[1]}
width={mainContainer.properties.width} width={mainContainer.properties.width}
height={mainContainer.properties.height} height={mainContainer.properties.height}
containers={current.containers} drawParams={drawParams}
selectedContainer={selectedContainer}
symbols={current.symbols}
selectedSymbol={selectedSymbol}
selectorMode={selectorMode}
selectContainer={selectContainer} selectContainer={selectContainer}
> />
{mainContainer}
</SVG>
); );
} }