drawGraphicsData et drawPath

Méthodes et classes de l’API de dessin du lecteur flash v10 (Flash CS4) utilisés dans cet article :

flash.display.GraphicsSolidFill
flash.display.GraphicsPath
flash.display.GraphicsStroke
flash.display.IGraphicsData
flash.display.Graphics.drawGraphicsData()
flash.display.Graphics.drawPath()


Pour cette présentation, j’ai mis en place un script qui permet de stocker les commandes de dessin (simple) de l’utilisateur, elles peuvent être ensuite répliqués et modifiés a volonté.

  • Dans la partie gauche de l’animation, un TextField affiche la manière dont les données de dessin sont stockés dans la variable GraphicsPath.
    c=1 correspond a une méthode moveTo()
    c=2 correspond a une méthode lineTo()
    les coordonnées sont la position X et Y.
  • La partie centrale permet de dessiner une forme a la souris.
  • le cadre en bas a droite est une miniature de la scène.

Les touches du clavier à utiliser :

  • ENTRER = Effacer toutes les données et le dessin.
  • ESPACE = recréer le dessin a partir des données stockés et créer la miniature du dessin de la scene.
  • SUPPRIMER = Effacer le dessin de la scène sans effacer les données.

le code :

package
{
	import flash.display.GraphicsPath;
	import flash.display.Graphics;
	import flash.display.IGraphicsData;
	import flash.display.GraphicsStroke;
	import flash.display.GraphicsSolidFill;
	import flash.display.Sprite;
	import flash.display.Shape;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.ui.Keyboard;
	import flash.utils.getTimer
	/**
	 * @author Lorenzo
	 *
	 * Test des nouvelles possibilités de l'API de dessin de Flash 10 : drawGraphicsData + GraphicsPath + drawPath + GraphicsStroke + ....
	 *
	 * -on dessine ce que l'on veut
	 * -on appuye DELETE pour effacer le dessin
	 * -on appuye sur SPACE pour recreer le dessin
	 * -on appuye sur ENTER pour tout remettre a zero
	 *
	 * une miniature du dessin est affiché en bas a droite
	 */
	public class Main5 extends Sprite
	{
		// -----------------------------------------------------------------------------------
		// DECLARATIONS
		// -----------------------------------------------------------------------------------
		private static const THICKNESS:uint = 1;
		private static const COLOR:uint = 0xFF0000;
		// le nombre max de données a stocker
		private static const MAX_LIGNES:uint = 20000;
 
		private var _txCode:TextField;
		private var _shapeMiniature:Shape;
		private var _shapeMiniatureContour:Shape;
 
		// les données de dessin (commandes (moveTo/lineTo) et coordonnées)
		private var _path:GraphicsPath = new GraphicsPath(new Vector.<int>(), new Vector.<Number>());
 
		// -----------------------------------------------------------------------------------
		// CONSTRUCTEUR
		// -----------------------------------------------------------------------------------
		public function Main5():void
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
 
		private function init(e:Event = null):void
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
 
			stage.scaleMode = "showAll";
 
			this._txCode = new TextField();
			this._txCode.width = 100;
			this._txCode.height = 800;
			this._txCode.background = true;
			this._txCode.defaultTextFormat = new TextFormat("Arial", 11);
			this._txCode.mouseWheelEnabled = true;
			this.addChild(this._txCode);
 
			this.graphics.lineStyle(THICKNESS, COLOR);
 
			// conteneur miniature
			this._shapeMiniatureContour = new Shape();
			this._shapeMiniatureContour.graphics.lineStyle(1, 0xFFFFFF, 0.5);
			this._shapeMiniatureContour.graphics.beginFill(0xAAAAAA, 0.5);
			this._shapeMiniatureContour.graphics.drawRect(0, 0, 200, 200);
			this._shapeMiniatureContour.x = 600;
			this._shapeMiniatureContour.y = 400;
			this.addChild(this._shapeMiniatureContour);
 
			this._shapeMiniature = new Shape();
			this._shapeMiniature.x = 600;
			this._shapeMiniature.y = 400;
			this.addChild(this._shapeMiniature);
 
			stage.addEventListener(MouseEvent.MOUSE_DOWN, evtStageMouseDown);
			stage.addEventListener(MouseEvent.MOUSE_UP, evtStageMouseUp);
			stage.addEventListener(KeyboardEvent.KEY_DOWN, evtStageKeyDown);
		}
 
		// -----------------------------------------------------------------------------------
		// EVENEMENTS
		// -----------------------------------------------------------------------------------
		private function evtStageMouseDown(event:MouseEvent):void
		{
			if ( this._path.data.length >= MAX_LIGNES ) {
				return;
			}
			this.graphics.moveTo(this.mouseX, this.mouseY);
			this._path.commands.push(1);
			this._path.data.push(this.mouseX, this.mouseY);
			this._txCode.appendText("C = 1 : " + this.mouseX + " x " + this.mouseY + "\n");
			stage.addEventListener(MouseEvent.MOUSE_MOVE, evtStageMouseMove);
		}
 
		private function evtStageMouseUp(event:MouseEvent):void
		{
			stage.removeEventListener(MouseEvent.MOUSE_MOVE, evtStageMouseMove);
		}
 
		private function evtStageMouseMove(event:MouseEvent):void
		{
			if ( this._path.data.length >= MAX_LIGNES ) {
				return;
			}
			this.graphics.lineTo(this.mouseX, this.mouseY);
			this._path.commands.push(2);
			this._path.data.push(this.mouseX, this.mouseY);
			this._txCode.appendText("C = 2 : " + this.mouseX + " x " + this.mouseY + "\n");
		}
 
		private function evtStageKeyDown(event:KeyboardEvent):void
		{
			switch (event.keyCode)
			{
				case Keyboard.SPACE :
					trace("données = " + this._path.data.length);
					var t:uint = getTimer();
 
					// recreer le dessin a partir des données GraphicsPath
					var stroke:GraphicsStroke = new GraphicsStroke(THICKNESS);
					stroke.fill = new GraphicsSolidFill(COLOR);
 
					var drawing:Vector.<IGraphicsData> = new Vector.<IGraphicsData>(); 
					drawing.push(stroke, this._path); 
 
					this.graphics.drawGraphicsData(drawing);
 
					trace("temps drawGraphicsData = " + (getTimer() - t));
					t = getTimer();
 
					// pareil mais en miniature et en utilisant drawPath aprés modification des
					// données GraphicsPath
					var tbPos:Vector.<Number> = new Vector.<Number>();
					var nbPos:uint = this._path.data.length;
					for (var i:int = 0; i < nbPos; i++)
					{
						tbPos[i] = i % 2 ? this._path.data[i] / 3 : (this._path.data[i] - 100) / 3.5;
					}
					this._shapeMiniature.graphics.lineStyle(THICKNESS, COLOR);
					this._shapeMiniature.graphics.drawPath(this._path.commands, tbPos);
 
					trace("temps drawPath + boucle = " + (getTimer() - t));
					break;
 
				case Keyboard.ENTER :
					// effacer les données
					this._txCode.text = "";
					this._path = new GraphicsPath(new Vector.<int>(), new Vector.<Number>()); 
 
				case Keyboard.DELETE :
					// effacer le dessin
					this.graphics.clear();
					this.graphics.lineStyle(THICKNESS, COLOR);
					this._shapeMiniature.graphics.clear();
					break;
			}
		}
	}
}


Même avec un grand nombre de données a dessiner/modifier, on remarque que l’exécution est trés rapide.
Imaginons un forum un Flash ou n’importe quel autre interface, on pourrait donc stocker en externe (XML/DB/..) la définition visuel de tous les composants afin d’ajouter la possibilité de créer/modifier un thème graphique de A à Z :-D
c’est trés plaisant !
Pour ceux qui ont installés FlashTracer dans Firefox, vous pouvez voir le trace du Flash qui affiche le nombre de données et le temps en milliseconde que prend les 2 types de dessin quand vous appuyez sur espace.
Le drawGraphicsData sur un le Vector comportant 10000 lignes (ce qui correspond quasiment au même nombre de ligne a dessiner), est executé en 1ms environ.

Concernant les nouveaux tableaux typés Vector, je m’attendais a des performances bien supérieur a un Array ou un Object, j’ai été décu ..
Suivant ce qui est stocké dans le Vector, on peut arriver a des performances inférieur a un Array 8-O, en stockant String par exemple, par contre avec uint et int les performances sont intéressantes.

Laisser un commentaire

*