Fx{r} is trying to start the Fx{r} Community! Please join our group on Adobe Groups following this link: http://groups.adobe.com/groups/ab29539ab9.
Fx{r} is now on Twitter too. Follow us @ twitter.com/fx_r!
«
»

ActionScript, Events, How to, Skin

Resizable Canvas – Horizontally

Andrei Ionescu | 25.04.08 | 2 Comments

Google Buzz

Yesterday I started to implement a new control: Resizable Canvas. A very interesting task which needed some thinking because there are more than one ways to achieve this.

My implementation is based on a canvas that includes a reskined button as the right edge of the canvas for dragging. The canvas will be resized when the button will be dragged. The steps are:

  1. initialization
  2. adding the right edge
  3. add the setter to enable/disable the resize funtionality
  4. adding the events on the right edge
    • mouse over – to show the resize cursor
    • mouse out – to hide the resize cursor
    • mouse down – to start the drag
    • mouse up – to end the drag
    • enter frame – to do the resize

The application can be seen bellow:

Bellow is listed the code for the ResizeCanvas class with comments for easy understanding:

package
{
    import mx.containers.Canvas;
    import mx.controls.Button;
    import mx.managers.CursorManager;
    import flash.events.MouseEvent;
    import flash.events.Event;
 
    public class ResizableCanvas extends Canvas
    {
        // right edge of the canvas
        private var _rightEdge:Button;
        // if it is resizable
        // it can be set as not resizable
        private var _resizable:Boolean;
        // the cursor id
        private var _currentCursorId:int;
        // true if the drag started
        private var _dragStarted:Boolean;
        // the position before starting to drag
        private var _dragStartPosition:int;
        // last width of our canvas before starting to drag
        private var _dragLastWidth:int;
        // cursor image
        [Embed("resources/img/h_resize.gif")]
        private var hResizeCursor:Class;
 
        // Constructor
        public function ResizableCanvas():void
        {
            super();
            // initialization
            _dragStarted = false;
            _dragStartPosition = 0;
            _currentCursorId = -1;
            // by default our canvas is resizable
            resizable = true;
        }
 
        // setter to enable/disable the resize functionality
        public function set resizable(value:Boolean):void
        {
            // if the value is changed
            if (value != _resizable)
            {
                if (value)
                {
                    // resizable = true
 
                    // we add the right edge which is a button
                    _rightEdge = new Button();
                    // no label
                    _rightEdge.label = "";
                    // no tooltip
                    _rightEdge.tabEnabled = false;
                    _rightEdge.toolTip = null;
                    _rightEdge.setStyle("right", 0);
                    _rightEdge.setStyle("verticalCenter",0);
                    _rightEdge.percentHeight = 95;
                    _rightEdge.width = 9;
                    // set its style
                    // in this style we set the skin to not show anything
                    _rightEdge.styleName = "canvasRightEdge";
 
                    // used to display the resize icon
                    _rightEdge.addEventListener(MouseEvent.MOUSE_OVER, handleResizeOver, false, 0 ,true);
                    // used to display the resize icon
                    _rightEdge.addEventListener(MouseEvent.MOUSE_MOVE, handleResizeOver, false, 0 ,true);
                    // used to hide the resize icon
                    _rightEdge.addEventListener(MouseEvent.MOUSE_OUT, handleResizeOut, false, 0 ,true);
                    // used to start the drag
                    // we save the initial position and width
                    _rightEdge.addEventListener(MouseEvent.MOUSE_DOWN, handleDragStart, false, 0 ,true);
                    // used for real rezise and other important stuff
                    _rightEdge.addEventListener(Event.ENTER_FRAME, handleDragMove, false, 0 ,true);
                    // used to stop the drag - mouse up on the edge
                    _rightEdge.addEventListener(MouseEvent.MOUSE_UP, handleDragStop, false, 0 ,true);
 
                    addChild(_rightEdge);
 
                } else {
                    // resizable = false
 
                    // we check if the events are created and we remove them
                    if (_rightEdge.hasEventListener(MouseEvent.MOUSE_OVER))
                        _rightEdge.removeEventListener(MouseEvent.MOUSE_OVER, handleResizeOver);
                    if (_rightEdge.hasEventListener(MouseEvent.MOUSE_OUT))
                        _rightEdge.removeEventListener(MouseEvent.MOUSE_OUT, handleResizeOut);
                    if (_rightEdge.hasEventListener(MouseEvent.MOUSE_DOWN))
                        _rightEdge.removeEventListener(MouseEvent.MOUSE_DOWN, handleDragStart);
                    if (_rightEdge.hasEventListener(MouseEvent.MOUSE_UP))
                        _rightEdge.removeEventListener(MouseEvent.MOUSE_UP, handleDragStop);
                    if (_rightEdge.hasEventListener(Event.ENTER_FRAME))
                        _rightEdge.removeEventListener(Event.ENTER_FRAME, handleDragMove);
                    // we check if the stage if created and if it has the event listener
                    if (stage != null && stage.hasEventListener(MouseEvent.MOUSE_UP))
                        stage.removeEventListener(MouseEvent.MOUSE_UP, handleDragStop);
                    // we remove the edge
                    removeChild(_rightEdge);
                }
                // set the resizable value
                // used to see if the value is changed
                _resizable = value;
            }
        }
 
        // event handler to show the resize cursor
        private function handleResizeOver(event:MouseEvent):void
        {
            // check if we already have the resize cursor set
            if (_currentCursorId == -1)
                _currentCursorId = CursorManager.setCursor(hResizeCursor,2,-10);
        }
 
        // event handler to hide the resize cursor
        private function handleResizeOut(event:MouseEvent):void
        {
            if (!_dragStarted) {
                CursorManager.removeCursor(_currentCursorId);
                _currentCursorId = -1;
            }
        }
 
        // event handler to start the drag
        private function handleDragStart(event:MouseEvent):void
        {
            _dragStarted = true;
            // we save the initial position and width
            _dragStartPosition = stage.mouseX;
            _dragLastWidth = width;
        }
 
        // event handler to stop the drag
        private function handleDragStop(event:MouseEvent):void
        {
            _dragStarted = false;
            CursorManager.removeCursor(_currentCursorId);
            _currentCursorId = -1;
        }
 
        // event handler for real rezise and other important stuff
        private function handleDragMove(event:Event):void
        {
            // we put the edge always on the top of the other children
            if (getChildIndex(_rightEdge) < numChildren-1)
                setChildIndex(_rightEdge,numChildren-1);
            // we add the event to stop the drag also on the stage
            // we cannot add this event in set resizable because the
            // stage is not created because set resizable is done at
            // constructor time and stage is set after adding our
            // canvas to the application
            if (!stage.hasEventListener(MouseEvent.MOUSE_UP))
                stage.addEventListener(MouseEvent.MOUSE_UP, handleDragStop, false, 0 ,true);
            // we resize our canvas only if drag started
            if (_dragStarted)
            {
                // get the amount of movement
                // difference between the current mouse x position relative 
                // to the stage and the saved position at mouse down event
                var movement:int = (stage.mouseX - _dragStartPosition);
                // if the canvas is positioned relative to the center
                // the width will be changed in both left and right directions
                // so we will double the movement
                if (getStyle("horizontalCenter") != undefined)
                {
                    movement *= 2;
                }
                // if we move to the left
                if (movement <= 0)
                {
                    // check not to pass the minimum width
                    if (minWidth < _dragLastWidth + movement)
                        width = _dragLastWidth + movement;
                    else
                        width = minWidth;
                } else {
                    // check not to pass the maximum width
                    if (maxWidth > _dragLastWidth + movement)
                        width = _dragLastWidth + movement;
                    else
                        width = maxWidth;
                }
            }
        }
    }
}

What resources are needed for this: the resize icon, the style sheet and the skin class for the right edge. The styles are loaded in the main application and the skin class is used in the style sheet.

.canvasRightEdge {
	disabledSkin: ClassReference("resources.skin.CanvasRightEdgeSkin");
	downSkin: ClassReference("resources.skin.CanvasRightEdgeSkin");
	overSkin: ClassReference("resources.skin.CanvasRightEdgeSkin");
	upSkin: ClassReference("resources.skin.CanvasRightEdgeSkin");
	selectedDisabledSkin: ClassReference("resources.skin.CanvasRightEdgeSkin");
	selectedDownSkin: ClassReference("resources.skin.CanvasRightEdgeSkin");
	selectedOverSkin: ClassReference("resources.skin.CanvasRightEdgeSkin");
	selectedUpSkin: ClassReference("resources.skin.CanvasRightEdgeSkin");
}

To remove the button but without loosing its interaction surface (making it invisible) is to set alpha to 0 on all skins. I copied the Button skins from “%path_to_flex_builder%\Flex SDK 2\frameworks\source\mx\skins\halo\ButtonSkin.as” to my resources/skin folder in the project, then line by line where drawRoundRect is I modified all alphas to [0,0]. This way nothing is displayed anymore because any drawing has its alpha set to 0 (invisible). At the end I added those three vertical lines as drag handle.

graphics.lineStyle(1,0xAAAAAA,1);
graphics.moveTo(Math.floor(w/2)-2,Math.floor(h/2)-7);
graphics.lineTo(Math.floor(w/2)-2,Math.floor(h/2)+7);
graphics.moveTo(Math.floor(w/2),Math.floor(h/2)-7);
graphics.lineTo(Math.floor(w/2),Math.floor(h/2)+7);
graphics.moveTo(Math.floor(w/2)+2,Math.floor(h/2)-7);
graphics.lineTo(Math.floor(w/2)+2,Math.floor(h/2)+7);

If you don’t want that handle just remove the lines above from the skin file.

ResizableCanvas class can be used like a regular Canvas the main difference being the resizable property that can be used to make it not resizable.

The source files are at the end so you can study the entire code.

Share and Enjoy:
  • Twitter
  • Google Buzz
  • LinkedIn
  • Google Bookmarks
  • del.icio.us
  • Digg
  • Sphinn
  • blogmarks
  • Reddit
  • StumbleUpon
  • Facebook
  • DZone
  • FriendFeed
  • Yahoo! Buzz
  • Yahoo! Bookmarks
  • Slashdot
  • MySpace
  • Add to favorites
ResizableCanvasApplication
ResizableCanvas_sources




Tags: , , , ,

This post was written by Andrei Ionescu

Views: 7145

related

2 Comments

have your say

Add your comment below, or trackback from your own site. Subscribe to these comments.

Be nice. Keep it clean. Stay on topic. No spam.

You can use these tags:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

:

:


«
»