From 79caa5e9abe1e5f1fa141d330e573ddb1d353184 Mon Sep 17 00:00:00 2001 From: Carl Fuchs Date: Thu, 9 Feb 2023 17:25:55 +0100 Subject: [PATCH 01/34] WIP --- src/Components/Canvas/Symbol.ts | 2 +- .../SVG/Elements/DimensionLayer.tsx | 2 +- .../SelectorSymbol/SelectorSymbol.tsx | 2 +- src/Components/SVG/Elements/Symbol.tsx | 7 +++--- .../SymbolProperties/SymbolForm.tsx | 25 ++++++++++++------- src/Interfaces/IAvailableSymbol.ts | 10 ++++---- src/Interfaces/ISymbolModel.ts | 8 +++--- src/utils/default.ts | 4 ++- 8 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/Components/Canvas/Symbol.ts b/src/Components/Canvas/Symbol.ts index 96ca161..752eb66 100644 --- a/src/Components/Canvas/Symbol.ts +++ b/src/Components/Canvas/Symbol.ts @@ -36,7 +36,7 @@ function DrawImage( ctx.fillStyle = '#000000'; ctx.drawImage( image, - symbol.x, + symbol.offset, -DIMENSION_MARGIN, symbol.width, symbol.height diff --git a/src/Components/SVG/Elements/DimensionLayer.tsx b/src/Components/SVG/Elements/DimensionLayer.tsx index 62d8bef..e8f5df3 100644 --- a/src/Components/SVG/Elements/DimensionLayer.tsx +++ b/src/Components/SVG/Elements/DimensionLayer.tsx @@ -169,7 +169,7 @@ function AddHorizontalSymbolDimension(symbol: ISymbolModel, color: string, depth: number ): void { - const width = symbol.x + (symbol.width / 2); + const width = symbol.offset + (symbol.width / 2); if (width != null && width > 0) { const id = `dim-y-margin-left${symbol.width.toFixed(0)}-${symbol.id}`; diff --git a/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx b/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx index 2cdce3b..4b6899e 100644 --- a/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx +++ b/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx @@ -23,7 +23,7 @@ export function SelectorSymbol(props: ISelectorSymbolProps): JSX.Element { props.selected.height / scale ]; - const [x, y] = [props.selected.x, -SYMBOL_MARGIN - height]; + const [x, y] = [props.selected.offset, -SYMBOL_MARGIN - height]; const xText = x + width / 2; const yText = y + height / 2; diff --git a/src/Components/SVG/Elements/Symbol.tsx b/src/Components/SVG/Elements/Symbol.tsx index 09a19f9..a2b1e1b 100644 --- a/src/Components/SVG/Elements/Symbol.tsx +++ b/src/Components/SVG/Elements/Symbol.tsx @@ -1,6 +1,6 @@ import { Interweave } from 'interweave'; import * as React from 'react'; -import { ISymbolModel } from '../../../Interfaces/ISymbolModel'; +import { type ISymbolModel } from '../../../Interfaces/ISymbolModel'; import { DIMENSION_MARGIN, SYMBOL_MARGIN } from '../../../utils/default'; interface ISymbolProps { @@ -12,10 +12,11 @@ export function Symbol(props: ISymbolProps): JSX.Element { const href = props.model.config.Image.Base64Image ?? props.model.config.Image.Url; const hasSVG = props.model.config.Image.Svg !== undefined && props.model.config.Image.Svg !== null; + if (hasSVG) { return ( diff --git a/src/Components/SymbolProperties/SymbolForm.tsx b/src/Components/SymbolProperties/SymbolForm.tsx index 9ffc727..fe0efeb 100644 --- a/src/Components/SymbolProperties/SymbolForm.tsx +++ b/src/Components/SymbolProperties/SymbolForm.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; -import { ISymbolModel } from '../../Interfaces/ISymbolModel'; -import { RestoreX, TransformX } from '../../utils/svg'; +import { type ISymbolModel } from '../../Interfaces/ISymbolModel'; +import { RestoreX, RestoreY, TransformX, TransformY } from '../../utils/svg'; import { InputGroup } from '../InputGroup/InputGroup'; import { TextInputGroup } from '../InputGroup/TextInputGroup'; import { Text } from '../Text/Text'; @@ -32,16 +32,23 @@ export function SymbolForm(props: ISymbolFormProps): JSX.Element { inputClassName='' type='string' value={props.symbol.displayedText} - onChange={(value) => props.onChange('displayedText', value)} /> + onChange={(value) => { props.onChange('displayedText', value); }} /> props.onChange('x', RestoreX(Number(value), props.symbol.width, props.symbol.config.PositionReference))} /> + value={TransformX(props.symbol.offset, props.symbol.width, props.symbol.config.PositionReference).toString()} + onChange={(value) => { props.onChange('offset', RestoreX(Number(value), props.symbol.width, props.symbol.config.PositionReference)); }} /> + { props.onChange('isVertical', e.target.checked); }}/> props.onChange('height', Number(value))} /> + onChange={(value) => { props.onChange('height', Number(value)); }} /> props.onChange('width', Number(value))} /> + onChange={(value) => { props.onChange('width', Number(value)); }} /> props.onChange('showDimension', e.target.checked)}/> + onChange={(e) => { props.onChange('showDimension', e.target.checked); }}/> ); } diff --git a/src/Interfaces/IAvailableSymbol.ts b/src/Interfaces/IAvailableSymbol.ts index e69a996..fe085a6 100644 --- a/src/Interfaces/IAvailableSymbol.ts +++ b/src/Interfaces/IAvailableSymbol.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { PositionReference } from '../Enums/PositionReference'; -import { IAvailableContainer } from './IAvailableContainer'; -import { IImage } from './IImage'; +import { type PositionReference } from '../Enums/PositionReference'; +import { type IAvailableContainer } from './IAvailableContainer'; +import { type IImage } from './IImage'; /** * Model of available symbol to configure the application */ @@ -13,9 +13,9 @@ export interface IAvailableSymbol { /** displayed text */ DisplayedText?: string - X?: number + isVertical?: boolean - Y?: number + offset?: number Width?: number diff --git a/src/Interfaces/ISymbolModel.ts b/src/Interfaces/ISymbolModel.ts index 3a71290..ff91b00 100644 --- a/src/Interfaces/ISymbolModel.ts +++ b/src/Interfaces/ISymbolModel.ts @@ -1,4 +1,4 @@ -import { IAvailableSymbol } from './IAvailableSymbol'; +import { type IAvailableSymbol } from './IAvailableSymbol'; export interface ISymbolModel { /** Identifier */ @@ -13,10 +13,10 @@ export interface ISymbolModel { /** Configuration of the symbol */ config: IAvailableSymbol - /** Horizontal offset */ - x: number + isVertical: boolean - // TODO: Implement Y and verticality + /** offset */ + offset: number /** Width */ width: number diff --git a/src/utils/default.ts b/src/utils/default.ts index 632c12a..585d5a4 100644 --- a/src/utils/default.ts +++ b/src/utils/default.ts @@ -73,6 +73,7 @@ export const NOTCHES_LENGTH = 10; /// SYMBOL DEFAULTS /// export const DEFAULT_SYMBOL_WIDTH = 32; +export const DEFAULT_SYMBOL_IS_VERTICAL = false; export const DEFAULT_SYMBOL_HEIGHT = 32; /** @@ -310,7 +311,8 @@ export function GetDefaultSymbolModel(name: string, displayedText: symbolConfig.DisplayedText ?? id, type: name, config: structuredClone(symbolConfig), - x: 0, + offset: 0, + isVertical : symbolConfig.isVertical ?? DEFAULT_SYMBOL_IS_VERTICAL, width: symbolConfig.Width ?? DEFAULT_SYMBOL_WIDTH, height: symbolConfig.Height ?? DEFAULT_SYMBOL_HEIGHT, linkedContainers: new Set(), From b09718d72df86ae47eb5df70c5c0ef34ca0466e6 Mon Sep 17 00:00:00 2001 From: Carl Fuchs Date: Fri, 10 Feb 2023 09:46:39 +0100 Subject: [PATCH 02/34] WIP2 --- .../Editor/Actions/SymbolOperations.ts | 17 +++++++++++------ .../Editor/Behaviors/SymbolBehaviors.ts | 2 +- src/Components/SymbolProperties/SymbolForm.tsx | 4 ++-- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/Components/Editor/Actions/SymbolOperations.ts b/src/Components/Editor/Actions/SymbolOperations.ts index 7464193..abff45f 100644 --- a/src/Components/Editor/Actions/SymbolOperations.ts +++ b/src/Components/Editor/Actions/SymbolOperations.ts @@ -1,10 +1,10 @@ -import { IConfiguration } from '../../../Interfaces/IConfiguration'; -import { IContainerModel } from '../../../Interfaces/IContainerModel'; -import { IHistoryState } from '../../../Interfaces/IHistoryState'; -import { ISymbolModel } from '../../../Interfaces/ISymbolModel'; +import { type IConfiguration } from '../../../Interfaces/IConfiguration'; +import { type IContainerModel } from '../../../Interfaces/IContainerModel'; +import { type IHistoryState } from '../../../Interfaces/IHistoryState'; +import { type ISymbolModel } from '../../../Interfaces/ISymbolModel'; import { GetDefaultSymbolModel } from '../../../utils/default'; import { FindContainerById } from '../../../utils/itertools'; -import { RestoreX } from '../../../utils/svg'; +import {RestoreX, RestoreY} from '../../../utils/svg'; import { ApplyBehaviors, ApplyBehaviorsOnSiblingsChildren } from '../Behaviors/Behaviors'; import { GetCurrentHistory, GetCurrentHistoryState, UpdateCounters } from '../Editor'; import { AddContainers } from './AddContainer'; @@ -32,7 +32,12 @@ export function AddSymbol( const newSymbols = structuredClone(current.symbols); const newSymbol: ISymbolModel = GetDefaultSymbolModel(name, typeCounters, type, symbolConfig); const containers = structuredClone(current.containers); - newSymbol.x = RestoreX(newSymbol.x, newSymbol.width, newSymbol.config.PositionReference); + + if (newSymbol.isVertical) { + newSymbol.offset = RestoreY(newSymbol.offset, newSymbol.height, newSymbol.config.PositionReference); + } else { + newSymbol.offset = RestoreX(newSymbol.offset, newSymbol.width, newSymbol.config.PositionReference); + } newSymbols.set(newSymbol.id, newSymbol); diff --git a/src/Components/Editor/Behaviors/SymbolBehaviors.ts b/src/Components/Editor/Behaviors/SymbolBehaviors.ts index 5efde19..7ece236 100644 --- a/src/Components/Editor/Behaviors/SymbolBehaviors.ts +++ b/src/Components/Editor/Behaviors/SymbolBehaviors.ts @@ -4,7 +4,7 @@ import { ApplyParentTransform, FindContainerById } from '../../../utils/itertool import { RestoreX, TransformX } from '../../../utils/svg'; export function ApplySymbol(containers: Map, container: IContainerModel, symbol: ISymbolModel): IContainerModel { - container.properties.x = TransformX(symbol.x, symbol.width, symbol.config.PositionReference); + container.properties.x = TransformX(symbol.offset, symbol.width, symbol.config.PositionReference); container.properties.x = RestoreX(container.properties.x, container.properties.width, container.properties.positionReference); const parent = FindContainerById(containers, container.properties.parentId); let x = 0; diff --git a/src/Components/SymbolProperties/SymbolForm.tsx b/src/Components/SymbolProperties/SymbolForm.tsx index fe0efeb..9b268fe 100644 --- a/src/Components/SymbolProperties/SymbolForm.tsx +++ b/src/Components/SymbolProperties/SymbolForm.tsx @@ -34,9 +34,9 @@ export function SymbolForm(props: ISymbolFormProps): JSX.Element { value={props.symbol.displayedText} onChange={(value) => { props.onChange('displayedText', value); }} /> Date: Fri, 10 Feb 2023 17:08:18 +0100 Subject: [PATCH 03/34] [Update] Poc symbol Y working --- .../Editor/Behaviors/SymbolBehaviors.ts | 34 ++++++--- .../SVG/Elements/DimensionLayer.tsx | 73 ++++++++++++++----- .../SelectorSymbol/SelectorSymbol.tsx | 10 ++- src/Components/SVG/Elements/Symbol.tsx | 26 +++++-- 4 files changed, 109 insertions(+), 34 deletions(-) diff --git a/src/Components/Editor/Behaviors/SymbolBehaviors.ts b/src/Components/Editor/Behaviors/SymbolBehaviors.ts index 7ece236..939b1f6 100644 --- a/src/Components/Editor/Behaviors/SymbolBehaviors.ts +++ b/src/Components/Editor/Behaviors/SymbolBehaviors.ts @@ -1,16 +1,28 @@ -import { IContainerModel } from '../../../Interfaces/IContainerModel'; -import { ISymbolModel } from '../../../Interfaces/ISymbolModel'; +import { type IContainerModel } from '../../../Interfaces/IContainerModel'; +import { type ISymbolModel } from '../../../Interfaces/ISymbolModel'; import { ApplyParentTransform, FindContainerById } from '../../../utils/itertools'; -import { RestoreX, TransformX } from '../../../utils/svg'; +import { RestoreX, RestoreY, TransformX, TransformY } from '../../../utils/svg'; export function ApplySymbol(containers: Map, container: IContainerModel, symbol: ISymbolModel): IContainerModel { - container.properties.x = TransformX(symbol.offset, symbol.width, symbol.config.PositionReference); - container.properties.x = RestoreX(container.properties.x, container.properties.width, container.properties.positionReference); - const parent = FindContainerById(containers, container.properties.parentId); - let x = 0; - if (parent !== undefined && parent !== null) { - ([x] = ApplyParentTransform(containers, parent, container.properties.x, 0)); + if (symbol.isVertical) { + container.properties.y = TransformY(symbol.offset, symbol.height, symbol.config.PositionReference); + container.properties.y = RestoreY(container.properties.y, container.properties.height, container.properties.positionReference); + const parent = FindContainerById(containers, container.properties.parentId); + let y = 0; + if (parent !== undefined && parent !== null) { + ([,y] = ApplyParentTransform(containers, parent, 0, container.properties.y)); + } + container.properties.y = y; + return container; + } else { + container.properties.x = TransformX(symbol.offset, symbol.width, symbol.config.PositionReference); + container.properties.x = RestoreX(container.properties.x, container.properties.width, container.properties.positionReference); + const parent = FindContainerById(containers, container.properties.parentId); + let x = 0; + if (parent !== undefined && parent !== null) { + ([x] = ApplyParentTransform(containers, parent, container.properties.x, 0)); + } + container.properties.x = x; + return container; } - container.properties.x = x; - return container; } diff --git a/src/Components/SVG/Elements/DimensionLayer.tsx b/src/Components/SVG/Elements/DimensionLayer.tsx index e8f5df3..6c5ad56 100644 --- a/src/Components/SVG/Elements/DimensionLayer.tsx +++ b/src/Components/SVG/Elements/DimensionLayer.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { Orientation } from '../../../Enums/Orientation'; import { Position } from '../../../Enums/Position'; -import { IContainerModel } from '../../../Interfaces/IContainerModel'; +import { type IContainerModel } from '../../../Interfaces/IContainerModel'; import { DIMENSION_MARGIN, SHOW_BORROWER_DIMENSIONS, @@ -12,7 +12,7 @@ import { import { FindContainerById, MakeRecursionDFSIterator, Pairwise } from '../../../utils/itertools'; import { TransformX, TransformY } from '../../../utils/svg'; import { Dimension } from './Dimension'; -import { ISymbolModel } from '../../../Interfaces/ISymbolModel'; +import { type ISymbolModel } from '../../../Interfaces/ISymbolModel'; interface IDimensionLayerProps { containers: Map @@ -37,12 +37,13 @@ function ActionByPosition( horizontalAction: (dim: number, ...params: any[]) => void, verticalAction: (dim: number, isRight: boolean, ...params: any[]) => void, params: any[] -): boolean { - let incrementDepthSymbols = false; +): [boolean, boolean] { + let [incrementHorizontalDepthSymbols, incrementVerticalDepthSymbols] = [false, false]; positions.forEach((position: Position) => { const dim = dimMapped[position]; switch (position) { case Position.Left: + incrementVerticalDepthSymbols = true; case Position.Right: { const isRight = position === Position.Right; verticalAction(dim, isRight, ...params); @@ -50,12 +51,12 @@ function ActionByPosition( } case Position.Down: case Position.Up: - incrementDepthSymbols = true; + incrementHorizontalDepthSymbols = true; horizontalAction(dim, ...params); break; } }); - return incrementDepthSymbols; + return [incrementHorizontalDepthSymbols, incrementVerticalDepthSymbols]; } /** @@ -74,7 +75,7 @@ function Dimensions({ containers, symbols, root, scale }: IDimensionLayerProps): if (!SHOW_SELF_DIMENSIONS) { return []; } - let startDepthSymbols: number = 0; + let [startDepthHorizontalSymbols, startDepthVerticalSymbols] = [0, 0]; for (const { container, depth, currentTransform } of it) { const offset = (DIMENSION_MARGIN * (depth + 1)) / scale; @@ -84,7 +85,7 @@ function Dimensions({ containers, symbols, root, scale }: IDimensionLayerProps): const containerRightDim = rightDim + offset; const dimMapped = [containerLeftDim, containerBottomDim, containerTopDim, containerRightDim]; if (SHOW_SELF_DIMENSIONS && container.properties.dimensionOptions.selfDimensions.positions.length > 0) { - const incrementDepthSymbol = ActionByPosition( + const [incrementHorizontalDepthSymbol, incrementVerticalDepthSymbol] = ActionByPosition( dimMapped, container.properties.dimensionOptions.selfDimensions.positions, AddHorizontalSelfDimension, @@ -96,11 +97,12 @@ function Dimensions({ containers, symbols, root, scale }: IDimensionLayerProps): scale, container.properties.dimensionOptions.selfDimensions.color] ); - if (incrementDepthSymbol) { startDepthSymbols++; } + if (incrementHorizontalDepthSymbol) { startDepthHorizontalSymbols++; } + if (incrementVerticalDepthSymbol) { startDepthVerticalSymbols++; } } if (SHOW_SELF_MARGINS_DIMENSIONS && container.properties.dimensionOptions.selfMarginsDimensions.positions.length > 0) { - const incrementDepthSymbol = ActionByPosition( + const [incrementHorizontalDepthSymbol, incrementVerticalDepthSymbol] = ActionByPosition( dimMapped, container.properties.dimensionOptions.selfMarginsDimensions.positions, AddHorizontalSelfMarginsDimension, @@ -112,11 +114,12 @@ function Dimensions({ containers, symbols, root, scale }: IDimensionLayerProps): scale, container.properties.dimensionOptions.selfMarginsDimensions.color] ); - if (incrementDepthSymbol) { startDepthSymbols++; } + if (incrementHorizontalDepthSymbol) { startDepthHorizontalSymbols++; } + if (incrementVerticalDepthSymbol) { startDepthVerticalSymbols++; } } if (SHOW_BORROWER_DIMENSIONS && container.properties.dimensionOptions.dimensionWithMarks.positions.length > 0) { - const incrementDepthSymbol = ActionByPosition( + const [incrementHorizontalDepthSymbol, incrementVerticalDepthSymbol] = ActionByPosition( dimMapped, container.properties.dimensionOptions.dimensionWithMarks.positions, @@ -131,11 +134,12 @@ function Dimensions({ containers, symbols, root, scale }: IDimensionLayerProps): scale, container.properties.dimensionOptions.dimensionWithMarks.color] ); - if (incrementDepthSymbol) { startDepthSymbols++; } + if (incrementHorizontalDepthSymbol) { startDepthHorizontalSymbols++; } + if (incrementVerticalDepthSymbol) { startDepthVerticalSymbols++; } } if (SHOW_CHILDREN_DIMENSIONS && container.properties.dimensionOptions.childrenDimensions.positions.length > 0 && container.children.length >= 2) { - const incrementDepthSymbol = ActionByPosition( + const [incrementHorizontalDepthSymbol, incrementVerticalDepthSymbol] = ActionByPosition( dimMapped, container.properties.dimensionOptions.childrenDimensions.positions, AddHorizontalChildrenDimension, @@ -149,14 +153,20 @@ function Dimensions({ containers, symbols, root, scale }: IDimensionLayerProps): container.properties.dimensionOptions.childrenDimensions.color] ); - if (incrementDepthSymbol) { startDepthSymbols++; } + if (incrementHorizontalDepthSymbol) { startDepthHorizontalSymbols++; } + if (incrementVerticalDepthSymbol) { startDepthVerticalSymbols++; } } } for (const symbol of symbols) { if (symbol[1].showDimension) { - startDepthSymbols++; - AddHorizontalSymbolDimension(symbol[1], dimensions, scale, 'black', startDepthSymbols); + startDepthHorizontalSymbols++; + + if (symbol[1].isVertical) { + AddVerticalSymbolDimension(symbol[1], dimensions, scale, 'black', startDepthVerticalSymbols); + } else { + AddHorizontalSymbolDimension(symbol[1], dimensions, scale, 'black', startDepthHorizontalSymbols); + } } } @@ -192,6 +202,35 @@ function AddHorizontalSymbolDimension(symbol: ISymbolModel, } } +function AddVerticalSymbolDimension(symbol: ISymbolModel, + dimensions: React.ReactNode[], + scale: number, + color: string, + depth: number +): void { + const height = symbol.offset + (symbol.height / 2); + if (height != null && height > 0) { + const id = `dim-x-margin-left${symbol.height.toFixed(0)}-${symbol.id}`; + + const offset = (DIMENSION_MARGIN * (depth + 1)) / scale; + const text = height + .toFixed(0) + .toString(); + dimensions.push( + + ); + } +} + /** * A layer containing all dimension * @param props diff --git a/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx b/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx index 4b6899e..6a27fd8 100644 --- a/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx +++ b/src/Components/SVG/Elements/SelectorSymbol/SelectorSymbol.tsx @@ -23,7 +23,15 @@ export function SelectorSymbol(props: ISelectorSymbolProps): JSX.Element { props.selected.height / scale ]; - const [x, y] = [props.selected.offset, -SYMBOL_MARGIN - height]; + let x, y: number; + + if (props.selected.isVertical) { + x = -SYMBOL_MARGIN; + y = props.selected.offset; + } else { + x = props.selected.offset; + y = -SYMBOL_MARGIN - height; + } const xText = x + width / 2; const yText = y + height / 2; diff --git a/src/Components/SVG/Elements/Symbol.tsx b/src/Components/SVG/Elements/Symbol.tsx index a2b1e1b..9595e8c 100644 --- a/src/Components/SVG/Elements/Symbol.tsx +++ b/src/Components/SVG/Elements/Symbol.tsx @@ -13,11 +13,20 @@ export function Symbol(props: ISymbolProps): JSX.Element { const hasSVG = props.model.config.Image.Svg !== undefined && props.model.config.Image.Svg !== null; + let x, y: number; + if (hasSVG) { + if (props.model.isVertical) { + x = -DIMENSION_MARGIN / props.scale; + y = props.model.offset; + } else { + x = props.model.offset; + y = -DIMENSION_MARGIN / props.scale; + } return ( ); } - + if (props.model.isVertical) { + x = -SYMBOL_MARGIN; + y = props.model.offset + props.model.width / 2; + } else { + x = props.model.offset + props.model.width / 2; + y = -SYMBOL_MARGIN; + } return ( ); From caa680b511433ed3243c0756d6a87300df00306c Mon Sep 17 00:00:00 2001 From: Eric NGUYEN Date: Fri, 17 Feb 2023 10:33:30 +0100 Subject: [PATCH 04/34] Update translations --- src/Translations/translation.en.json | 1 + src/Translations/translation.fr.json | 3 ++- src/Translations/translation.fr.kline.json | 11 +++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Translations/translation.en.json b/src/Translations/translation.en.json index 65d7410..844b572 100644 --- a/src/Translations/translation.en.json +++ b/src/Translations/translation.en.json @@ -22,6 +22,7 @@ "@DeleteContainerTitle": "Delete the container", "@DeleteSymbol": "Delete", "@DeleteSymbolTitle": "Delete the container", + "@ReplaceByContainer": "Replace by component", "@ExportAsJSON": "Export as JSON", "@ExportAsSVG": "Export as SVG", diff --git a/src/Translations/translation.fr.json b/src/Translations/translation.fr.json index 3d2ce91..6d01aef 100644 --- a/src/Translations/translation.fr.json +++ b/src/Translations/translation.fr.json @@ -9,7 +9,7 @@ "@Symbols": "Symboles", "@SymbolsLeft": "Symboles", "@SymbolsRight": "Symboles", - "@NoSymbolSelected": "Pas de symbol sélectionné", + "@NoSymbolSelected": "Pas de symbole sélectionné", "@Timeline": "Chronologie", "@Messages": "Messages", "@Settings": "Paramètres", @@ -22,6 +22,7 @@ "@DeleteContainerTitle": "Supprimer le conteneur", "@DeleteSymbol": "Supprimer", "@DeleteSymbolTitle": "Supprimer le symbole", + "@ReplaceByContainer": "Replacer par un composant", "@ExportAsJSON": "Exporter en JSON", "@ExportAsSVG": "Exporter en SVG", diff --git a/src/Translations/translation.fr.kline.json b/src/Translations/translation.fr.kline.json index 3c005fe..09cface 100644 --- a/src/Translations/translation.fr.kline.json +++ b/src/Translations/translation.fr.kline.json @@ -2,12 +2,14 @@ "@StartFromScratch": "Partir de zéro", "@LoadConfigFile": "Charger un fichier de configuration", "@GoBack": "Revenir", + "@Properties": "Propriétés", "@Components": "Composants", "@Elements": "Éléments", "@Symbols": "Ancrages", "@SymbolsLeft": "Ancrages", "@SymbolsRight": "Ancrages", + "@NoSymbolSelected": "Pas d'ancre sélectionnée", "@Timeline": "Chronologie", "@Messages": "Messages", "@Settings": "Paramètres", @@ -61,9 +63,18 @@ "@ContainerShowChildrenDimension": "Afficher les cotations englobante des enfants", "@ContainerMarkPosition": "Marquer la position pour les parents", "@ContainerShowDimensionWithMarks": "Afficher les cotations avec les enfants marqués", + "@ContainerShowMarginsDimension": "Afficher les cotations des jeux", "@ContainerStyle": "Style", + "@StyleStrokeColor": "Couleur du tracé", + "@StyleStrokeDashArray": "Tableau de traits", + "@StyleStroke": "Tracé", + "@StyleStrokeOpacity": "Opacité du tracé", + "@StyleStrokeWidth": "Epaisseur du tracé", + "@StyleFill": "Remplissage", + "@StyleFillOpacity": "Opacité du remplissage", "@SymbolName": "Nom", + "@SymbolDisplayedText": "Texte affiché", "@SymbolX": "x", "@SymbolHeight": "Hauteur", "@SymbolWidth": "Largeur" From 4053763e44fef6597b5332049a55627851c2340a Mon Sep 17 00:00:00 2001 From: Eric NGUYEN Date: Wed, 25 Jan 2023 15:33:49 +0100 Subject: [PATCH 05/34] Implement #7978: Add double click event to rescale and replace the viewer --- src/Components/SVG/SVG.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Components/SVG/SVG.tsx b/src/Components/SVG/SVG.tsx index 4b49213..c56ce18 100644 --- a/src/Components/SVG/SVG.tsx +++ b/src/Components/SVG/SVG.tsx @@ -109,6 +109,9 @@ export function SVG(props: ISVGProps): JSX.Element { const value = event as Value; setScale(value.a); }} + onDoubleClick={() => { + svgViewer?.current?.setPointOnViewerCenter(props.width / 2, props.height / 2, 0.8); + }} background={'#ffffff'} defaultTool='pan' miniatureProps={{ @@ -131,6 +134,7 @@ export function SVG(props: ISVGProps): JSX.Element { function UseFitOnce(svgViewer: React.RefObject, width: number, height: number): void { React.useEffect(() => { - svgViewer?.current?.fitToViewer(); + // TODO: Fix this + svgViewer?.current?.setPointOnViewerCenter(width / 2, height / 2, 0.8); }, [svgViewer, width, height]); } From b3338b0167051800ec59b159c56faf92951e6d32 Mon Sep 17 00:00:00 2001 From: Eric NGUYEN Date: Fri, 17 Feb 2023 11:53:19 +0100 Subject: [PATCH 06/34] Add custom toolbar --- package.json | 1 + patches/@types+react-svg-pan-zoom+3.3.5.patch | 17 +++ src/Components/SVG/SVG.tsx | 2 + src/Components/SVG/SVGReactPanZoom/LICENSE | 21 +++ .../ui-toolbar/icon-cursor.tsx | 12 ++ .../SVGReactPanZoom/ui-toolbar/icon-fit.tsx | 12 ++ .../SVGReactPanZoom/ui-toolbar/icon-pan.tsx | 12 ++ .../ui-toolbar/icon-zoom-in.tsx | 15 ++ .../ui-toolbar/icon-zoom-out.tsx | 12 ++ .../ui-toolbar/toolbar-button.tsx | 81 +++++++++++ .../SVGReactPanZoom/ui-toolbar/toolbar.tsx | 134 ++++++++++++++++++ 11 files changed, 319 insertions(+) create mode 100644 patches/@types+react-svg-pan-zoom+3.3.5.patch create mode 100644 src/Components/SVG/SVGReactPanZoom/LICENSE create mode 100644 src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-cursor.tsx create mode 100644 src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-fit.tsx create mode 100644 src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-pan.tsx create mode 100644 src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-zoom-in.tsx create mode 100644 src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-zoom-out.tsx create mode 100644 src/Components/SVG/SVGReactPanZoom/ui-toolbar/toolbar-button.tsx create mode 100644 src/Components/SVG/SVGReactPanZoom/ui-toolbar/toolbar.tsx diff --git a/package.json b/package.json index ff96249..5cdc210 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "private": true, "version": "v1.0.0", "type": "module", + "postinstall": "npx patch-package", "scripts": { "d": "mprocs", "dev": "vite", diff --git a/patches/@types+react-svg-pan-zoom+3.3.5.patch b/patches/@types+react-svg-pan-zoom+3.3.5.patch new file mode 100644 index 0000000..b7fc8cc --- /dev/null +++ b/patches/@types+react-svg-pan-zoom+3.3.5.patch @@ -0,0 +1,17 @@ +diff --git a/node_modules/@types/react-svg-pan-zoom/index.d.ts b/node_modules/@types/react-svg-pan-zoom/index.d.ts +index a57d545..83ace9f 100644 +--- a/node_modules/@types/react-svg-pan-zoom/index.d.ts ++++ b/node_modules/@types/react-svg-pan-zoom/index.d.ts +@@ -256,7 +256,11 @@ export function zoom(value: Value, SVGPointX: number, SVGPointY: number, scaleFa + export function fitSelection( + value: Value, selectionSVGPointX: number, selectionSVGPointY: number, selectionWidth: number, selectionHeight: number): Value; + +-export function fitToViewer(value: Value): Value; ++export function fitToViewer( ++ value: Value, ++ SVGAlignX?: typeof ALIGN_CENTER | typeof ALIGN_LEFT | typeof ALIGN_RIGHT | undefined, ++ SVGAlignY?: typeof ALIGN_CENTER | typeof ALIGN_TOP | typeof ALIGN_BOTTOM | undefined ++): Value; + + export function zoomOnViewerCenter(value: Value, scaleFactor: number): Value; + diff --git a/src/Components/SVG/SVG.tsx b/src/Components/SVG/SVG.tsx index c56ce18..742bb67 100644 --- a/src/Components/SVG/SVG.tsx +++ b/src/Components/SVG/SVG.tsx @@ -8,6 +8,7 @@ import { SymbolLayer } from './Elements/SymbolLayer'; import { type ISymbolModel } from '../../Interfaces/ISymbolModel'; import { DimensionLayer } from './Elements/DimensionLayer'; import { SelectorSymbol } from './Elements/SelectorSymbol/SelectorSymbol'; +import { Toolbar } from './SVGReactPanZoom/ui-toolbar/Toolbar'; interface ISVGProps { className?: string @@ -120,6 +121,7 @@ export function SVG(props: ISVGProps): JSX.Element { width: 120, height: 120 }} + customToolbar={Toolbar} > {children} diff --git a/src/Components/SVG/SVGReactPanZoom/LICENSE b/src/Components/SVG/SVGReactPanZoom/LICENSE new file mode 100644 index 0000000..2f083c0 --- /dev/null +++ b/src/Components/SVG/SVGReactPanZoom/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 https://github.com/chrvadala + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-cursor.tsx b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-cursor.tsx new file mode 100644 index 0000000..554dc8e --- /dev/null +++ b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-cursor.tsx @@ -0,0 +1,12 @@ +import React from 'react'; + +// credits https://materialdesignicons.com/icon/cursor-default-outline + +export function IconCursor(): JSX.Element { + return ( + + + + ); +} diff --git a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-fit.tsx b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-fit.tsx new file mode 100644 index 0000000..5ad1472 --- /dev/null +++ b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-fit.tsx @@ -0,0 +1,12 @@ +import React from 'react'; + +//credits https://materialdesignicons.com/icon/cursor-default-outline + +export function IconFit(): JSX.Element { + return ( + + + + ); +} diff --git a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-pan.tsx b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-pan.tsx new file mode 100644 index 0000000..ad74de5 --- /dev/null +++ b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-pan.tsx @@ -0,0 +1,12 @@ +import React from 'react'; + +//https://materialdesignicons.com/icon/cursor-move + +export function IconPan(): JSX.Element { + return ( + + + + ); +} diff --git a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-zoom-in.tsx b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-zoom-in.tsx new file mode 100644 index 0000000..40a2edc --- /dev/null +++ b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-zoom-in.tsx @@ -0,0 +1,15 @@ +import React from 'react'; + +//https://material.io/icons/#ic_zoom_in + +export function IconZoomIn(): JSX.Element { + return ( + + + + + + + ); +} diff --git a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-zoom-out.tsx b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-zoom-out.tsx new file mode 100644 index 0000000..0ccb97b --- /dev/null +++ b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-zoom-out.tsx @@ -0,0 +1,12 @@ +import React from 'react'; + +//https://material.io/icons/#ic_zoom_out + +export function IconZoomOut(): JSX.Element { + return ( + + + + ) +} diff --git a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/toolbar-button.tsx b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/toolbar-button.tsx new file mode 100644 index 0000000..91fed61 --- /dev/null +++ b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/toolbar-button.tsx @@ -0,0 +1,81 @@ +import React from 'react'; +import { POSITION_TOP, POSITION_BOTTOM } from 'react-svg-pan-zoom'; + +interface IToolbarButtonProps { + title: string + name: string + toolbarPosition: string + activeColor: string + onClick: (event: React.MouseEvent | React.TouchEvent) => void + active: boolean + children: JSX.Element | JSX.Element[] +} + +interface IToolbarButtonState { + hover: boolean +} + +export class ToolbarButton extends React.Component { + public state: IToolbarButtonState; + + constructor(props: IToolbarButtonProps) { + super(props); + this.state = { hover: false }; + } + + change(event: (React.MouseEvent | React.TouchEvent)): void { + event.preventDefault(); + event.stopPropagation(); + + switch (event.type) { + case 'mouseenter': + case 'touchstart': + this.setState({ hover: true }); + break; + case 'mouseleave': + case 'touchend': + case 'touchcancel': + this.setState({ hover: false }); + break; + default: + // noop + } + } + + render(): JSX.Element { + const style = { + display: 'block', + width: '24px', + height: '24px', + margin: [POSITION_TOP, POSITION_BOTTOM].includes(this.props.toolbarPosition) ? '2px 1px' : '1px 2px', + color: this.props.active || this.state.hover ? this.props.activeColor : '#FFF', + transition: 'color 200ms ease', + background: 'none', + padding: '0px', + border: '0px', + outline: '0px', + cursor: 'pointer' + }; + + return ( + + ); + } +} diff --git a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/toolbar.tsx b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/toolbar.tsx new file mode 100644 index 0000000..21d5a6b --- /dev/null +++ b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/toolbar.tsx @@ -0,0 +1,134 @@ +import React from 'react'; + +import { + fitToViewer, + POSITION_TOP, + POSITION_BOTTOM, + POSITION_LEFT, + POSITION_RIGHT, + TOOL_NONE, + TOOL_PAN, + TOOL_ZOOM_IN, + TOOL_ZOOM_OUT, + ALIGN_LEFT, + ALIGN_TOP, + type Value, + type Tool, + type ALIGN_BOTTOM, + type ALIGN_CENTER, + type ALIGN_RIGHT, + type ToolbarPosition +} from 'react-svg-pan-zoom'; +import { IconCursor } from './icon-cursor'; +import { IconFit } from './icon-fit'; +import { IconPan } from './icon-pan'; +import { IconZoomIn } from './icon-zoom-in'; +import { IconZoomOut } from './icon-zoom-out'; +import { ToolbarButton } from './toolbar-button'; + +interface IToolbarProps { + tool: Tool + value: Value + onChangeValue: (value: Value) => void + onChangeTool: (tool: Tool) => void + activeToolColor?: string + position?: ToolbarPosition | undefined + SVGAlignX?: typeof ALIGN_CENTER | typeof ALIGN_LEFT | typeof ALIGN_RIGHT | undefined + SVGAlignY?: typeof ALIGN_CENTER | typeof ALIGN_TOP | typeof ALIGN_BOTTOM | undefined +} + +export function Toolbar({ + tool, + value, + onChangeValue, + onChangeTool, + activeToolColor = '#1CA6FC', + position = POSITION_RIGHT, + SVGAlignX = ALIGN_LEFT, + SVGAlignY = ALIGN_TOP +}: IToolbarProps): JSX.Element { + function handleChangeTool(event: React.MouseEvent | React.TouchEvent, tool: Tool): void { + onChangeTool(tool); + event.stopPropagation(); + event.preventDefault(); + }; + + function handleFit(event: React.MouseEvent | React.TouchEvent): void { + onChangeValue(fitToViewer(value, SVGAlignX, SVGAlignY)); + event.stopPropagation(); + event.preventDefault(); + }; + + const isHorizontal = [POSITION_TOP, POSITION_BOTTOM].includes(position); + + const style: React.CSSProperties = { + // position + position: 'absolute', + transform: [POSITION_TOP, POSITION_BOTTOM].includes(position) ? 'translate(-50%, 0px)' : 'none', + top: [POSITION_LEFT, POSITION_RIGHT, POSITION_TOP].includes(position) ? '5px' : 'unset', + left: [POSITION_TOP, POSITION_BOTTOM].includes(position) ? '50%' : (POSITION_LEFT === position ? '5px' : 'unset'), + right: [POSITION_RIGHT].includes(position) ? '5px' : 'unset', + bottom: [POSITION_BOTTOM].includes(position) ? '5px' : 'unset', + + // inner styling + backgroundColor: 'rgba(19, 20, 22, 0.90)', + borderRadius: '2px', + display: 'flex', + flexDirection: isHorizontal ? 'row' : 'column', + padding: isHorizontal ? '1px 2px' : '2px 1px' + }; + + return ( +
+ { handleChangeTool(event, TOOL_NONE); } }> + + + + { handleChangeTool(event, TOOL_PAN); } }> + + + + { handleChangeTool(event, TOOL_ZOOM_IN); } }> + + + + { handleChangeTool(event, TOOL_ZOOM_OUT); } }> + + + + { handleFit(event); } }> + + +
+ ); +} From 14d74edf9361b603f123135952819f85a1c14978 Mon Sep 17 00:00:00 2001 From: Eric NGUYEN Date: Fri, 17 Feb 2023 11:54:12 +0100 Subject: [PATCH 07/34] Update react-svg-pan-zoom --- package.json | 2 +- pnpm-lock.yaml | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 5cdc210..f49dfef 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "interweave": "^13.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-svg-pan-zoom": "^3.11.0", + "react-svg-pan-zoom": "^3.12.1", "react-window": "^1.8.8", "sweetalert2": "^11.7.1", "sweetalert2-react-content": "^5.0.7" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 212f797..922995b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,7 +33,7 @@ specifiers: postcss: ^8.4.21 react: ^18.2.0 react-dom: ^18.2.0 - react-svg-pan-zoom: ^3.11.0 + react-svg-pan-zoom: ^3.12.1 react-window: ^1.8.8 sass: ^1.58.0 sweetalert2: ^11.7.1 @@ -49,7 +49,7 @@ dependencies: interweave: 13.0.0_react@18.2.0 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - react-svg-pan-zoom: 3.11.0_react@18.2.0 + react-svg-pan-zoom: 3.12.1 react-window: 1.8.8_biqbaboplfbrettd7655fr4n2y sweetalert2: 11.7.1 sweetalert2-react-content: 5.0.7_5cbezu6w3tvev2ldv5vdmnpfca @@ -3453,13 +3453,10 @@ packages: engines: {node: '>=0.10.0'} dev: true - /react-svg-pan-zoom/3.11.0_react@18.2.0: - resolution: {integrity: sha512-xK2tpfp4YksHOfyMZH5zXP52ARLSBgkoJgWNJmJ1B+6O1tkuf23TQp7Q4m9GG5IRSK5KWO0JEGEWlNYG9+iiug==} - peerDependencies: - react: '>=17.0.0' + /react-svg-pan-zoom/3.12.1: + resolution: {integrity: sha512-ug1LHCN5qed56C64xFypr/ClajuMFkig1OKvwJrIgGeSyHOjWM7XGgSgeP3IfHAkNw8QEc6a31ggZRpTijWYRw==} dependencies: prop-types: 15.8.1 - react: 18.2.0 transformation-matrix: 2.14.0 dev: false From 4bb9e44b847670ae2e9084f97aaa8a9a7d323383 Mon Sep 17 00:00:00 2001 From: Eric NGUYEN Date: Fri, 17 Feb 2023 12:03:05 +0100 Subject: [PATCH 08/34] Changed the icons in the toolbar --- src/Components/SVG/SVG.tsx | 2 +- .../SVGReactPanZoom/ui-toolbar/icon-cursor.tsx | 12 ------------ .../SVG/SVGReactPanZoom/ui-toolbar/icon-fit.tsx | 12 ------------ .../SVG/SVGReactPanZoom/ui-toolbar/icon-pan.tsx | 12 ------------ .../SVGReactPanZoom/ui-toolbar/icon-zoom-in.tsx | 15 --------------- .../SVGReactPanZoom/ui-toolbar/icon-zoom-out.tsx | 12 ------------ .../SVG/SVGReactPanZoom/ui-toolbar/toolbar.tsx | 16 ++++++---------- 7 files changed, 7 insertions(+), 74 deletions(-) delete mode 100644 src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-cursor.tsx delete mode 100644 src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-fit.tsx delete mode 100644 src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-pan.tsx delete mode 100644 src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-zoom-in.tsx delete mode 100644 src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-zoom-out.tsx diff --git a/src/Components/SVG/SVG.tsx b/src/Components/SVG/SVG.tsx index 742bb67..69cd0d0 100644 --- a/src/Components/SVG/SVG.tsx +++ b/src/Components/SVG/SVG.tsx @@ -8,7 +8,7 @@ import { SymbolLayer } from './Elements/SymbolLayer'; import { type ISymbolModel } from '../../Interfaces/ISymbolModel'; import { DimensionLayer } from './Elements/DimensionLayer'; import { SelectorSymbol } from './Elements/SelectorSymbol/SelectorSymbol'; -import { Toolbar } from './SVGReactPanZoom/ui-toolbar/Toolbar'; +import { Toolbar } from './SVGReactPanZoom/ui-toolbar/toolbar'; interface ISVGProps { className?: string diff --git a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-cursor.tsx b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-cursor.tsx deleted file mode 100644 index 554dc8e..0000000 --- a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-cursor.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; - -// credits https://materialdesignicons.com/icon/cursor-default-outline - -export function IconCursor(): JSX.Element { - return ( - - - - ); -} diff --git a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-fit.tsx b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-fit.tsx deleted file mode 100644 index 5ad1472..0000000 --- a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-fit.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; - -//credits https://materialdesignicons.com/icon/cursor-default-outline - -export function IconFit(): JSX.Element { - return ( - - - - ); -} diff --git a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-pan.tsx b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-pan.tsx deleted file mode 100644 index ad74de5..0000000 --- a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-pan.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; - -//https://materialdesignicons.com/icon/cursor-move - -export function IconPan(): JSX.Element { - return ( - - - - ); -} diff --git a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-zoom-in.tsx b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-zoom-in.tsx deleted file mode 100644 index 40a2edc..0000000 --- a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-zoom-in.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; - -//https://material.io/icons/#ic_zoom_in - -export function IconZoomIn(): JSX.Element { - return ( - - - - - - - ); -} diff --git a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-zoom-out.tsx b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-zoom-out.tsx deleted file mode 100644 index 0ccb97b..0000000 --- a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/icon-zoom-out.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; - -//https://material.io/icons/#ic_zoom_out - -export function IconZoomOut(): JSX.Element { - return ( - - - - ) -} diff --git a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/toolbar.tsx b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/toolbar.tsx index 21d5a6b..39a801e 100644 --- a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/toolbar.tsx +++ b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/toolbar.tsx @@ -1,3 +1,4 @@ +import { ArrowsPointingOutIcon, CursorArrowRaysIcon, HandRaisedIcon, MagnifyingGlassMinusIcon, MagnifyingGlassPlusIcon } from '@heroicons/react/24/outline'; import React from 'react'; import { @@ -19,11 +20,6 @@ import { type ALIGN_RIGHT, type ToolbarPosition } from 'react-svg-pan-zoom'; -import { IconCursor } from './icon-cursor'; -import { IconFit } from './icon-fit'; -import { IconPan } from './icon-pan'; -import { IconZoomIn } from './icon-zoom-in'; -import { IconZoomOut } from './icon-zoom-out'; import { ToolbarButton } from './toolbar-button'; interface IToolbarProps { @@ -87,7 +83,7 @@ export function Toolbar({ name="unselect-tools" title="Selection" onClick={ (event: React.MouseEvent | React.TouchEvent) => { handleChangeTool(event, TOOL_NONE); } }> - + { handleChangeTool(event, TOOL_PAN); } }> - + { handleChangeTool(event, TOOL_ZOOM_IN); } }> - + { handleChangeTool(event, TOOL_ZOOM_OUT); } }> - + { handleFit(event); } }> - + ); From 61807b621f3eb69e8c4d317370e8eb7c1e3927c7 Mon Sep 17 00:00:00 2001 From: Eric NGUYEN Date: Fri, 17 Feb 2023 12:46:55 +0100 Subject: [PATCH 09/34] Add fittingScale to toolbar + Add transformation-matrix to dependencies --- package.json | 3 +- pnpm-lock.yaml | 2 + src/Components/SVG/SVG.tsx | 15 ++++-- .../SVGReactPanZoom/ui-toolbar/toolbar.tsx | 48 ++++++++++++++++--- 4 files changed, 56 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index f49dfef..cbfaf5d 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "react-svg-pan-zoom": "^3.12.1", "react-window": "^1.8.8", "sweetalert2": "^11.7.1", - "sweetalert2-react-content": "^5.0.7" + "sweetalert2-react-content": "^5.0.7", + "transformation-matrix": "^2.14.0" }, "devDependencies": { "@testing-library/dom": "^8.20.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 922995b..e3b088c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,6 +39,7 @@ specifiers: sweetalert2: ^11.7.1 sweetalert2-react-content: ^5.0.7 tailwindcss: ^3.2.4 + transformation-matrix: ^2.14.0 typescript: ^4.9.5 vite: ^4.1.1 vitest: ^0.28.4 @@ -53,6 +54,7 @@ dependencies: react-window: 1.8.8_biqbaboplfbrettd7655fr4n2y sweetalert2: 11.7.1 sweetalert2-react-content: 5.0.7_5cbezu6w3tvev2ldv5vdmnpfca + transformation-matrix: 2.14.0 devDependencies: '@testing-library/dom': 8.20.0 diff --git a/src/Components/SVG/SVG.tsx b/src/Components/SVG/SVG.tsx index 69cd0d0..90bbcc8 100644 --- a/src/Components/SVG/SVG.tsx +++ b/src/Components/SVG/SVG.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { ReactSVGPanZoom, type Tool, TOOL_PAN, type Value } 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 { IContainerModel } from '../../Interfaces/IContainerModel'; import { SelectorContainer } from './Elements/SelectorContainer/SelectorContainer'; @@ -8,7 +8,7 @@ import { SymbolLayer } from './Elements/SymbolLayer'; import { type ISymbolModel } from '../../Interfaces/ISymbolModel'; import { DimensionLayer } from './Elements/DimensionLayer'; import { SelectorSymbol } from './Elements/SelectorSymbol/SelectorSymbol'; -import { Toolbar } from './SVGReactPanZoom/ui-toolbar/toolbar'; +import { IToolbarProps, Toolbar } from './SVGReactPanZoom/ui-toolbar/toolbar'; interface ISVGProps { className?: string @@ -121,7 +121,14 @@ export function SVG(props: ISVGProps): JSX.Element { width: 120, height: 120 }} - customToolbar={Toolbar} + customToolbar={(props: IToolbarProps) => ( + + )} > {children} @@ -135,7 +142,7 @@ export function SVG(props: ISVGProps): JSX.Element { } function UseFitOnce(svgViewer: React.RefObject, width: number, height: number): void { - React.useEffect(() => { + React.useCallback(() => { // TODO: Fix this svgViewer?.current?.setPointOnViewerCenter(width / 2, height / 2, 0.8); }, [svgViewer, width, height]); diff --git a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/toolbar.tsx b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/toolbar.tsx index 39a801e..83bb4b0 100644 --- a/src/Components/SVG/SVGReactPanZoom/ui-toolbar/toolbar.tsx +++ b/src/Components/SVG/SVGReactPanZoom/ui-toolbar/toolbar.tsx @@ -1,5 +1,12 @@ -import { ArrowsPointingOutIcon, CursorArrowRaysIcon, HandRaisedIcon, MagnifyingGlassMinusIcon, MagnifyingGlassPlusIcon } from '@heroicons/react/24/outline'; +import { + ArrowsPointingOutIcon, + CursorArrowRaysIcon, + HandRaisedIcon, + MagnifyingGlassMinusIcon, + MagnifyingGlassPlusIcon +} from '@heroicons/react/24/outline'; import React from 'react'; +import { fromObject, scale, transform, translate } from 'transformation-matrix'; import { fitToViewer, @@ -10,9 +17,7 @@ import { TOOL_NONE, TOOL_PAN, TOOL_ZOOM_IN, - TOOL_ZOOM_OUT, - ALIGN_LEFT, - ALIGN_TOP, + TOOL_ZOOM_OUT, ALIGN_LEFT, ALIGN_TOP, type Value, type Tool, type ALIGN_BOTTOM, @@ -22,7 +27,7 @@ import { } from 'react-svg-pan-zoom'; import { ToolbarButton } from './toolbar-button'; -interface IToolbarProps { +export interface IToolbarProps { tool: Tool value: Value onChangeValue: (value: Value) => void @@ -31,6 +36,19 @@ interface IToolbarProps { position?: ToolbarPosition | undefined SVGAlignX?: typeof ALIGN_CENTER | typeof ALIGN_LEFT | typeof ALIGN_RIGHT | undefined SVGAlignY?: typeof ALIGN_CENTER | typeof ALIGN_TOP | typeof ALIGN_BOTTOM | undefined + fittingScale?: number | undefined +} + +/** + * Change value + * @param value + * @param patch + * @param action + * @returns {Object} + */ +function set(value: Value, patch: object, action = null): Value { + value = Object.assign({}, value, patch, { lastAction: action }); + return Object.freeze(value); } export function Toolbar({ @@ -41,7 +59,8 @@ export function Toolbar({ activeToolColor = '#1CA6FC', position = POSITION_RIGHT, SVGAlignX = ALIGN_LEFT, - SVGAlignY = ALIGN_TOP + SVGAlignY = ALIGN_TOP, + fittingScale = undefined }: IToolbarProps): JSX.Element { function handleChangeTool(event: React.MouseEvent | React.TouchEvent, tool: Tool): void { onChangeTool(tool); @@ -50,7 +69,22 @@ export function Toolbar({ }; function handleFit(event: React.MouseEvent | React.TouchEvent): void { - onChangeValue(fitToViewer(value, SVGAlignX, SVGAlignY)); + let fittedValue: Value = fitToViewer(value, SVGAlignX, SVGAlignY); + if (fittingScale !== undefined) { + const { viewerWidth, viewerHeight } = fittedValue; + const matrix = transform( + fromObject(fittedValue), + translate(viewerWidth, viewerHeight), + scale(fittingScale, fittingScale), + translate(-viewerWidth, -viewerHeight) + ); + + fittedValue = set(fittedValue, { + ...matrix + }); + } + + onChangeValue(fittedValue); event.stopPropagation(); event.preventDefault(); }; From 00cf80d9e3cf39c6a6521054190e035a19522821 Mon Sep 17 00:00:00 2001 From: Eric NGUYEN Date: Fri, 17 Feb 2023 14:28:56 +0100 Subject: [PATCH 10/34] Keep the extended sidebar open when changing Sidebar type + Rename ElementsSidebar --- .../ElementsSidebar.tsx} | 52 ++++++----- .../Sidebar/ToggleSideBar/ToggleSideBar.tsx | 6 +- .../SymbolsSidebar.tsx | 34 ++++--- src/Components/UI/UI.tsx | 90 ++++++------------- 4 files changed, 81 insertions(+), 101 deletions(-) rename src/Components/{ElementsList/ElementsSideBar.tsx => ElementsSidebar/ElementsSidebar.tsx} (81%) rename src/Components/{SymbolsList => SymbolsSidebar}/SymbolsSidebar.tsx (66%) diff --git a/src/Components/ElementsList/ElementsSideBar.tsx b/src/Components/ElementsSidebar/ElementsSidebar.tsx similarity index 81% rename from src/Components/ElementsList/ElementsSideBar.tsx rename to src/Components/ElementsSidebar/ElementsSidebar.tsx index 78d9b6b..e39bf2d 100644 --- a/src/Components/ElementsList/ElementsSideBar.tsx +++ b/src/Components/ElementsSidebar/ElementsSidebar.tsx @@ -1,21 +1,22 @@ import * as React from 'react'; -import { useState } from 'react'; import useSize from '@react-hook/size'; import { FixedSizeList as List } from 'react-window'; import { ExclamationTriangleIcon } from '@heroicons/react/24/outline'; import { ContainerProperties } from '../ContainerProperties/ContainerProperties'; -import { IContainerModel } from '../../Interfaces/IContainerModel'; +import { type IContainerModel } from '../../Interfaces/IContainerModel'; import { FindContainerById, MakeRecursionDFSIterator } from '../../utils/itertools'; -import { ISymbolModel } from '../../Interfaces/ISymbolModel'; -import { PropertyType } from '../../Enums/PropertyType'; +import { type ISymbolModel } from '../../Interfaces/ISymbolModel'; +import { type PropertyType } from '../../Enums/PropertyType'; import { ToggleSideBar } from '../Sidebar/ToggleSideBar/ToggleSideBar'; import { Text } from '../Text/Text'; +import { ExtendedSidebar } from '../UI/UI'; -interface IElementsSideBarProps { +interface IElementsSidebarProps { containers: Map mainContainer: IContainerModel symbols: Map selectedContainer: IContainerModel | undefined + selectedExtendedSidebar: ExtendedSidebar onPropertyChange: ( key: string, value: string | number | boolean | number[], @@ -23,8 +24,7 @@ interface IElementsSideBarProps { ) => void selectContainer: (containerId: string) => void addContainer: (index: number, type: string, parent: string) => void - isExpanded: boolean - onExpandChange: () => void + onExpandChange: (value: ExtendedSidebar) => void } function RemoveBorderClasses(target: HTMLButtonElement, exception: string = ''): void { @@ -124,11 +124,10 @@ function HandleOnDrop( } } -export function ElementsSideBar(props: IElementsSideBarProps): JSX.Element { +export function ElementsSidebar(props: IElementsSidebarProps): JSX.Element { // States const divRef = React.useRef(null); const [,height] = useSize(divRef); - const [showProperties, setShowProperties] = useState(props.isExpanded); // Render const it = MakeRecursionDFSIterator(props.mainContainer, props.containers, 0, [0, 0], true); @@ -167,18 +166,27 @@ export function ElementsSideBar(props: IElementsSideBarProps): JSX.Element { return (
- {showProperties && -
- -
+ {props.selectedExtendedSidebar === ExtendedSidebar.Property && +
+ +
}
- { setShowProperties(newValue); props.onExpandChange(); }} /> + { + const newValue = props.selectedExtendedSidebar !== ExtendedSidebar.Property + ? ExtendedSidebar.Property + : ExtendedSidebar.None; + props.onExpandChange(newValue); + }} + />
selectContainer(container.properties.id)} - onDrop={(event) => HandleOnDrop(event, containers, mainContainer, addContainer)} - onDragOver={(event) => HandleDragOver(event, mainContainer)} - onDragLeave={(event) => HandleDragLeave(event)} + onClick={() => { selectContainer(container.properties.id); }} + onDrop={(event) => { HandleOnDrop(event, containers, mainContainer, addContainer); }} + onDragOver={(event) => { HandleDragOver(event, mainContainer); }} + onDragLeave={(event) => { HandleDragLeave(event); }} > {verticalBars} {text} diff --git a/src/Components/Sidebar/ToggleSideBar/ToggleSideBar.tsx b/src/Components/Sidebar/ToggleSideBar/ToggleSideBar.tsx index 61a35d9..7d7a082 100644 --- a/src/Components/Sidebar/ToggleSideBar/ToggleSideBar.tsx +++ b/src/Components/Sidebar/ToggleSideBar/ToggleSideBar.tsx @@ -4,16 +4,16 @@ import './ToggleSideBar.scss'; interface IToggleSidebarProps { title: string checked: boolean - onChange: (newValue: boolean) => void + onClick: () => void } -export function ToggleSideBar({ title, checked, onChange }: IToggleSidebarProps): JSX.Element { +export function ToggleSideBar({ title, checked, onClick }: IToggleSidebarProps): JSX.Element { return (