@@ -2,8 +2,9 @@ import Heap from 'js-slang/dist/cse-machine/heap';
22import { Control , Stash } from 'js-slang/dist/cse-machine/interpreter' ;
33import { Chapter , Frame } from 'js-slang/dist/types' ;
44import { KonvaEventObject } from 'konva/lib/Node' ;
5+ import { Stage } from 'konva/lib/Stage' ;
56import React , { RefObject } from 'react' ;
6- import { Layer , Rect , Stage } from 'react-konva' ;
7+ import { Layer as KonvaLayer , Rect as KonvaRect , Stage as KonvaStage } from 'react-konva' ;
78import classes from 'src/styles/Draggable.module.scss' ;
89
910import { Binding } from './components/Binding' ;
@@ -98,17 +99,19 @@ export class Layout {
9899 static currentStackTruncDark : React . ReactNode ;
99100 static currentStackLight : React . ReactNode ;
100101 static currentStackTruncLight : React . ReactNode ;
101- static stageRef : RefObject < any > = React . createRef ( ) ;
102+ static stageRef : RefObject < Stage > = React . createRef ( ) ;
102103
103104 // buffer for faster rendering of diagram when scrolling
104105 static invisiblePaddingVertical : number = 300 ;
105106 static invisiblePaddingHorizontal : number = 300 ;
106- static scrollContainerRef : RefObject < any > = React . createRef ( ) ;
107+ static scrollContainerRef : RefObject < HTMLDivElement > = React . createRef ( ) ;
107108
108109 static updateDimensions ( width : number , height : number ) {
109110 // update the size of the scroll container and stage given the width and height of the sidebar content.
110111 Layout . visibleWidth = width ;
111112 Layout . visibleHeight = height ;
113+ Layout . _width = Math . max ( Layout . visibleWidth , Layout . stageWidth ) ;
114+ Layout . _height = Math . max ( Layout . visibleHeight , Layout . stageHeight ) ;
112115 if (
113116 Layout . stageRef . current !== null &&
114117 ( Math . min ( Layout . width ( ) , window . innerWidth ) > Layout . stageWidth ||
@@ -122,16 +125,14 @@ export class Layout {
122125 Layout . stageRef . current . height ( Layout . stageHeight ) ;
123126 CseMachine . redraw ( ) ;
124127 }
125- if ( Layout . stageHeight > Layout . visibleHeight ) {
126- }
127128 Layout . invisiblePaddingVertical =
128129 Layout . stageHeight > Layout . visibleHeight
129130 ? ( Layout . stageHeight - Layout . visibleHeight ) / 2
130131 : 0 ;
131132 Layout . invisiblePaddingHorizontal =
132133 Layout . stageWidth > Layout . visibleWidth ? ( Layout . stageWidth - Layout . visibleWidth ) / 2 : 0 ;
133134
134- const container : HTMLElement | null = this . scrollContainerRef . current as HTMLDivElement ;
135+ const container = this . scrollContainerRef . current ;
135136 if ( container ) {
136137 container . style . width = `${ Layout . visibleWidth } px` ;
137138 container . style . height = `${ Layout . visibleHeight } px` ;
@@ -183,12 +184,13 @@ export class Layout {
183184 // calculate height and width by considering lowest and widest level
184185 const lastLevel = Layout . levels [ Layout . levels . length - 1 ] ;
185186 Layout . _height = Math . max (
187+ Layout . visibleHeight ,
186188 Config . CanvasMinHeight ,
187189 lastLevel . y ( ) + lastLevel . height ( ) + Config . CanvasPaddingY ,
188190 Layout . controlStashHeight ?? 0
189191 ) ;
190-
191192 Layout . _width = Math . max (
193+ Layout . visibleWidth ,
192194 Config . CanvasMinWidth ,
193195 Layout . levels . reduce < number > ( ( maxWidth , level ) => Math . max ( maxWidth , level . width ( ) ) , 0 ) +
194196 Config . CanvasPaddingX * 2 +
@@ -412,10 +414,10 @@ export class Layout {
412414 * Scrolls diagram to top left, resets the zoom, and saves the diagram as multiple images of width < MaxExportWidth.
413415 */
414416 static exportImage = ( ) => {
415- const container : HTMLElement | null = this . scrollContainerRef . current as HTMLDivElement ;
416- container . scrollTo ( { left : 0 , top : 0 } ) ;
417+ const container = this . scrollContainerRef . current ;
418+ container ? .scrollTo ( { left : 0 , top : 0 } ) ;
417419 Layout . handleScrollPosition ( 0 , 0 ) ;
418- this . stageRef . current . scale ( { x : 1 , y : 1 } ) ;
420+ this . stageRef . current ? .scale ( { x : 1 , y : 1 } ) ;
419421 const height = Layout . height ( ) ;
420422 const width = Layout . width ( ) ;
421423 const horizontalImages = Math . ceil ( width / Config . MaxExportWidth ) ;
@@ -429,13 +431,14 @@ export class Layout {
429431 const y = Math . floor ( n / horizontalImages ) ;
430432 const a = document . createElement ( 'a' ) ;
431433 a . style . display = 'none' ;
432- a . href = this . stageRef . current . toDataURL ( {
433- x : x * Config . MaxExportWidth + Layout . invisiblePaddingHorizontal ,
434- y : y * Config . MaxExportHeight + Layout . invisiblePaddingVertical ,
435- width : Math . min ( width - x * Config . MaxExportWidth , Config . MaxExportWidth ) ,
436- height : Math . min ( height - y * Config . MaxExportHeight , Config . MaxExportHeight ) ,
437- mimeType : 'image/jpeg'
438- } ) ;
434+ a . href =
435+ this . stageRef . current ?. toDataURL ( {
436+ x : x * Config . MaxExportWidth + Layout . invisiblePaddingHorizontal ,
437+ y : y * Config . MaxExportHeight + Layout . invisiblePaddingVertical ,
438+ width : Math . min ( width - x * Config . MaxExportWidth , Config . MaxExportWidth ) ,
439+ height : Math . min ( height - y * Config . MaxExportHeight , Config . MaxExportHeight ) ,
440+ mimeType : 'image/jpeg'
441+ } ) ?? '' ;
439442
440443 a . download = `diagram_${ x } _${ y } .jpg` ;
441444 document . body . appendChild ( a ) ;
@@ -457,6 +460,7 @@ export class Layout {
457460 * @param y y position of the scroll container
458461 */
459462 private static handleScrollPosition ( x : number , y : number ) {
463+ if ( ! this . stageRef . current ) return ;
460464 const dx = x - Layout . invisiblePaddingHorizontal ;
461465 const dy = y - Layout . invisiblePaddingVertical ;
462466 this . stageRef . current . container ( ) . style . transform = 'translate(' + dx + 'px, ' + dy + 'px)' ;
@@ -475,7 +479,10 @@ export class Layout {
475479 if ( Layout . stageRef . current !== null ) {
476480 const stage = Layout . stageRef . current ;
477481 const oldScale = stage . scaleX ( ) ;
478- const { x : pointerX , y : pointerY } = stage . getPointerPosition ( ) ;
482+ const { x : pointerX , y : pointerY } = stage . getPointerPosition ( ) ?? {
483+ x : Layout . visibleWidth / 2 - stage . x ( ) ,
484+ y : Layout . visibleHeight / 2 - stage . y ( )
485+ } ;
479486 const mousePointTo = {
480487 x : ( pointerX - stage . x ( ) ) / oldScale ,
481488 y : ( pointerY - stage . y ( ) ) / oldScale
@@ -531,16 +538,16 @@ export class Layout {
531538 backgroundColor : defaultBackgroundColor ( )
532539 } }
533540 >
534- < Stage
541+ < KonvaStage
535542 width = { Layout . stageWidth }
536543 height = { Layout . stageHeight }
537544 ref = { Layout . stageRef }
538545 draggable
539546 onWheel = { Layout . zoomStage }
540547 className = { classes [ 'draggable' ] }
541548 >
542- < Layer >
543- < Rect
549+ < KonvaLayer >
550+ < KonvaRect
544551 { ...ShapeDefaultProps }
545552 x = { 0 }
546553 y = { 0 }
@@ -553,11 +560,11 @@ export class Layout {
553560 { Layout . levels . map ( level => level . draw ( ) ) }
554561 { CseMachine . getControlStash ( ) && Layout . controlComponent . draw ( ) }
555562 { CseMachine . getControlStash ( ) && Layout . stashComponent . draw ( ) }
556- </ Layer >
557- < Layer ref = { CseAnimation . layerRef } listening = { false } >
563+ </ KonvaLayer >
564+ < KonvaLayer ref = { CseAnimation . layerRef } listening = { false } >
558565 { CseMachine . getControlStash ( ) && CseAnimation . animations . map ( c => c . draw ( ) ) }
559- </ Layer >
560- </ Stage >
566+ </ KonvaLayer >
567+ </ KonvaStage >
561568 </ div >
562569 </ div >
563570 </ div >
0 commit comments