@@ -318,7 +318,11 @@ export default {
318
318
let j ; // the recursive calls; XX best rename - "i" too generic
319
319
let prev_i ; // for unhighlighting
320
320
let prev_j ; // for unhighlighting
321
+ // search for POPPERS: below for more detailed comments
321
322
let floatingBoxes = new Array ( n ) ; // XXX popper instances (rename)
323
+ let DELAY_POPPER_CREATE = 600 ;
324
+ let DELAY_POPPER_RESET = 700 ;
325
+ let DELAY_POPPER_SWAP = 700 ;
322
326
323
327
const partition = ( arr , left , right , mask , depth ) => {
324
328
i = left
@@ -353,8 +357,8 @@ cur_i, cur_j, cur_depth, A) => {
353
357
// The solution we use here is to schedule a forceUpdate()
354
358
// after a bit of a delay - seems to work ok on some
355
359
// devices at least...
356
- setTimeout ( ( ) => floatingBoxes [ _n1 ] . forceUpdate ( ) , 900 ) ;
357
- setTimeout ( ( ) => floatingBoxes [ _n2 ] . forceUpdate ( ) , 900 ) ;
360
+ setTimeout ( ( ) => floatingBoxes [ _n1 ] . forceUpdate ( ) , DELAY_POPPER_SWAP ) ;
361
+ setTimeout ( ( ) => floatingBoxes [ _n2 ] . forceUpdate ( ) , DELAY_POPPER_SWAP ) ;
358
362
} ,
359
363
[ n1 , n2 , real_stack , finished_stack_frames , i , j , depth ,
360
364
arr ] ,
@@ -433,90 +437,94 @@ arr],
433
437
finished_stack_frames . push ( real_stack . pop ( ) ) ;
434
438
}
435
439
436
- // XXX probably should rename to something like poppers
437
- // Handling is rather tricky. We have the global array of poppers
438
- // which is initially all null. When the second chunk is executed,
439
- // poppers are created and when later chunks are executed things
440
- // can move around. When we step backwards, we go back and execute
441
- // from the first chunk, so the first chunk cleans up and destroys
442
- // all the existing poppers and later chunks re-create them. To
443
- // make things more complicated, its all asynchronous, so we put
444
- // delays in to (hopefully) stop it screwing up.
440
+ // XXX probably should rename floatingBoxes to something like poppers.
441
+ // POPPERS:
442
+ // Handling is rather tricky. We have the global array of poppers,
443
+ // which display the binary version of the data when the mouse is
444
+ // over the data. They are derived from the HTML displayed (the
445
+ // array renderer puts wrappers around array elements). However,
446
+ // the display of HTML is asynchronous, making things a bit of a
447
+ // nightmare, to put it mildly. When the algorithm is initially
448
+ // loaded/run, the array is filled with nulls. When the first
449
+ // chunk is executed for the first time, a popper is created for
450
+ // each data item and put in the array. A carefully crafted delay
451
+ // (using setTimeout) is inserted before popper creation to allow
452
+ // the HTML array contents to be rendered first. When array
453
+ // elements are swapped, the wrappers that the poppers rely on are
454
+ // swapped with them so the poppers automatically follow the data
455
+ // around... almost. They need to update their location (so the
456
+ // popper appears next to the current location of the data, not
457
+ // where the data used to be or some other random point); we use
458
+ // forceUpdate(), which also needs to be inside a setTimeout to
459
+ // allow rendering to take place first. Just to add to the
460
+ // complexity, if the execution steps backwards, all the chunks
461
+ // are re-executed, starting from the first one. The first chunk
462
+ // therefore checks if poppers have already been created and, if
463
+ // so, calls forceUpdate() (inside setTimeout of course) for each
464
+ // popper so it gets the right screen location.
465
+ // XXX It would probably be nicer to allow users to click on a
466
+ // data element and have that displayed with the mask etc. This
467
+ // was implemented in the BROKEN-radix-click4binary branch but it
468
+ // somehow breaks react - no further stepping through the
469
+ // animation is possible after a click:(
445
470
floatingBoxes . fill ( null ) ;
446
471
472
+ // We don't display maxIndex yet but use it for creating poppers
473
+ // with the desired number of bits. We want to create the poppers
474
+ // in the first chunk so there is a bit of a delay before anything
475
+ // else happens.
476
+ maxIndex = A . indexOf ( Math . max ( ...A ) )
477
+ const mask = getMaximumBit ( A ) ;
478
+
447
479
// Initialise the array on start
448
480
chunker . add ( MSD_BOOKMARKS . start ,
449
- ( vis , array ) => {
481
+ ( vis , array , mask ) => {
450
482
vis . array . set ( array , 'MSDRadixSort' )
451
483
vis . array . setSize ( 5 ) ; // more space for array
452
484
vis . array . setZoom ( 0.90 ) ;
453
- // destroy existing poppers, replace with null
454
- floatingBoxes . forEach ( ( p ) => {
455
- if ( p !== null ) {
456
- console . log ( 'popper gone' ) ;
457
- p . state . elements . popper . innerHTML = "" ; // reset HTML
458
- p . forceUpdate ( ) ;
459
- p . destroy ( ) ; // remove popper
460
- return null ; // array el. = null
485
+ // set up poppers
486
+ // A bit of a nightmare due to asynchronous programming. The
487
+ // first time this is called we create the poppers (after a
488
+ // delay); subsequently we just update them (after a delay).
489
+ // XXX could just use one setTimeout for all the poppers
490
+ for ( let idx = 0 ; idx < array . length ; idx ++ ) {
491
+ if ( floatingBoxes [ idx ] === null ) {
492
+ setTimeout ( ( ) => {
493
+ const popper = document . getElementById ( 'float_box_' + idx ) ;
494
+ const slot = document . getElementById ( 'chain_' + idx ) ;
495
+ floatingBoxes [ idx ] = createPopper ( slot , popper , {
496
+ placement : "right-start" ,
497
+ strategy : "fixed" ,
498
+ modifiers : [
499
+ {
500
+ removeOnDestroy : true , // doesn't work well?
501
+ name : 'preventOverflow' ,
502
+ options : {
503
+ // XXX popper_boundary not defined for 1D
504
+ // array - maybe it should be??
505
+ boundary : document . getElementById ( 'popper_boundary' ) ,
506
+ } ,
507
+ } ,
508
+ ]
509
+ } ) ;
510
+ popper . innerHTML = array [ idx ] . toString ( 2 ) . padStart ( mask + 1 , "0" ) ;
511
+ } , DELAY_POPPER_CREATE ) ;
512
+ } else {
513
+ setTimeout ( ( ) => floatingBoxes [ idx ] . forceUpdate ( ) , DELAY_POPPER_RESET ) ;
461
514
}
462
- } ) ;
515
+ }
463
516
} ,
464
- [ nodes ] ,
517
+ [ A , mask ] ,
465
518
0
466
519
)
467
520
468
- maxIndex = A . indexOf ( Math . max ( ...A ) )
469
- const mask = getMaximumBit ( A ) ;
470
-
471
- // Highlight the index
521
+ // Highlight the index of the max element + init mask
472
522
chunker . add ( MSD_BOOKMARKS . get_mask ,
473
523
( vis , maxIndex , mask , A ) => {
474
524
highlight ( vis , maxIndex )
475
525
vis . mask . setMaxBits ( mask + 1 )
476
526
updateMask ( vis , mask )
477
527
updateBinary ( vis , A [ maxIndex ] )
478
- // set up poppers
479
- // A bit of a nightmare due to asynchronous programming. If
480
- // we have stepped backwards the poppers have been reset and
481
- // destroyed but if we immediately create new poppers some
482
- // of the old state persists. If we wait a while then create
483
- // them it seems to work on some devices at least...
484
- // XXX do popper.innerHTML = immediately; use setTimeout for createPopper
485
- // XXX have array for the popper.innerHTML stuff?,
486
- setTimeout ( ( ) => {
487
- for ( let idx = 0 ; idx < A . length ; idx ++ ) {
488
- const popper = document . getElementById ( 'float_box_' + idx ) ;
489
- const slot = document . getElementById ( 'chain_' + idx ) ;
490
- floatingBoxes [ idx ] = createPopper ( slot , popper , {
491
- placement : "right-start" ,
492
- strategy : "fixed" ,
493
- modifiers : [
494
- {
495
- removeOnDestroy : true , // doesn't work well?
496
- name : 'preventOverflow' ,
497
- options : {
498
- // XXX popper_boundary not defined for 1D
499
- // array - maybe it should be??
500
- boundary : document . getElementById ( 'popper_boundary' ) ,
501
- } ,
502
- } ,
503
- ]
504
- } ) ;
505
- popper . innerHTML = A [ idx ] . toString ( 2 ) . padStart ( mask + 1 , "0" ) ;
506
- }
507
- } , 1000 ) ;
508
- /*
509
- console.log(floatingBoxes);
510
- setTimeout( () => {
511
- console.log(floatingBoxes);
512
- floatingBoxes.forEach((p) => {
513
- if (p !== null) {
514
- p.setOptions({placement: "right-start"});
515
- p.forceUpdate()
516
- }
517
- })
518
- }, 2000);
519
- */
520
528
} ,
521
529
[ maxIndex , mask , A ] ,
522
530
0
0 commit comments