@@ -20,7 +20,7 @@ import {
2020import q from "@design-sdk/query" ;
2121import { LazyFrame } from "@code-editor/canvas/lazy-frame" ;
2222import { HudCustomRenderers , HudSurface } from "../hud" ;
23- import type { Box , XY , CanvasTransform , XYWH } from "../types" ;
23+ import type { Box , XY , CanvasTransform , XYWH , XYWHR } from "../types" ;
2424import type { FrameOptimizationFactors } from "../frame" ;
2525// import { TransformDraftingStore } from "../drafting";
2626import {
@@ -98,23 +98,44 @@ const default_canvas_preferences: CanvsPreferences = {
9898 } ,
9999} ;
100100
101- type CanvasProps = CanvasCursorOptions & {
102- viewbound : Box ;
103- onSelectNode ?: ( ...node : ReflectSceneNode [ ] ) => void ;
104- onMoveNodeStart ?: ( ...node : string [ ] ) => void ;
105- onMoveNode ?: ( delta : XY , ...node : string [ ] ) => void ;
106- onMoveNodeEnd ?: ( delta : XY , ...node : string [ ] ) => void ;
107- onClearSelection ?: ( ) => void ;
108- } & CanvasCustomRenderers &
101+ type CanvasProps = CanvasFocusProps &
102+ CanvasCursorOptions & {
103+ viewbound : Box ;
104+ onSelectNode ?: ( ...node : ReflectSceneNode [ ] ) => void ;
105+ onMoveNodeStart ?: ( ...node : string [ ] ) => void ;
106+ onMoveNode ?: ( delta : XY , ...node : string [ ] ) => void ;
107+ onMoveNodeEnd ?: ( delta : XY , ...node : string [ ] ) => void ;
108+ onClearSelection ?: ( ) => void ;
109+ } & CanvasCustomRenderers &
109110 CanvasState & {
110111 config ?: CanvsPreferences ;
111112 } ;
112113
114+ type CanvasFocusProps = {
115+ /**
116+ * IDs of focus nodes.
117+ *
118+ * @default []
119+ */
120+ focus ?: string [ ] ;
121+ focusRefreshkey ?: string ;
122+ } ;
123+
113124interface HovringNode {
114125 node : ReflectSceneNode ;
115126 reason : "frame-title" | "raycast" | "external" ;
116127}
117128
129+ function xywhr_of ( node : ReflectSceneNode ) : XYWHR {
130+ return [
131+ node . absoluteX ,
132+ node . absoluteY ,
133+ node . width ,
134+ node . height ,
135+ node . rotation ,
136+ ] as XYWHR ;
137+ }
138+
118139export function Canvas ( {
119140 viewbound,
120141 renderItem,
@@ -126,6 +147,8 @@ export function Canvas({
126147 filekey,
127148 pageid,
128149 nodes,
150+ focus = [ ] ,
151+ focusRefreshkey : focusRefreshKey ,
129152 initialTransform,
130153 highlightedLayer,
131154 selectedNodes,
@@ -135,6 +158,11 @@ export function Canvas({
135158 cursor,
136159 ...props
137160} : CanvasProps ) {
161+ const viewboundmeasured = useMemo (
162+ ( ) => ! viewbound_not_measured ( viewbound ) ,
163+ viewbound
164+ ) ;
165+
138166 useEffect ( ( ) => {
139167 if ( transformIntitialized ) {
140168 return ;
@@ -148,7 +176,7 @@ export function Canvas({
148176 return ;
149177 }
150178
151- if ( viewbound_not_measured ( viewbound ) ) {
179+ if ( ! viewboundmeasured ) {
152180 return ;
153181 }
154182
@@ -158,6 +186,39 @@ export function Canvas({
158186 setTransformInitialized ( true ) ;
159187 } , [ viewbound ] ) ;
160188
189+ useEffect ( ( ) => {
190+ // change the canvas transform to visually fit the focus nodes.
191+
192+ if ( ! viewboundmeasured ) {
193+ return ;
194+ }
195+
196+ if ( focus . length == 0 ) {
197+ return ;
198+ }
199+
200+ // TODO: currently only the root nodes are supported to be focused.
201+ const _focus_nodes = nodes . filter ( ( n ) => focus . includes ( n . id ) ) ;
202+ if ( _focus_nodes . length == 0 ) {
203+ return ;
204+ }
205+
206+ const _focus_center = centerOf (
207+ viewbound ,
208+ 200 ,
209+ ..._focus_nodes . map ( ( n ) => ( {
210+ x : n . absoluteX ,
211+ y : n . absoluteY ,
212+ width : n . width ,
213+ height : n . height ,
214+ rotation : n . rotation ,
215+ } ) )
216+ ) ;
217+
218+ setOffset ( _focus_center . translate ) ;
219+ setZoom ( _focus_center . scale ) ;
220+ } , [ ...focus , focusRefreshKey , viewboundmeasured ] ) ;
221+
161222 const [ transformIntitialized , setTransformInitialized ] = useState ( false ) ;
162223 const [ zoom , setZoom ] = useState ( initialTransform ?. scale || 1 ) ;
163224 const [ isZooming , setIsZooming ] = useState ( false ) ;
@@ -339,9 +400,7 @@ export function Canvas({
339400 const [ x , y ] = [ cx / zoom , cy / zoom ] ;
340401
341402 const box = boundingbox (
342- selected_nodes . map ( ( d ) => {
343- return [ d . absoluteX , d . absoluteY , d . width , d . height , d . rotation ] ;
344- } ) ,
403+ selected_nodes . map ( ( d ) => xywhr_of ( d ) ) ,
345404 2
346405 ) ;
347406
@@ -543,29 +602,12 @@ function position_guide({
543602
544603 const guides = [ ] ;
545604 const a = boundingbox (
546- selections . map ( ( s ) => [
547- s . absoluteX ,
548- s . absoluteY ,
549- s . width ,
550- s . height ,
551- s . rotation ,
552- ] ) ,
605+ selections . map ( ( s ) => xywhr_of ( s ) ) ,
553606 2
554607 ) ;
555608
556609 if ( hover ) {
557- const hover_box = boundingbox (
558- [
559- [
560- hover . absoluteX ,
561- hover . absoluteY ,
562- hover . width ,
563- hover . height ,
564- hover . rotation ,
565- ] ,
566- ] ,
567- 2
568- ) ;
610+ const hover_box = boundingbox ( [ xywhr_of ( hover ) ] , 2 ) ;
569611
570612 const guide_relative_to_hover = {
571613 a : a ,
@@ -580,18 +622,7 @@ function position_guide({
580622 if ( selections . length === 1 ) {
581623 const parent = selections [ 0 ] . parent ;
582624 if ( parent ) {
583- const parent_box = boundingbox (
584- [
585- [
586- parent . absoluteX ,
587- parent . absoluteY ,
588- parent . width ,
589- parent . height ,
590- parent . rotation ,
591- ] ,
592- ] ,
593- 2
594- ) ;
625+ const parent_box = boundingbox ( [ xywhr_of ( parent ) ] , 2 ) ;
595626 const guide_relative_to_parent = {
596627 a : a ,
597628 b : parent_box ,
@@ -702,7 +733,7 @@ function auto_initial_transform(
702733 }
703734
704735 const fit_single_node = ( n : ReflectSceneNode ) => {
705- return centerOf ( viewbound , n ) ;
736+ return centerOf ( viewbound , 0 , n ) ;
706737 } ;
707738
708739 if ( nodes . length === 0 ) {
@@ -716,7 +747,7 @@ function auto_initial_transform(
716747 } ;
717748 } else if ( nodes . length < 20 ) {
718749 // fit bounds
719- const c = centerOf ( viewbound , ...nodes ) ;
750+ const c = centerOf ( viewbound , 0 , ...nodes ) ;
720751 return {
721752 xy : c . translate ,
722753 scale : c . scale ,
0 commit comments