From 2cb851866b828fb0c04f5dbe766d7387f5994d22 Mon Sep 17 00:00:00 2001 From: Eric Nguyen Date: Tue, 4 Oct 2022 13:25:07 +0000 Subject: [PATCH] Merged PR 209: Implement Symbols in Canvas mode --- src/Components/Canvas/Canvas.tsx | 3 +- src/Components/Canvas/Symbol.ts | 45 ++++++++++++++++++ src/Components/Viewer/Viewer.tsx | 79 ++++++++++++++++++++++++-------- src/utils/default.ts | 2 +- 4 files changed, 107 insertions(+), 22 deletions(-) create mode 100644 src/Components/Canvas/Symbol.ts diff --git a/src/Components/Canvas/Canvas.tsx b/src/Components/Canvas/Canvas.tsx index ca32b69..708b5cd 100644 --- a/src/Components/Canvas/Canvas.tsx +++ b/src/Components/Canvas/Canvas.tsx @@ -70,12 +70,11 @@ function UseCanvas(draw: (context: CanvasRenderingContext2D, frameCount: number, } draw(context, frameCount.current, scale.current, translatePos.current); - evt.preventDefault(); } canvas.addEventListener('mousedown', MouseDown); window.addEventListener('mouseup', MouseUp); canvas.addEventListener('mousemove', MouseMove); - canvas.addEventListener('wheel', HandleScroll); + canvas.addEventListener('wheel', HandleScroll, { passive: true }); function Render(): void { if (context === null) { diff --git a/src/Components/Canvas/Symbol.ts b/src/Components/Canvas/Symbol.ts new file mode 100644 index 0000000..96ca161 --- /dev/null +++ b/src/Components/Canvas/Symbol.ts @@ -0,0 +1,45 @@ +import { ISymbolModel } from '../../Interfaces/ISymbolModel'; +import { DIMENSION_MARGIN } from '../../utils/default'; + +const IMAGE_CACHE = new Map(); + +export function RenderSymbol( + symbol: ISymbolModel, + ctx: CanvasRenderingContext2D, + scale: number): void { + const href = symbol.config.Image.Base64Image ?? symbol.config.Image.Url; + + if (href === undefined) { + return; + } + const image: HTMLImageElement | undefined = IMAGE_CACHE.get(href); + + if (image === undefined) { + const newImage = new Image(); + newImage.src = href; + IMAGE_CACHE.set(href, newImage); + newImage.onload = () => { + DrawImage(ctx, scale, newImage, symbol); + }; + return; + } + + DrawImage(ctx, scale, image, symbol); +} +function DrawImage( + ctx: CanvasRenderingContext2D, + scale: number, + image: HTMLImageElement, + symbol: ISymbolModel +): void { + ctx.save(); + ctx.fillStyle = '#000000'; + ctx.drawImage( + image, + symbol.x, + -DIMENSION_MARGIN, + symbol.width, + symbol.height + ); + ctx.restore(); +} diff --git a/src/Components/Viewer/Viewer.tsx b/src/Components/Viewer/Viewer.tsx index a462c5e..7c23a29 100644 --- a/src/Components/Viewer/Viewer.tsx +++ b/src/Components/Viewer/Viewer.tsx @@ -9,6 +9,7 @@ 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'; interface IViewerProps { isLeftSidebarOpen: boolean @@ -107,9 +108,9 @@ export function Viewer({ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.save(); - ctx.translate(translatePos.x, translatePos.y); - ctx.scale(scale, scale); + ctx.setTransform(scale, 0, 0, scale, translatePos.x, translatePos.y); ctx.fillStyle = '#000000'; + const it = MakeRecursionDFSIterator(current.mainContainer, 0, [0, 0]); for (const { container, depth, currentTransform } of it) { const [x, y] = [ @@ -118,25 +119,20 @@ export function Viewer({ ]; // Draw container - 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.globalAlpha = 1; - ctx.lineWidth = 1; - ctx.fillStyle = '#000000'; - ctx.strokeStyle = '#000000'; + RenderContainers(ctx, container, x, y); // Draw dimensions - const containerLeftDim = leftDim - (DIMENSION_MARGIN * (depth + 1)) / scale; - const containerTopDim = topDim - (DIMENSION_MARGIN * (depth + 1)) / scale; - const containerBottomDim = bottomDim + (DIMENSION_MARGIN * (depth + 1)) / scale; - const containerRightDim = rightDim + (DIMENSION_MARGIN * (depth + 1)) / scale; - const dimMapped = [containerLeftDim, containerBottomDim, containerTopDim, containerRightDim]; - AddDimensions(ctx, container, dimMapped, currentTransform, scale, depth); + RenderDimensions( + ctx, + leftDim, + bottomDim, + topDim, + rightDim, + depth, + scale, + container, + currentTransform + ); // Draw selector RenderSelector(ctx, frameCount, { @@ -144,6 +140,9 @@ export function Viewer({ selected: selectedContainer }); } + + // Draw symbols + RenderSymbols(current, ctx, scale); ctx.restore(); } return ( @@ -171,3 +170,45 @@ export function Viewer({ ); } +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, + container: IContainerModel, + currentTransform: [number, number] +): void { + ctx.save(); + const containerLeftDim = leftDim - (DIMENSION_MARGIN * (depth + 1)) / scale; + const containerTopDim = topDim - (DIMENSION_MARGIN * (depth + 1)) / scale; + const containerBottomDim = bottomDim + (DIMENSION_MARGIN * (depth + 1)) / scale; + const containerRightDim = rightDim + (DIMENSION_MARGIN * (depth + 1)) / scale; + const dimMapped = [containerLeftDim, containerBottomDim, containerTopDim, containerRightDim]; + AddDimensions(ctx, 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(); +} diff --git a/src/utils/default.ts b/src/utils/default.ts index 5ffb68c..4d4a844 100644 --- a/src/utils/default.ts +++ b/src/utils/default.ts @@ -33,7 +33,7 @@ export const MAX_HISTORY = 200; export const APPLY_BEHAVIORS_ON_CHILDREN = true; /** Framerate of the svg controller (recommanded = 60) */ -export const MAX_FRAMERATE = 60; +export const MAX_FRAMERATE = 120; /// CONTAINER DEFAULTS ///