Table of contents
- Resizable Canvas - Horizontally
- Resizable Canvas - …and Vertically
- Resizable Canvas - …both directions
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:
- initialization
- adding the right edge
- add the setter to enable/disable the resize funtionality
- 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.
| ||
|
Tags: ActionScript, canvas, drag, event, resize
This post was written by Andrei Ionescu
Views: 2866


















