import * as React from 'react'; import { type IContainerModel } from '../../Interfaces/IContainerModel'; import { type IHistoryState } from '../../Interfaces/IHistoryState'; import { type IPoint } from '../../Interfaces/IPoint'; import { DIMENSION_MARGIN, USE_EXPERIMENTAL_CANVAS_API } from '../../utils/default'; import { FindContainerById, MakeRecursionDFSIterator } from '../../utils/itertools'; import { BAR_WIDTH } from '../Bar/Bar'; import { Canvas } from '../Canvas/Canvas'; import { AddDimensions } from '../Canvas/DimensionLayer'; import { RenderSelector } from '../Canvas/Selector'; import { SVG } from '../SVG/SVG'; import { RenderSymbol } from '../Canvas/Symbol'; import { useState } from 'react'; interface IViewerProps { className?: string current: IHistoryState selectedContainer: IContainerModel | undefined selectContainer: (containerId: string) => void margin: number } export function Viewer({ className, current, selectedContainer, selectContainer, margin }: IViewerProps): JSX.Element { function computeWidth(margin: number): number { return window.innerWidth - (window.innerWidth < 768 ? BAR_WIDTH : margin); } const [windowSize, setWindowSize] = useState([ computeWidth(margin), window.innerHeight ]); React.useEffect(() => { function SVGAutoResizer(): void { setWindowSize([ computeWidth(margin), window.innerHeight ]); } window.addEventListener('resize', SVGAutoResizer); return () => { window.removeEventListener('resize', SVGAutoResizer); }; }); React.useEffect(() => { setWindowSize([ computeWidth(margin), window.innerHeight ]); }, [margin]); const mainContainer = FindContainerById(current.containers, current.mainContainer); if (mainContainer === undefined) { return <>; } 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'; const it = MakeRecursionDFSIterator(mainContainer, current.containers, 0, [0, 0]); for (const { container, depth, currentTransform } of it) { const [x, y] = [ container.properties.x + currentTransform[0], container.properties.y + currentTransform[1] ]; // Draw container RenderContainers(ctx, container, x, y); // Draw dimensions RenderDimensions( ctx, leftDim, bottomDim, topDim, rightDim, depth, scale, current.containers, container, currentTransform ); // Draw selector RenderSelector(ctx, frameCount, { containers: current.containers, scale, selected: selectedContainer }); } // Draw symbols RenderSymbols(current, ctx, scale); ctx.restore(); } return ( ); } return ( {mainContainer} ); } function RenderSymbols( current: IHistoryState, ctx: CanvasRenderingContext2D, scale: number ): void { current.symbols.forEach((symbol) => { RenderSymbol(symbol, ctx, scale); }); } function RenderDimensions( ctx: CanvasRenderingContext2D, leftDim: number, bottomDim: number, topDim: number, rightDim: number, depth: number, scale: number, containers: Map, container: IContainerModel, currentTransform: [number, number] ): void { ctx.save(); const depthOffset = (DIMENSION_MARGIN * (depth + 1)) / scale; const containerLeftDim = leftDim - depthOffset; const containerTopDim = topDim - depthOffset; const containerBottomDim = bottomDim + depthOffset; const containerRightDim = rightDim + depthOffset; const dimMapped = [containerLeftDim, containerBottomDim, containerTopDim, containerRightDim]; AddDimensions(ctx, containers, container, dimMapped, currentTransform, scale, depth); ctx.restore(); } function RenderContainers(ctx: CanvasRenderingContext2D, container: IContainerModel, x: number, y: number): void { ctx.save(); ctx.strokeStyle = container.properties.style?.stroke ?? '#000000'; ctx.fillStyle = container.properties.style?.fill ?? '#000000'; ctx.lineWidth = Number(container.properties.style?.strokeWidth ?? 1); ctx.globalAlpha = Number(container.properties.style?.fillOpacity ?? 1); ctx.fillRect(x, y, container.properties.width, container.properties.height); ctx.globalAlpha = Number(container.properties.style?.strokeOpacity ?? 1); ctx.strokeRect(x, y, container.properties.width, container.properties.height); ctx.restore(); }