1+ /* eslint-disable react-hooks/exhaustive-deps */
12import { useCanvas } from "./contexts/CanvasContext.tsx" ;
23import React , { useEffect , useMemo , useRef , useState } from "react" ;
34import { Group , Layer , Stage , Transformer } from "react-konva" ;
@@ -11,7 +12,7 @@ import useApiService from "services/apiService.ts";
1112import { useParams } from "react-router-dom" ;
1213import StagePreview from "components/canvas/elements/StagePreview.tsx" ;
1314import NeighbourArrows from "components/canvas/elements/NeighbourArrows.tsx" ;
14- import SelectionRectangle from "components/canvas/elements/SelectionRectangle.tsx" ;
15+ import SelectionRectangle , { type SelectionRectangleType } from "components/canvas/elements/SelectionRectangle.tsx" ;
1516import {
1617 handleDoubleClickOnElement ,
1718 handleDragEnd ,
@@ -28,12 +29,14 @@ import {
2829 handleWheel ,
2930} from "components/canvas/EventListeners.tsx" ;
3031import type { Chair } from "components/canvas/elements/Chair.tsx" ;
32+ import type { QuickWallProps } from "components/canvas/elements/Wall.tsx" ;
3133
3234
3335const TYPE_ORDER : { [ key in ShapeType ] : number } = {
3436 rectTable : 2 ,
3537 circleTable : 3 ,
3638 chair : 4 ,
39+ room : 0 ,
3740 wall : 1 ,
3841 quickWall : 1 ,
3942 arrow : 5 ,
@@ -47,7 +50,7 @@ export interface KonvaCanvasProps {
4750 isFullWidth ?: boolean ,
4851}
4952
50- function KonvaCanvas ( { stageReference, schematicsUUID, isFullWidth } : KonvaCanvasProps ) {
53+ export function KonvaCanvas ( { stageReference, schematicsUUID, isFullWidth } : KonvaCanvasProps ) {
5154 const { state, dispatch } = useCanvas ( ) ;
5255 let stageRef = useRef < Konva . Stage | null > ( null ) ;
5356 let { schematicsId } = useParams ( ) ;
@@ -62,18 +65,24 @@ function KonvaCanvas({ stageReference, schematicsUUID, isFullWidth }: KonvaCanva
6265 const containerRef = useRef < HTMLDivElement | null > ( null ) ;
6366 const [ scale , setScale ] = useState ( 1 ) ;
6467 const [ containerSize , setContainerSize ] = useState ( { width : 800 , height : 600 } ) ;
65- const [ quickWallCoordinates , setQuickWallCoordinates ] = useState < {
66- x1 ?: number ;
67- y1 ?: number ;
68- } > ( { x1 : undefined , y1 : undefined } ) ;
68+ const [ quickWallCoordinates , setQuickWallCoordinates ] = useState < QuickWallProps > ( { x1 : undefined , y1 : undefined } ) ;
6969 const { getSchematics } = useApiService ( ) ;
7070 const [ selectedIds , setSelectedIds ] = useState < string [ ] > ( [ ] ) ;
7171 const [ initiated , setInitiated ] = useState ( false ) ;
7272 const [ isShiftPressed , setIsShiftPressed ] = useState ( false ) ;
7373 const dragLayer = useRef < Konva . Layer | null > ( null ) ;
7474 const mainLayer = useRef < Konva . Layer | null > ( null ) ;
75-
76- const [ selectionRectangle , setSelectionRectangle ] = useState ( {
75+ const isSelecting = useRef ( false ) ;
76+ const transformerRef = useRef < Konva . Transformer > ( null ) ;
77+ const rectRefs = useRef ( new Map ( ) ) ;
78+ // we sort elements according to their types so that they are drawn properly
79+ // this sort operation causes overhead initially but negligible afterward
80+ // we use this hash function to limit these unnecessary re-sorts to only positions/properties change
81+ const elementTypesHash = useMemo ( ( ) =>
82+ state . elements ?. map ( el => el . type ) . join ( "," ) ,
83+ [ state . elements ] ,
84+ ) ;
85+ const [ selectionRectangle , setSelectionRectangle ] = useState < SelectionRectangleType > ( {
7786 visible : false ,
7887 x1 : 0 ,
7988 y1 : 0 ,
@@ -107,10 +116,6 @@ function KonvaCanvas({ stageReference, schematicsUUID, isFullWidth }: KonvaCanva
107116 fetchData ( ) ;
108117 } , [ dispatch , getSchematics , initiated , schematicsId , state . canvasPosition , state . scale ] ) ;
109118
110- useEffect ( ( ) => {
111- window . scrollTo ( 0 , 0 ) ; // we have to scroll to top-left corner of the page, otherwise it looks bad
112- } , [ ] ) ;
113-
114119 // Measure container size
115120 useEffect ( ( ) => {
116121 const updateContainerSize = ( ) => {
@@ -128,20 +133,17 @@ function KonvaCanvas({ stageReference, schematicsUUID, isFullWidth }: KonvaCanva
128133 return ( ) => window . removeEventListener ( "resize" , updateContainerSize ) ;
129134 } , [ isFullWidth ] ) ;
130135
131- const isSelecting = useRef ( false ) ;
132- const transformerRef = useRef < Konva . Transformer > ( null ) ;
133- const rectRefs = useRef ( new Map ( ) ) ;
134-
136+ // if selectedIds change, then capture them into Transformer so that we can scale or rotate them
135137 useEffect ( ( ) => {
136138 if ( selectedIds . length && transformerRef . current ) {
137139 const nodes = selectedIds . map ( id => rectRefs . current . get ( id ) ) . filter ( node => node ) ;
138-
139140 transformerRef . current . nodes ( nodes ) ;
140141 } else if ( transformerRef . current ) {
141142 transformerRef . current . nodes ( [ ] ) ;
142143 }
143144 } , [ selectedIds ] ) ;
144145
146+ // if build mode changes, then reset quickwall
145147 useEffect ( ( ) => {
146148 if ( state . buildMode === 0 ) setQuickWallCoordinates ( { x1 : undefined , y1 : undefined } ) ;
147149 } , [ state . buildMode ] ) ;
@@ -165,12 +167,6 @@ function KonvaCanvas({ stageReference, schematicsUUID, isFullWidth }: KonvaCanva
165167 } ;
166168 } , [ dispatch , setSelectedIds , setIsShiftPressed , selectedIds , setQuickWallCoordinates , stageRef ] ) ;
167169
168- // unnecessary re-sorts when only positions/properties change
169- const elementTypesHash = useMemo ( ( ) =>
170- state . elements ?. map ( el => el . type ) . join ( "," ) ,
171- [ state . elements ] ,
172- ) ;
173-
174170 useEffect ( ( ) => {
175171 if ( state . elements ?. length > 1 ) {
176172 state . elements . sort ( ( a , b ) => {
@@ -342,5 +338,3 @@ function KonvaCanvas({ stageReference, schematicsUUID, isFullWidth }: KonvaCanva
342338 </ div >
343339 ) ;
344340}
345-
346- export default KonvaCanvas ;
0 commit comments