1 Reply Latest reply on Mar 12, 2014 1:38 PM by Aaron Beall

    Drag selection in spark datagrid?

    Aaron Beall Level 3

      Is there an easy way to enable a spark DataGrid to use drag selection, similar to how you can select cells in Excel or Google Docs? Or will I need to track mouse movements and manually manipulate the selectedCells?

       

      Thanks!

      -Aaron

        • 1. Re: Drag selection in spark datagrid?
          Aaron Beall Level 3

          Couldn't find a built in way to do this, but it turned out to be pretty easy thanks to the GridEvent classes that solve the challenge of know what row/column index the mouse is interacting with. My final solution:

           

          A class that extends spark::DataGrid

           

          private var _allowDragSelection:Boolean = false;
          
          
          private var dragSelectionAnchor:CellPosition;
          private var dragSelectionStarted:Boolean;
          
          
          /**
           * If true and selectionMode is GridSelectionMode.MULTIPLE_CELLS the user can drag their
           * mouse to select a rectangular area of cells, just like Excel or Google Docs.
           */
          public function get allowDragSelection():Boolean { return this._allowDragSelection; }
          public function set allowDragSelection(value:Boolean):void {
                    if(this._allowDragSelection == value)
                              return;
                    this._allowDragSelection = value;
          
                    if(this.allowDragSelection)
                              this.addEventListener(GridEvent.GRID_MOUSE_DOWN, this.handleGridMouseDown);
                    else
                              this.removeEventListener(GridEvent.GRID_MOUSE_DOWN, this.handleGridMouseDown);
          }
          
          private function handleGridMouseDown(e:GridEvent):void {
                    if(this.selectionMode != GridSelectionMode.MULTIPLE_CELLS)
                              return;
          
                    this.dragSelectionAnchor = new CellPosition(e.rowIndex, e.columnIndex);
                    this.dragSelectionStarted = false;
          
                    this.addEventListener(GridEvent.GRID_MOUSE_DRAG, this.handleGridMouseDrag);
                    this.stage.addEventListener(MouseEvent.MOUSE_UP, this.handleDragMouseUp);
          }
          
          
          private function handleGridMouseDrag(e:GridEvent):void {
                    // don't start processing selection drag until mouse has left the selection anchor
                    if(!this.dragSelectionStarted && e.rowIndex == this.dragSelectionAnchor.rowIndex && e.columnIndex == this.dragSelectionAnchor.columnIndex)
                              return;
          
                    // once started, process changes even if the user drags back over the anchor
                    this.dragSelectionStarted = true;
                    
                    // local to avoid expensive getter cost
                    const selectedCells:Vector.<CellPosition> = e.grid.selectedCells;
                    
                    // determine the selection rectangle from the anchor to the current cell
                    const rowFromIndex:int = Math.min(this.dragSelectionAnchor.rowIndex, e.rowIndex);
                    const rowToIndex:int = Math.max(this.dragSelectionAnchor.rowIndex, e.rowIndex);
                    const colFromIndex:int = Math.min(this.dragSelectionAnchor.columnIndex, e.columnIndex);
                    const colToIndex:int = Math.max(this.dragSelectionAnchor.columnIndex, e.columnIndex);
          
                    // create new cell positions selection vector, and track if any new cell is added
                    var cells:Vector.<CellPosition> = new Vector.<CellPosition>();
                    var cellsChanged:Boolean = false;
                    for(var row:int = rowFromIndex; row <= rowToIndex; row++){
                              for(var col:int = colFromIndex; col <= colToIndex; col++){
                                        var cell:CellPosition = new CellPosition(row, col);
                                        cells.push(cell);
                                        cellsChanged = cellsChanged || !selectedCells.some(function(c:CellPosition, i:int, v:Vector.<CellPosition>):Boolean {
                                                  return c.rowIndex == cell.rowIndex && c.columnIndex == cell.columnIndex;
                                        });
                              }
                    }
          
                    // assign the new selection only if it changed (Flex is pretty slow here with big selections)
                    if(cellsChanged || selectedCells.length != cells.length){
                              this.selectedCells = cells;
                              // maintain the selection anchor for any following SHIFT click selection
                              this.grid.anchorRowIndex = rowFromIndex;
                              this.grid.anchorColumnIndex = colFromIndex;
                    }
          }
          
          
          private function handleDragMouseUp(e:MouseEvent):void {
                    this.removeEventListener(GridEvent.GRID_MOUSE_DRAG, this.handleGridMouseDrag);
                    this.stage.removeEventListener(MouseEvent.MOUSE_UP, this.handleDragMouseUp);
          }
          

           

           

           

          Cheers.

          -Aaron