flash propagation_bubbling
The bubbling phase
The bubbling phase is the last propagation phase. During this phase the event traverses the opposite direction from the capture phase, notifying each parent node of the target object. The direction of the event during this phase is compared to a bubble rising to the water’s surface. It is for this reason that it is called the bubbling phase. The rising event ultimately targets the stage object:
To subscribe a listener to the bubbling phase we call the add EventListener method on one of the parent graphic objects by passing the Boolean value false to the useCapture parameter:
myParentObject.addEventListener ( MouseEvent.CLICK, clickBubbling, false );
By reading the signature of the addEventListener method we see that the useCapture parameter is false by default:
public function addEventListener(type: String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
The subscription to the bubbling phase can be written without specifying the useCapture parameter:
objetParent.addEventListener ( MouseEvent.CLICK, clickBubbling );
This indicates that when we listen to an event for the target phase, the bubbling phase is automatically listened to.
The clickBubbling function will also therefore receive the MouseEvent.CLICK events coming from the children during their bubbling phase.
In the following example we listen to the MouseEvent.CLICK event at the time of capture and the bubbling phase in the container:
// number of windows var lng:int = 12; // creation of a container var windowsContainer:Sprite = new Sprite(); // added to the display list addChild ( windowsContainer ); var myWindow:Window; for (var i:int = 0; i< lng; i++ ) { myWindow = new Window(); myWindow.x = 7 + Math.round ( i % 3 ) * ( myWindow.width + 10 ); myWindow.y = 7 + Math.floor ( i / 3 ) * ( myWindow.height + 10 ); windowsContainer.addChild ( myWindow ); } // subscription of the container for the capture phase windowsContainer.addEventListener ( MouseEvent.CLICK, captureClick, true ); // subscription of the container for the bubbling phase windowsContainer.addEventListener ( MouseEvent.CLICK, clickBubbling ); function captureClick ( pEvt:MouseEvent ):void { /* displays : capture phase of the event: click node in notification progress: [object Sprite] */ if ( pEvt.eventPhase == EventPhase.CAPTURING_PHASE ) { trace("capture phase of the event: " + pEvt.type ); trace("node in notification progress: " + pEvt.currentTarget ); } } function clickBubbling ( pEvt:MouseEvent ):void { /* displays : bubbling phase of the event: click node in notification progress: [object Sprite] */ if ( pEvt.eventPhase == EventPhase.BUBBLING_PHASE ) { trace("bubbling phase of the event: " + pEvt.type ); trace("node in notification progress: " + pEvt.currentTarget ); } }
We’re going to go further by adding an automatic re-organisation of the windows when one of them is deleted.
To do this we modify the code by integrating an inertia effect in order to give each instance of the Window class a slowing down effect:
// modification of the animation speed stage.frameRate = 30; for (var i:int = 0; i< lng; i++ ) { myWindow = new Window(); myWindow.destX = 7 + Math.round ( i % 3 ) * ( myWindow.width + 10 ); myWindow.destY = 7 + Math.floor ( i / 3 ) * ( myWindow.height + 10 ); myWindow.addEventListener ( Event.ENTER_FRAME, movement ); windowsContainer.addChild ( myWindow ); } function movement ( pEvt:Event ):void { // inertia algorithm pEvt.target.x -= ( pEvt.target.x - pEvt.target.destX ) * .3; pEvt.target.y -= ( pEvt.target.y - pEvt.target.destY ) * .3; }
Then we integrate the necessary logic in the captureClick and clickBubbling listening functions:
// number of windows var lng:int = 12; // creation of a container var windowsContainer:Sprite = new Sprite(); // added to the display list addChild ( windowsContainer ); var myWindow:Window; // modification of the animation speed stage.frameRate = 30; for (var i:int = 0; i< lng; i++ ) { myWindow = new Window(); myWindow.destX = 7 + Math.round ( i % 3 ) * ( myWindow.width + 10 ); myWindow.destY = 7 + Math.floor ( i / 3 ) * ( myWindow.height + 10 ); myWindow.addEventListener ( Event.ENTER_FRAME, movement ); windowsContainer.addChild ( myWindow ); } function movement ( pEvt:Event ):void { // inertia algorithm pEvt.target.x -= ( pEvt.target.x - pEvt.target.destX ) * .3; pEvt.target.y -= ( pEvt.target.y - pEvt.target.destY ) * .3; } // subscription of the container for the capture phase windowsContainer.addEventListener ( MouseEvent.CLICK, captureClick, true ); // subscription of the container for the bubbling phase windowsContainer.addEventListener ( MouseEvent.CLICK, clickBubbling ); function captureClick ( pEvt:MouseEvent ):void { pEvt.currentTarget.removeChild ( DisplayObject ( pEvt.target ) ); } function clickBubbling ( pEvt:MouseEvent ):void { var lng:int = pEvt.currentTarget.numChildren; var graphicObject:DisplayObject; var myWindow:Window; while ( lng-- ) { // recuperation of graphic objects graphicObject = pEvt.currentTarget.getChildAt ( lng ); // if one of them is a Window type if ( graphicObject is Window ) { // we transtype it into a Window type myWindow = Window ( graphicObject ); // repositioning of each occurrence myWindow.destX = 7 + Math.round ( lng % 3 ) * ( myWindow.width + 10 ); myWindow.destY = 7 + Math.floor ( lng / 3 ) * ( myWindow.height + 10 ); } } }
We benefit from the bubbling phase in that the container reorganizes its child objects when one of them is deleted from the display list.
We will see in the article entitled Object Oriented Programming how our code could be even better.
Mediabox Training Centre © 2000 - 2008 All rights reserved.
Adobe Authorized Training Centre. State convention under number 25 14 02167 14.
Mediabox : SARL au capital de 62.000€ - Activity number: 25 14 02167 14 - SIRET : 493 716 468 00027
MEDIABOX, 102 Avenue des Champs Elysées, 75008 PARIS - Tel. +33(0)2.31.91.96.89 - Fax. +33(0)2.72.68.56.42



