7 Replies Latest reply on Oct 29, 2010 5:24 AM by kemsky

    Slow drag performance (code inside)

    Peacemaker2000

      Hello,

      in my project I have discovered very poor peformance while dragging things onto my custom component. To make sure it is not my component which is causing this I made a very small test project (see below) and the dragging is still very slow. Nothing special in this code, just a big green canvas with a bunch of smaller ones inside and a red canvas to simulate dragging. As soon as I enter the green canvas and move the mouse the performance is very bad.

       

      <?xml version="1.0" encoding="utf-8"?>
      <mx:Application
           xmlns:mx="http://www.adobe.com/2006/mxml"
           creationComplete="onCreationComplete(event)"
           layout="vertical"
           >
           
           <mx:Script>
                <![CDATA[
                     import mx.core.DragSource;
                     import mx.core.UIComponent;
                     import mx.events.DragEvent;
                     import mx.events.FlexEvent;
                     import mx.managers.DragManager;
                     
                     private static function randomInt(min:Number, max:Number):Number {
                          return Math.round((Math.random() * (max - min)) + min);
                     }
      
                     private function onMouseDown(event:MouseEvent):void {
                          var dragInitiator:UIComponent = UIComponent(event.currentTarget);
                          var ds:DragSource = new DragSource();
                          DragManager.doDrag(dragInitiator, ds, event);
                     }
                     
                     private function onDragOver(event:DragEvent):void {
                          mouseLocation.text = "X: " + event.localX + " Y: " + event.localY;
                          dragLocation.text = "X: " + event.currentTarget.mouseX + " Y: " + event.currentTarget.mouseY;
                     }
                     
                     private function onCreationComplete(event:FlexEvent):void {
                          for (var y:int = 0; y < 600; y += 60) { 
                               for (var x:int = 0; x < 15000; x += 50) {
                                    var child:Canvas = new Canvas();
                                    child.x = x;
                                    child.y = y;
                                    child.width = randomInt(10, 50);
                                    child.height = 60;
                                    child.setStyle("backgroundColor", "0x0000FF");
                                    dragTarget.addChild(child);
                               }
                          }
      
                          trace("Children = " + dragTarget.numChildren);
                     }
      
                     private function onDragEnterHandler(event:DragEvent):void {
                          DragManager.acceptDragDrop(dragTarget);
                     }
                ]]>
           </mx:Script>
           
           <mx:VBox x="0" y="0" width="100%" height="100%">
                <mx:HBox width="100%" height="50">
                     <mx:VBox height="100%">
                          <mx:Label id="mouseLocation"/>
                          <mx:Label id="dragLocation"/>
                     </mx:VBox>
                     <mx:Spacer width="100%"/>
                     <mx:Canvas
                          id="dragProxy"
                          backgroundColor="red"
                          mouseDown="onMouseDown(event)"
                          width="200"
                          height="100%"
                          />
                </mx:HBox>
      
                <mx:Canvas
                     id="dragTarget"
                     backgroundColor="green"
                     dragEnter="onDragEnterHandler(event)"
                     dragOver="onDragOver(event)"
                     width="100%"
                     height="100%"
                     />
           </mx:VBox>
      
      </mx:Application>
      
        • 1. Re: Slow drag performance (code inside)
          Karl_Sigiscar_1971 Level 3

          Quite normal.

           

          In your onCreationComplete() handler, you create an unacceptable amount of Canvas containers:

           

          (600 / 60) * (15000 / 50) = 10 * 300 = 3000 !!!!

           

          The more containers in a layout, the slower it gets.

           

                         private function onCreationComplete(event:FlexEvent):void {
                              for (var y:int = 0; y < 600; y += 60) {
                                   for (var x:int = 0; x < 15000; x += 50) {
                                        var child:Canvas = new Canvas();
                                        child.x = x;
                                        child.y = y;
                                        child.width = randomInt(10, 50);
                                        child.height = 60;
                                        child.setStyle("backgroundColor", "0x0000FF");
                                        dragTarget.addChild(child);
                                   }
                              }

                              trace("Children = " + dragTarget.numChildren);
                         }
          • 2. Re: Slow drag performance (code inside)
            Peacemaker2000 Level 1

            I know there are 3000 containers ... but in the real app this component is kind of like a schedule viewer which displays many items on a time based layout. So 3000 items is nothing special here when viewing a period of let's say a year.

            • 3. Re: Slow drag performance (code inside)
              Karl_Sigiscar_1971 Level 3

              Every technology has it optimizations.

               

              In Flex, you keep the number of containers to a minimum.

               

              If  your containers do not contain anything, I would instead create my own custom component, extending UIComponent. UIComponent has drag'n'drop functionnality. You can override the createChildren() method to add every component you need.

               

              http://livedocs.adobe.com/flex/3/langref/mx/core/UIComponent.html

              • 4. Re: Slow drag performance (code inside)
                Peacemaker2000 Level 1

                Actually there is a lot inside those containers in the real application, but I use an extended UIComponent anyway because of all the overhead a Canvas has. The Canvases were just for the example, but the actual application shows the same performance glitches ... maybe a little bit less, but that's subjective. The children of those UIComponents actually have different drag behaviours, thats why I can't simply set mouseEnabled or mouseChildren to false. The strange thing is that scrolling and everything else is surprisingly smooth, only the dragging is extremly slow.

                • 5. Re: Slow drag performance (code inside)
                  Matt Le Fevre Level 4

                  The strange thing is that scrolling and everything else is surprisingly smooth, only the dragging is extremly slow.

                   

                  that is most likely to the thousands of events that are being fired off as you drag your container over each item, whereas the scrolling is mere rendering.

                   

                   

                  I'd suggest either adopting a system where you need to display less containers at a time, or maybe adopting a different type of component, maybe a grid.

                  • 6. Re: Slow drag performance (code inside)
                    Peacemaker2000 Level 1

                    The question is why are there so many events being fired? For my understanding he only needs to dispatch events to the DisplayObjects which are on screen, which obviously isn't the case ... same as he does for rendering, where he also has offscreen items that won't get rendered. When I change the example code to only add the child when it is not offscreen (see below) everything works smooth for the resulting 320 containers. So I was thinking of some way to fool Flash into believing that he only has 320 children for dragging and 3000 children for rendering.

                     

                    private function onCreationComplete(event:FlexEvent):void {
                         for (var y:int = 0; y < 600; y += 60) { 
                              for (var x:int = 0; x < 15000; x += 50) {
                                   var child:Canvas = new Canvas();
                                   child.x = x;
                                   child.y = y;
                                   child.width = randomInt(10, 50);
                                   child.height = 60;
                                   child.setStyle("backgroundColor", "0x0000FF");
                                   if ( child.x < this.width ) dragTarget.addChild(child);
                              }
                         }
                    
                         trace("Children = " + dragTarget.numChildren);
                    }
                    
                    • 7. Re: Slow drag performance (code inside)
                      kemsky

                      i have found solution for the problem, see http://compile4fun.wordpress.com/2010/10/29/optimization-drag-and-drop/ its in russian, but you can use google translate.