@@ -318,7 +318,11 @@ export default {
318318 let j ; // the recursive calls; XX best rename - "i" too generic
319319 let prev_i ; // for unhighlighting
320320 let prev_j ; // for unhighlighting
321+ // search for POPPERS: below for more detailed comments
321322 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 ;
322326
323327 const partition = ( arr , left , right , mask , depth ) => {
324328 i = left
@@ -353,8 +357,8 @@ cur_i, cur_j, cur_depth, A) => {
353357 // The solution we use here is to schedule a forceUpdate()
354358 // after a bit of a delay - seems to work ok on some
355359 // 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 ) ;
358362 } ,
359363 [ n1 , n2 , real_stack , finished_stack_frames , i , j , depth ,
360364arr ] ,
@@ -433,90 +437,94 @@ arr],
433437 finished_stack_frames . push ( real_stack . pop ( ) ) ;
434438 }
435439
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:(
445470 floatingBoxes . fill ( null ) ;
446471
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+
447479 // Initialise the array on start
448480 chunker . add ( MSD_BOOKMARKS . start ,
449- ( vis , array ) => {
481+ ( vis , array , mask ) => {
450482 vis . array . set ( array , 'MSDRadixSort' )
451483 vis . array . setSize ( 5 ) ; // more space for array
452484 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 ) ;
461514 }
462- } ) ;
515+ }
463516 } ,
464- [ nodes ] ,
517+ [ A , mask ] ,
465518 0
466519 )
467520
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
472522 chunker . add ( MSD_BOOKMARKS . get_mask ,
473523 ( vis , maxIndex , mask , A ) => {
474524 highlight ( vis , maxIndex )
475525 vis . mask . setMaxBits ( mask + 1 )
476526 updateMask ( vis , mask )
477527 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- */
520528 } ,
521529 [ maxIndex , mask , A ] ,
522530 0
0 commit comments