diff --git a/src/Components/Canvas/Container.ts b/src/Components/Canvas/Container.ts new file mode 100644 index 0000000..4914b4b --- /dev/null +++ b/src/Components/Canvas/Container.ts @@ -0,0 +1,18 @@ +import { type IContainerModel } from '../../Interfaces/IContainerModel'; + +export function RenderContainer( + 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/Components/Canvas/DimensionLayer.ts b/src/Components/Canvas/DimensionLayer.ts index bf4bc35..74a9d09 100644 --- a/src/Components/Canvas/DimensionLayer.ts +++ b/src/Components/Canvas/DimensionLayer.ts @@ -1,12 +1,14 @@ import { Orientation } from '../../Enums/Orientation'; import { Position } from '../../Enums/Position'; import { type IContainerModel } from '../../Interfaces/IContainerModel'; -import { SHOW_SELF_DIMENSIONS, SHOW_BORROWER_DIMENSIONS, SHOW_CHILDREN_DIMENSIONS } from '../../utils/default'; +import { type ISymbolModel } from '../../Interfaces/ISymbolModel'; +import { SHOW_SELF_DIMENSIONS, SHOW_BORROWER_DIMENSIONS, SHOW_CHILDREN_DIMENSIONS, DIMENSION_MARGIN } from '../../utils/default'; import { FindContainerById, MakeRecursionDFSIterator, Pairwise } from '../../utils/itertools'; import { TransformX, TransformY } from '../../utils/svg'; +import { type IDimensionStyle } from '../SVG/Elements/Dimension'; import { RenderDimension } from './Dimension'; -export function AddDimensions( +export function AddContainerDimensions( ctx: CanvasRenderingContext2D, containers: Map, container: IContainerModel, @@ -66,6 +68,20 @@ export function AddDimensions( } } +export function AddSymbolDimensions( + ctx: CanvasRenderingContext2D, + symbol: ISymbolModel, + scale: number, + depth: number +): void { + AddHorizontalSymbolDimension( + ctx, + symbol, + scale, + depth + ); +} + /** * Fonction that call another function given the positions * @param dimMapped Position mapped depending on the Position enum in order: @@ -420,3 +436,39 @@ function AddHorizontalSelfDimension( style }); } + +function AddHorizontalSymbolDimension( + ctx: CanvasRenderingContext2D, + symbol: ISymbolModel, + scale: number, + depth: number +): void { + const width = symbol.x + (symbol.width / 2); + + if (width == null || width <= 0) { + return; + } + + const id = `dim-y-margin-left${symbol.width.toFixed(0)}-${symbol.id}`; + + const offset = (DIMENSION_MARGIN * (depth + 1)) / scale; + const text = width + .toFixed(0) + .toString(); + + // TODO: Put this in default.ts + const defaultDimensionSymbolStyle: IDimensionStyle = { + color: 'black' + }; + + RenderDimension(ctx, { + id, + xStart: 0, + yStart: -offset, + xEnd: width, + yEnd: -offset, + text, + scale, + style: defaultDimensionSymbolStyle + }); +} diff --git a/src/Components/Canvas/Renderer.ts b/src/Components/Canvas/Renderer.ts index d325eed..82f3ea1 100644 --- a/src/Components/Canvas/Renderer.ts +++ b/src/Components/Canvas/Renderer.ts @@ -1,10 +1,49 @@ import { type IContainerModel } from '../../Interfaces/IContainerModel'; import { type IHistoryState } from '../../Interfaces/IHistoryState'; +import { ISymbolModel } from '../../Interfaces/ISymbolModel'; import { DIMENSION_MARGIN } from '../../utils/default'; -import { AddDimensions } from './DimensionLayer'; +import { MakeRecursionDFSIterator } from '../../utils/itertools'; +import { RenderContainer } from './Container'; +import { AddContainerDimensions, AddSymbolDimensions } from './DimensionLayer'; import { RenderSymbol } from './Symbol'; -export function RenderDimensions( +export function RenderContainers( + ctx: CanvasRenderingContext2D, + root: IContainerModel, + containers: Map, + leftDim: number, + bottomDim: number, + topDim: number, + rightDim: number, + scale: number +): void { + const it = MakeRecursionDFSIterator(root, 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 + RenderContainer(ctx, container, x, y); + + // Draw dimensions + RenderContainerDimensions( + ctx, + leftDim, + bottomDim, + topDim, + rightDim, + depth, + scale, + containers, + container, + currentTransform + ); + } +} + +export function RenderContainerDimensions( ctx: CanvasRenderingContext2D, leftDim: number, bottomDim: number, @@ -23,33 +62,43 @@ export function RenderDimensions( const containerBottomDim = bottomDim + depthOffset; const containerRightDim = rightDim + depthOffset; const dimMapped = [containerLeftDim, containerBottomDim, containerTopDim, containerRightDim]; - AddDimensions(ctx, containers, container, dimMapped, currentTransform, scale, depth); + AddContainerDimensions(ctx, containers, container, dimMapped, currentTransform, scale, depth); ctx.restore(); } export function RenderSymbols( - current: IHistoryState, ctx: CanvasRenderingContext2D, + current: IHistoryState, scale: number ): void { - current.symbols.forEach((symbol) => { - RenderSymbol(symbol, ctx, scale); + let count = 0; + current.symbols.forEach((symbol: ISymbolModel) => { + RenderSymbol(ctx, symbol, scale); + + if (!symbol.showDimension) { + return; + } + + AddSymbolDimensions(ctx, symbol, scale, count); + count++; }); } -export function RenderContainers( +export function RenderSymbolDimensions( ctx: CanvasRenderingContext2D, + depth: number, + scale: number, + containers: Map, container: IContainerModel, - x: number, - y: number + currentTransform: [number, 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); + const depthOffset = (DIMENSION_MARGIN * (depth + 1)) / scale; + const containerLeftDim = -depthOffset; + const containerTopDim = -depthOffset; + const containerBottomDim = depthOffset; + const containerRightDim = depthOffset; + const dimMapped = [containerLeftDim, containerBottomDim, containerTopDim, containerRightDim]; + AddContainerDimensions(ctx, containers, container, dimMapped, currentTransform, scale, depth); ctx.restore(); } diff --git a/src/Components/Canvas/Symbol.ts b/src/Components/Canvas/Symbol.ts index 96ca161..ced9593 100644 --- a/src/Components/Canvas/Symbol.ts +++ b/src/Components/Canvas/Symbol.ts @@ -4,8 +4,8 @@ import { DIMENSION_MARGIN } from '../../utils/default'; const IMAGE_CACHE = new Map(); export function RenderSymbol( - symbol: ISymbolModel, ctx: CanvasRenderingContext2D, + symbol: ISymbolModel, scale: number): void { const href = symbol.config.Image.Base64Image ?? symbol.config.Image.Url; diff --git a/src/Components/Viewer/Viewer.tsx b/src/Components/Viewer/Viewer.tsx index 5128b0d..af9dc8e 100644 --- a/src/Components/Viewer/Viewer.tsx +++ b/src/Components/Viewer/Viewer.tsx @@ -10,7 +10,8 @@ import { RenderSelector } from '../Canvas/Selector'; import { SelectorMode, SVG } from '../SVG/SVG'; import { useState } from 'react'; import { type ISymbolModel } from '../../Interfaces/ISymbolModel'; -import { RenderContainers, RenderDimensions, RenderSymbols } from '../Canvas/Renderer'; +import { RenderContainers, RenderContainerDimensions, RenderSymbols } from '../Canvas/Renderer'; +import { RenderContainer } from '../Canvas/Container'; interface IViewerProps { className: string @@ -78,7 +79,12 @@ export function Viewer({ } if (USE_EXPERIMENTAL_CANVAS_API) { - function Draw(ctx: CanvasRenderingContext2D, frameCount: number, scale: number, translatePos: IPoint): void { + function Draw( + ctx: CanvasRenderingContext2D, + frameCount: number, + scale: number, + translatePos: IPoint + ): void { if (mainContainer === undefined) { return; } @@ -93,30 +99,12 @@ export function Viewer({ 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 containers and symbol dimensions + RenderContainers( + ctx, + mainContainer, + current.containers, + leftDim, bottomDim, topDim, rightDim, scale); // Draw selector RenderSelector(ctx, frameCount, { @@ -124,8 +112,8 @@ export function Viewer({ scale, selected: selectedContainer }); - // Draw symbols - RenderSymbols(current, ctx, scale); + // Draw symbols and symbol dimensions + RenderSymbols(ctx, current, scale); ctx.restore(); } return (