@@ -33,15 +33,14 @@ export interface IHitBox extends HitBoxData {
3333export class HitTest extends Emitter {
3434 private tree = new RBush < HitBox > ( 9 ) ;
3535
36- protected empty = true ;
37-
3836 protected $usableRect = signal < TRect > ( { x : 0 , y : 0 , width : 0 , height : 0 } ) ;
3937
4038 // Single queue replaces all complex state tracking
4139 protected queue = new Map < HitBox , HitBoxData | null > ( ) ;
4240
4341 public get isUnstable ( ) {
4442 return (
43+ this . processQueue . isScheduled ( ) ||
4544 this . queue . size > 0 ||
4645 ( this . $usableRect . value . height === 0 &&
4746 this . $usableRect . value . width === 0 &&
@@ -57,8 +56,7 @@ export class HitTest extends Emitter {
5756 // Single debounced job replaces complex scheduler logic
5857 protected processQueue = debounce (
5958 ( ) => {
60- let needUpdateUsableRect = false ;
61-
59+ const items = [ ] ;
6260 for ( const [ item , bbox ] of this . queue ) {
6361 if ( bbox === null ) {
6462 // Remove operation
@@ -67,29 +65,28 @@ export class HitTest extends Emitter {
6765 // Add/update operation
6866 this . tree . remove ( item ) ;
6967 item . updateRect ( bbox ) ;
70- this . tree . load ( [ item ] ) ;
71- needUpdateUsableRect = true ;
68+ items . push ( item ) ;
7269 }
7370 }
71+ this . tree . load ( items ) ;
7472 this . queue . clear ( ) ;
75-
76- if ( needUpdateUsableRect ) {
77- this . updateUsableRect ( ) ;
78- }
73+ this . updateUsableRect ( ) ;
7974 this . emit ( "update" , this ) ;
8075 } ,
8176 {
82- priority : ESchedulerPriority . HIGHEST ,
77+ priority : ESchedulerPriority . LOWEST ,
8378 frameTimeout : 250 ,
8479 }
8580 ) ;
8681
87- public update ( item : HitBox , bbox : HitBoxData , force = false ) {
82+ public update ( item : HitBox , bbox : HitBoxData , _force = false ) {
8883 this . queue . set ( item , bbox ) ;
8984 this . processQueue ( ) ;
90- if ( force ) {
85+ // TODO: force update may be cause to unset unstable flag before graph is really made stable
86+ // Usually case: updateEntities update blocks and connections. In this case used force stategy, so every entity will be updated immediatelly, but async, so zoom will be unstable
87+ /* if (force) {
9188 this.processQueue.flush();
92- }
89+ } */
9390 }
9491
9592 public clear ( ) {
@@ -109,25 +106,13 @@ export class HitTest extends Emitter {
109106 this . processQueue ( ) ;
110107 }
111108
112- protected getBBox ( items : HitBox [ ] ) {
113- return items . reduce (
114- ( acc , item ) => {
115- if ( Number . isFinite ( item . minX ) ) {
116- acc . minX = Math . min ( acc . minX , item . minX ) ;
117- }
118- if ( Number . isFinite ( item . minY ) ) {
119- acc . minY = Math . min ( acc . minY , item . minY ) ;
120- }
121- if ( Number . isFinite ( item . maxX ) ) {
122- acc . maxX = Math . max ( acc . maxX , item . maxX ) ;
123- }
124- if ( Number . isFinite ( item . maxY ) ) {
125- acc . maxY = Math . max ( acc . maxY , item . maxY ) ;
126- }
127- return acc ;
128- } ,
129- { minX : 0 , minY : 0 , maxX : 0 , maxY : 0 }
130- ) ;
109+ public waitUsableRectUpdate ( callback : ( rect : TRect ) => void ) {
110+ if ( this . isUnstable ) {
111+ return this . once ( "update" , ( ) => {
112+ this . waitUsableRectUpdate ( callback ) ;
113+ } ) ;
114+ }
115+ callback ( this . $usableRect . value ) ;
131116 }
132117
133118 protected updateUsableRect ( ) {
0 commit comments