@@ -35,6 +35,7 @@ import {
3535 MenuItem ,
3636} from "@editor-ui/context-menu" ;
3737import styled from "@emotion/styled" ;
38+ import toast from "react-hot-toast" ;
3839
3940interface CanvasState {
4041 pageid : string ;
@@ -44,6 +45,10 @@ interface CanvasState {
4445 highlightedLayer ?: string ;
4546 selectedNodes : string [ ] ;
4647 readonly ?: boolean ;
48+ /**
49+ * displays the debug info on the canvas.
50+ */
51+ debug ?: boolean ;
4752 /**
4853 * when provided, it will override the saved value or centering logic and use this transform as initial instead.
4954 *
@@ -101,6 +106,10 @@ const default_canvas_preferences: CanvsPreferences = {
101106
102107type CanvasProps = CanvasFocusProps &
103108 CanvasCursorOptions & {
109+ /**
110+ * canvas view bound.
111+ * [(x1) left, (y1) top, (x2) right, (y2) bottom]
112+ */
104113 viewbound : Box ;
105114 onSelectNode ?: ( ...node : ReflectSceneNode [ ] ) => void ;
106115 onMoveNodeStart ?: ( ...node : string [ ] ) => void ;
@@ -158,6 +167,7 @@ export function Canvas({
158167 initialTransform,
159168 highlightedLayer,
160169 selectedNodes,
170+ debug,
161171 readonly = true ,
162172 config = default_canvas_preferences ,
163173 backgroundColor,
@@ -225,7 +235,9 @@ export function Canvas({
225235 setZoom ( _focus_center . scale ) ;
226236 } , [ ...focus , focusRefreshKey , viewboundmeasured ] ) ;
227237
228- const [ transformIntitialized , setTransformInitialized ] = useState ( false ) ;
238+ const [ transformIntitialized , setTransformInitialized ] = useState (
239+ ! ! initialTransform
240+ ) ;
229241 const [ zoom , setZoom ] = useState ( initialTransform ?. scale || 1 ) ;
230242 const [ isZooming , setIsZooming ] = useState ( false ) ;
231243 const [ offset , setOffset ] = useState < [ number , number ] > (
@@ -429,19 +441,25 @@ export function Canvas({
429441 onMoveNode ?.( [ dx / zoom , dy / zoom ] , ...selectedNodes ) ;
430442 }
431443
432- if ( marquee ) {
433- const [ w , h ] = [
434- x1 - marquee [ 0 ] , // w
435- y1 - marquee [ 1 ] , // h
436- ] ;
437- setMarquee ( [ marquee [ 0 ] , marquee [ 1 ] , w , h ] ) ;
438- }
444+ if ( config . marquee . disabled ) {
445+ // skip
446+ } else {
447+ // edge scrolling
448+ // edge scrolling is only enabled when config#marquee is enabled
449+ const [ cx , cy ] = [ x , y ] ;
450+ const [ dx , dy ] = edge_scrolling ( cx , cy , viewbound ) ;
451+ if ( dx || dy ) {
452+ setOffset ( [ ox + dx , oy + dy ] ) ;
453+ }
439454
440- // edge scrolling
441- const [ cx , cy ] = [ x , y ] ;
442- const [ dx , dy ] = edge_scrolling ( cx , cy , viewbound ) ;
443- if ( dx || dy ) {
444- setOffset ( [ ox + dx , oy + dy ] ) ;
455+ // update marquee & following selections via effect
456+ if ( marquee ) {
457+ const [ w , h ] = [
458+ x1 - marquee [ 0 ] , // w
459+ y1 - marquee [ 1 ] , // h
460+ ] ;
461+ setMarquee ( [ marquee [ 0 ] , marquee [ 1 ] , w , h ] ) ;
462+ }
445463 }
446464 } ;
447465
@@ -504,11 +522,35 @@ export function Canvas({
504522 return (
505523 < >
506524 < >
525+ { debug === true && (
526+ < Debug
527+ infos = { [
528+ { label : "zoom" , value : zoom } ,
529+ { label : "offset" , value : offset . join ( ", " ) } ,
530+ { label : "isPanning" , value : isPanning } ,
531+ { label : "isZooming" , value : isZooming } ,
532+ { label : "isDragging" , value : isDragging } ,
533+ { label : "isMovingSelections" , value : isMovingSelections } ,
534+ { label : "isTransforming" , value : is_canvas_transforming } ,
535+ { label : "selectedNodes" , value : selectedNodes . join ( ", " ) } ,
536+ { label : "hoveringLayer" , value : hoveringLayer ?. node ?. id } ,
537+ { label : "marquee" , value : marquee ?. join ( ", " ) } ,
538+ { label : "viewbound" , value : viewbound . join ( ", " ) } ,
539+ {
540+ label : "initial-transform (xy)" ,
541+ value : initialTransform ? initialTransform . xy . join ( ", " ) : null ,
542+ } ,
543+ {
544+ label : "initial-transform (zoom)" ,
545+ value : initialTransform ? initialTransform . scale : null ,
546+ } ,
547+ ] }
548+ />
549+ ) }
507550 { /* <ContextMenuProvider> */ }
508551 < Container
509- // todo: viewbound not accurate.
510- // width={viewbound[2] - viewbound[0]}
511- // height={viewbound[3] - viewbound[1]}
552+ width = { viewbound [ 2 ] - viewbound [ 0 ] }
553+ height = { viewbound [ 3 ] - viewbound [ 1 ] }
512554 >
513555 < CanvasEventTarget
514556 onPanning = { onPanning }
@@ -524,6 +566,7 @@ export function Canvas({
524566 // const newoffset = zoomToFit(viewbound, offset, zoom, 1);
525567 // setOffset(newoffset);
526568 _canvas_state_store . saveLastTransform ( cvtransform ) ;
569+ toast ( "Zoom to 100%" ) ;
527570 } }
528571 onZooming = { onZooming }
529572 onZoomingStart = { ( ) => {
@@ -585,12 +628,10 @@ export function Canvas({
585628 ) ;
586629}
587630
588- const Container = styled . div `
589- min- width: 240px;
590- min- height: 240px;
631+ const Container = styled . div < { width : number ; height : number } > `
632+ /* width: ${ ( p ) => p . width } px; */
633+ /* height: ${ ( p ) => p . height } px; */
591634` ;
592- /* width: ${(p) => p.width}px; */
593- /* height: ${(p) => p.height}px; */
594635
595636/**
596637 * 1. container positioning guide (static per selection)
@@ -713,9 +754,10 @@ function DisableBackdropFilter({ children }: { children: React.ReactNode }) {
713754function CanvasBackground ( { backgroundColor } : { backgroundColor ?: string } ) {
714755 return (
715756 < div
757+ id = "canvas-background"
716758 style = { {
717759 zIndex : - 2 ,
718- position : "fixed " ,
760+ position : "absolute " ,
719761 top : 0 ,
720762 left : 0 ,
721763 width : "100%" ,
@@ -786,3 +828,39 @@ const viewbound_not_measured = (viewbound: Box) => {
786828 viewbound [ 3 ] === 0 )
787829 ) ;
788830} ;
831+
832+ function Debug ( {
833+ infos,
834+ } : {
835+ infos : { label : string ; value : string | number | boolean } [ ] ;
836+ } ) {
837+ return (
838+ < DebugInfoContainer >
839+ { infos . map ( ( { label, value } , i ) => {
840+ if ( value === undefined || value === null ) {
841+ return < > </ > ;
842+ }
843+ return (
844+ < div key = { i } >
845+ { label } : { JSON . stringify ( value ) }
846+ </ div >
847+ ) ;
848+ } ) }
849+ </ DebugInfoContainer >
850+ ) ;
851+ }
852+
853+ const DebugInfoContainer = styled . div `
854+ position: absolute;
855+ top: 12px;
856+ left: 12px;
857+ z-index: 9999;
858+ background: rgba(0, 0, 0, 0.5);
859+ border-radius: 4px;
860+ color: white;
861+ padding: 0.5rem;
862+ font-size: 0.8rem;
863+ font-family: monospace;
864+ line-height: 1.2;
865+ white-space: pre;
866+ ` ;
0 commit comments