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 (
);
}
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();
}