@@ -69,6 +69,7 @@ import { useFrameContext } from "./hooks";
69
69
import usePinchToZoom from "@cocalc/frontend/frame-editors/frame-tree/pinch-to-zoom" ;
70
70
import Grid from "./elements/grid" ;
71
71
import {
72
+ centerOfRect ,
72
73
compressPath ,
73
74
fontSizeToZoom ,
74
75
ZOOM100 ,
@@ -160,35 +161,27 @@ export default function Canvas({
160
161
161
162
// Whenever the scale changes, make sure the current center of the screen
162
163
// is preserved.
163
- const [ lastScale , setLastScale ] = useState < number > ( canvasScale ) ;
164
+ const lastViewport = useRef < Rect | undefined > ( undefined ) ;
164
165
useEffect ( ( ) => {
165
166
if ( isNavigator ) return ;
166
- if ( canvasScale == lastScale ) return ;
167
- const ctr = getCenterPositionWindow ( ) ;
168
- if ( ctr == null ) return ;
169
- const { x, y } = ctr ;
170
- const new_x = ( lastScale / canvasScale ) * x ;
171
- const new_y = ( lastScale / canvasScale ) * y ;
172
- const delta_x = x - new_x ;
173
- const delta_y = y - new_y ;
174
- const c = canvasRef . current ;
175
- if ( c == null ) return ;
176
- c . scrollLeft += delta_x ;
177
- c . scrollTop += delta_y ;
178
- setLastScale ( canvasScale ) ;
179
- } , [ canvasScale ] ) ;
180
-
181
- useEffect ( ( ) => {
182
- const { current } = canvasRef ;
183
- if ( current != null ) {
184
- const scaledMargin = ( margin ?? 0 ) * canvasScale ;
185
- current . scrollTop = scaledMargin ;
186
- current . scrollLeft = scaledMargin ;
167
+ const viewport = getViewportData ( ) ;
168
+ if ( lastViewport . current != null && viewport != null ) {
169
+ const last = centerOfRect ( lastViewport . current ) ;
170
+ const cur = centerOfRect ( viewport ) ;
171
+ const tx = last . x - cur . x ;
172
+ const ty = last . y - cur . y ;
173
+ const c = canvasRef . current ;
174
+ if ( c == null ) return ;
175
+ c . scrollLeft += tx * canvasScale ;
176
+ c . scrollTop += ty * canvasScale ;
187
177
}
188
- } , [ ] ) ;
178
+ lastViewport . current = viewport ;
179
+ } , [ canvasScale , margin ] ) ;
189
180
181
+ // maintain state about the viewport so it can be displayed
182
+ // in the navmap, and also restored later.
190
183
useEffect ( ( ) => {
191
- updateVisibleWindow ( ) ;
184
+ updateViewport ( ) ;
192
185
} , [ font_size , scale , transforms . width , transforms . height ] ) ;
193
186
194
187
const frame = useFrameContext ( ) ;
@@ -197,10 +190,10 @@ export default function Canvas({
197
190
const restoring = useRef < boolean > ( true ) ;
198
191
useEffect ( ( ) => {
199
192
if ( isNavigator || restoring . current ) return ;
200
- const center = frame . desc . get ( "visibleWindowCenter " ) ?. toJS ( ) ;
193
+ const center = frame . desc . get ( "viewportCenter " ) ?. toJS ( ) ;
201
194
if ( center == null ) return ;
202
195
setCenterPositionData ( center ) ;
203
- } , [ frame . desc . get ( "visibleWindowCenter " ) ] ) ;
196
+ } , [ frame . desc . get ( "viewportCenter " ) ] ) ;
204
197
205
198
useEffect ( ( ) => {
206
199
if ( isNavigator ) return ;
@@ -272,24 +265,31 @@ export default function Canvas({
272
265
c . scrollTop = scrollTopGoal ;
273
266
}
274
267
275
- // when fitToScreen is true, compute data then set font_size to get zoom (plus offset) to
276
- // everything is visible properly on the page; also set fitToScreen back to false in
268
+ // when fitToScreen is true, compute data then set font_size to
269
+ // get zoom (plus offset) to everything is visible properly
270
+ // on the page; also set fitToScreen back to false in
277
271
// frame tree data
278
272
useEffect ( ( ) => {
279
- if ( frame . desc . get ( "fitToScreen" ) && ! isNavigator ) {
280
- try {
281
- const viewport = getViewportData ( ) ;
282
- if ( viewport == null ) return ;
283
- const rect = rectSpan ( elements ) ;
284
- const { scale } = fitRectToRect ( rect , viewport ) ;
285
- frame . actions . set_font_size ( frame . id , ( font_size ?? ZOOM100 ) * scale ) ;
286
- setCenterPositionData ( {
287
- x : rect . x + rect . w / 2 ,
288
- y : rect . y + rect . h / 2 ,
289
- } ) ;
290
- } finally {
291
- frame . actions . fitToScreen ( frame . id , false ) ;
273
+ if ( isNavigator || ! frame . desc . get ( "fitToScreen" ) ) return ;
274
+ try {
275
+ const viewport = getViewportData ( ) ;
276
+ if ( viewport == null ) return ;
277
+ const rect = rectSpan ( elements ) ;
278
+ setCenterPositionData ( {
279
+ x : rect . x + rect . w / 2 ,
280
+ y : rect . y + rect . h / 2 ,
281
+ } ) ;
282
+ const { scale } = fitRectToRect ( rect , viewport ) ;
283
+ if ( scale != 1 ) {
284
+ // ensure lastViewport is up to date before zooming.
285
+ lastViewport . current = getViewportData ( ) ;
286
+ frame . actions . set_font_size (
287
+ frame . id ,
288
+ Math . round ( ( font_size ?? ZOOM100 ) * scale )
289
+ ) ;
292
290
}
291
+ } finally {
292
+ frame . actions . fitToScreen ( frame . id , false ) ;
293
293
}
294
294
} , [ frame . desc . get ( "fitToScreen" ) ] ) ;
295
295
@@ -326,6 +326,7 @@ export default function Canvas({
326
326
element = { element }
327
327
focused = { focused }
328
328
canvasScale = { canvasScale }
329
+ readOnly = { readOnly || isNavigator }
329
330
/>
330
331
) ;
331
332
if ( ! isNavRectangle && ( element . style || selected || isNavigator ) ) {
@@ -450,9 +451,8 @@ export default function Canvas({
450
451
451
452
if ( isNavigator ) {
452
453
// The navigator rectangle
453
- const visible = frame . desc . get ( "visibleWindow " ) ?. toJS ( ) ;
454
+ const visible = frame . desc . get ( "viewport " ) ?. toJS ( ) ;
454
455
if ( visible ) {
455
- const { xMin, yMin, xMax, yMax } = visible ;
456
456
v . unshift (
457
457
< Draggable
458
458
key = "nav"
@@ -467,14 +467,11 @@ export default function Canvas({
467
467
onStop = { ( data : MouseEvent ) => {
468
468
if ( ! navDrag . current ) return ;
469
469
const { x0, y0 } = navDrag . current ;
470
- const visible = frame . desc . get ( "visibleWindow " ) ?. toJS ( ) ;
470
+ const visible = frame . desc . get ( "viewport " ) ?. toJS ( ) ;
471
471
if ( visible == null ) return ;
472
- const ctr = {
473
- x : ( visible . xMax + visible . xMin ) / 2 ,
474
- y : ( visible . yMax + visible . yMin ) / 2 ,
475
- } ;
472
+ const ctr = centerOfRect ( visible ) ;
476
473
const { x, y } = data ;
477
- frame . actions . setVisibleWindowCenter ( frame . id , {
474
+ frame . actions . setViewportCenter ( frame . id , {
478
475
x : ctr . x + ( x - x0 ) / canvasScale ,
479
476
y : ctr . y + ( y - y0 ) / canvasScale ,
480
477
} ) ;
@@ -484,10 +481,7 @@ export default function Canvas({
484
481
{ processElement (
485
482
{
486
483
id : "nav-frame" ,
487
- x : xMin ,
488
- y : yMin ,
489
- w : xMax - xMin ,
490
- h : yMax - yMin ,
484
+ ...visible ,
491
485
z : MAX_ELEMENTS + 1 ,
492
486
type : "frame" ,
493
487
data : { color : "#888" , radius : 0.5 } ,
@@ -615,25 +609,17 @@ export default function Canvas({
615
609
}
616
610
}
617
611
618
- const updateVisibleWindow = isNavigator
612
+ const updateViewport = isNavigator
619
613
? ( ) => { }
620
614
: useMemo ( ( ) => {
621
615
return throttle ( ( ) => {
622
- const elt = canvasRef . current ;
623
- if ( ! elt ) return ;
624
- // upper left corner of visible window
625
- const { scrollLeft, scrollTop } = elt ;
626
- // width and height of visible window
627
- const { width, height } = elt . getBoundingClientRect ( ) ;
628
- const { x : xMin , y : yMin } = transforms . windowToDataNoScale (
629
- scrollLeft / canvasScale ,
630
- scrollTop / canvasScale
631
- ) ;
632
- const xMax = xMin + width / canvasScale ;
633
- const yMax = yMin + height / canvasScale ;
634
- frame . actions . saveVisibleWindow ( frame . id , { xMin, yMin, xMax, yMax } ) ;
616
+ const viewport = getViewportData ( ) ;
617
+ if ( viewport ) {
618
+ frame . actions . saveViewport ( frame . id , viewport ) ;
619
+ lastViewport . current = viewport ;
620
+ }
635
621
} , 50 ) ;
636
- } , [ transforms , canvasScale ] ) ;
622
+ } , [ transforms , canvasScale , margin ] ) ;
637
623
638
624
const onMouseDown = ( e ) => {
639
625
if ( selectedTool == "select" || selectedTool == "frame" ) {
@@ -816,15 +802,15 @@ export default function Canvas({
816
802
navDrag . current = null ;
817
803
return ;
818
804
}
819
- frame . actions . setVisibleWindowCenter ( frame . id , evtToData ( e ) ) ;
805
+ frame . actions . setViewportCenter ( frame . id , evtToData ( e ) ) ;
820
806
return ;
821
807
}
822
808
if ( ! readOnly ) {
823
809
handleClick ( e ) ;
824
810
}
825
811
} }
826
812
onScroll = { ( ) => {
827
- updateVisibleWindow ( ) ;
813
+ updateViewport ( ) ;
828
814
saveCenterPosition ( ) ;
829
815
} }
830
816
onMouseDown = { onMouseDown }
0 commit comments