Merged PR 366: Refactor Canvas, SVG and Viewer parameters
This commit is contained in:
parent
d40f97ad6f
commit
b2644a039e
4 changed files with 139 additions and 98 deletions
|
@ -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,
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const drawParams: DrawParams = {
|
||||||
|
mainContainer,
|
||||||
|
selectorMode,
|
||||||
|
selectedContainer,
|
||||||
|
selectedSymbol,
|
||||||
|
containers: current.containers,
|
||||||
|
symbols: current.symbols
|
||||||
|
};
|
||||||
|
|
||||||
if (USE_EXPERIMENTAL_CANVAS_API) {
|
if (USE_EXPERIMENTAL_CANVAS_API) {
|
||||||
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,
|
|
||||||
current.containers,
|
|
||||||
leftDim, bottomDim, topDim, rightDim, scale);
|
|
||||||
|
|
||||||
// Draw symbols and symbol dimensions
|
|
||||||
RenderSymbols(ctx, current, scale);
|
|
||||||
|
|
||||||
// Draw selector
|
|
||||||
switch (selectorMode) {
|
|
||||||
case SelectorMode.Containers:
|
|
||||||
RenderContainerSelector(ctx, frameCount, {
|
|
||||||
containers: current.containers,
|
|
||||||
scale,
|
|
||||||
selected: selectedContainer
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case SelectorMode.Symbols:
|
|
||||||
RenderSymbolSelector(ctx, frameCount, {
|
|
||||||
symbols: current.symbols,
|
|
||||||
scale,
|
|
||||||
selected: selectedSymbol
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.restore();
|
|
||||||
}
|
|
||||||
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>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue