Comment ajouter le contrôle du geste de la souris à vos projets Flash gestes simples

J'ai récemment acheté mon premier Bamboo, une tablette Wacom qui reconnaît les lettres à partir de formes dessinées au stylet. Cela rappelait ma première expérience avec une application contrôlée par gestes: à l'aide de gestes de la souris, les navigateurs Web tels que Maxthon (et plus tard Opera) permettaient aux utilisateurs de parcourir rapidement les pages Web de l'historique, de basculer entre différents onglets, etc. Je suis fasciné par son interface utilisateur soignée, car il enlève les clics de souris traditionnels. Bien sûr, des appareils sophistiqués à commande gestuelle tels que Kinect, iPad et iPhone sont maintenant disponibles, mais tout a commencé avec le bon vieux PC. Dans ce didacticiel, vous allez apprendre à développer une galerie de photos qui reconnaît les gestes singuliers de la souris..


Aperçu du résultat final

Jetons un coup d'œil au résultat final sur lequel nous allons travailler. Pour effectuer un panoramique de la galère dans les quatre directions principales, cliquez et faites glisser la souris dans la direction appropriée. Pour redimensionner une photo, faites glisser la souris vers le sud-est pour la redimensionner et faites-la glisser vers le nord-ouest pour la redimensionner à la taille par défaut.

(Remarque: cela ne permet pas de centrer la photo lorsque vous effectuez un panoramique; il est sensible à la longueur de la ligne que vous tracez.)


Étape 1: déroulement du didacticiel

Voici ce que vous allez apprendre dans ce tutoriel et l'ordre dans lequel vous allez l'apprendre:

  • Interprétation vectorielle des gestes de la souris
  • Implémentation codée en dur des gestes de la souris
  • Classe pour détecter les gestes singuliers de la souris
  • Exemple d'application (galerie de photos) en utilisant la classe mentionnée

Étape 2: Détection de geste: analyse vectorielle

Il est important de comprendre le vecteur mathématique impliqué dans la détection des gestes de la souris. Après avoir compris la détection d'une seule direction, on peut facilement étendre la compréhension à l'ensemble des huit directions.

La présentation Flash ci-dessous montre les étapes de la détection d'un simple geste de la souris à droite. Pour faire défiler les images de la présentation Flash ci-dessous, (souris vers le bas - déplacer la souris - souris vers le haut) dans l’une des directions suivantes:

  • Vers l'est pour faire défiler l'image vers l'avant
  • Vers l'ouest pour faire défiler le cadre en arrière
  • Vers le nord pour sauter à la dernière image
  • Vers le sud pour passer à la première image

Étape 3: Détection de geste: atténuation des angles

La mise en œuvre de l'étape 2 sera facile. Cependant, il y a 90% de chances que les gestes des utilisateurs échouent. Le diagramme ci-dessous montre les gestes couramment commis (milieu); ils se conforment rarement à un vecteur rigide pointant vers la droite (gauche). Il est donc préférable d’atténuer les inexactitudes gestuelles (droite)..

Par exemple, nous pouvons donner une atténuation de 30 ° des deux côtés du vecteur pointant vers la droite, de sorte que l'angle du vecteur d'un geste compris dans cette plage soit accepté et interprété comme un geste de droite..


Étape 4: Détection de geste: exemple d'implémentation

Vous trouverez ci-dessous une implémentation de la détection de geste due à droite. Appuyez sur la souris, déplacez la souris vers la droite et relâchez la souris dans la présentation Flash ci-dessous. Essayez de faire un geste du droit absolu de vérifier la mise en œuvre de l'allégement.


Étape 5: Variables

Regardons les variables de notre implémentation codée en dur à l'étape 4. J'ai mis en évidence les variables importantes de Vector2D. Prenez note des commentaires que j'ai placés à la fin de chaque variable.

 var privé: TextField; private var antérieur: Vector2D // stocke l'emplacement de la souris lors du premier clic privé var dernier: Vector2D // stocke l'emplacement de la souris lors de la validation privé var RIGHT: Vector2D = new Vector2D (1, 0); // vecteur de DROIT absolu

Étape 6: Implémentation codée en dur

Je suppose que vous connaissez déjà les bases de la mise en Champ de texte dans votre projet, je me concentrerai donc sur la mise en oeuvre ActionScript du geste de la souris. La mise en œuvre telle qu'indiquée ci-dessous est fortement commentée. Important Les calculs vectoriels sont également mis en évidence. J'encourage les lecteurs à examiner ces commentaires, en particulier ceux mis en évidence, à comprendre les opérations lors de différents événements lors de l'exécution.

(La classe Vector2D est identique à celle que j'avais déjà utilisée dans des tutoriels précédents, comme celui-ci.)

 fonction publique HardCoded () // Création d'une zone de texte t = new TextField (); t.selectable = false; largeur t = 300; t.x = stage.stageWidth / 2; t.y = stage.stageHeight - 30; addChild (t); // Début de la phase de détection de geste.addEventListener (MouseEvent.MOUSE_DOWN, start);  // Enregistrer la position de la souris lorsque la souris est descendue, démarrage de la fonction privée (e: MouseEvent): void // Enregistrer la suppression de la souris plus tôt = new Vector2D (e.localX, e.localY); // Commence à dessiner la ligne graphics.lineStyle (3); graphics.moveTo (antérieure.x, antérieure.y); // ajoute des écouteurs de déplacement de souris et de libération de souris stage.addEventListener (MouseEvent.MOUSE_MOVE, move); stage.addEventListener (MouseEvent.MOUSE_UP, up);  // Dessine un geste lorsque la souris se déplace avec une fonction privée move (e: MouseEvent): void graphics.lineTo (e.localX, e.localY);  // Evalue le geste lors de la libération de la souris avec une fonction privée up (e: MouseEvent): void // Indique l'emplacement de la libération de la souris dernièrement = new Vector2D (e.localX, e.localY); // Vecteur de calcul du geste de la souris var résultat: Vector2D = last.minus (previous); // Calcul de l'angle de droite absolue au vecteur de geste. var déviation: Number = RIGHT.angleBetween (result); écart = Math2.degreeOf (écart); // Interprétation de geste avec soulagement si (Math.abs (écart) < 30) t.text = "RIGHT gesture detected"; else t.text = ""; //Clear screen of previous drawing. graphics.clear(); //remove mouse move and mouse up listeners stage.removeEventListener(MouseEvent.MOUSE_MOVE, move); stage.removeEventListener(MouseEvent.MOUSE_UP, up); 

Étape 7: Résumé

À des fins de clarification, voici un résumé de la mise en œuvre codée en dur:

  1. Lorsque la souris est enfoncée, lancez la détection des gestes.
  2. Si vous déplacez la souris, mettez à jour le dernier emplacement du pointeur de la souris.
  3. Souris levée, évalue tout le geste depuis (1).

Étape 8: atténuation des angles de gestes

Faire un geste précis en utilisant une souris est difficile. Il est difficile de tracer des lignes droites (est, sud, ouest, nord), mais il est encore plus difficile de tracer des lignes diagonales (sud-est, sud-ouest, nord-ouest, nord-est) car nous devons estimer ce supplément de 45 °. J'ai donc donné aux diagonales plus d'atténuations que de droites. Remarquez le plus grand angle grisé du vecteur diagonal par rapport à celui du vecteur droit.


Étape 9: Sensibilité du geste

 Je voudrais signaler un autre problème - les gestes sensibles. Les gestes sensibles identifient les directions des gestes lorsque le pointeur de la souris effectue les moindres changements de position, même vers les pixels adjacents. Le diagramme ci-dessous illustre des scénarios de gestes sensibles.

Si l'utilisateur change d'idée après avoir appuyé sur la souris et que cette dernière est relâchée immédiatement, un geste sera toujours détecté si son pointeur fait un léger mouvement vers les pixels adjacents. Nous devrions permettre aux utilisateurs d'annuler la détection de geste. Dans ce tutoriel, j'ai imposé une magnitude minimale que le vecteur du geste actuel doit dépasser pour être valide. J'ai inclus un diagramme comme ci-dessous.


Étape 10: Variables de classe

Afin de détecter les gestes singuliers de souris, j'ai implémenté MGesture. Téléchargez et examinez ce fichier ActionScript. Je vais d'abord passer en revue ses variables de classe, puis les méthodes de classe.

Variable Type de données Objectif
MainBox DisplayObjectContainer Conteneur à partir duquel les gestes sont détectés
directions Vecteur. Vecteurs de directions standards
_deviationFromMains Nombre Allègement de l'angle autorisé du geste Vector dans 4 directions principales (0 ~ 3 in directions)
_deviationFromDiagonals Nombre Allègement de l'angle permis du geste vecteur de 4 directions diagonales (4 ~ 7 dans directions)
_minDist Nombre Magnitude minimale sur le geste en cours Vecteur à valider
_plus tôt Vector2D Lieu du premier clic
_dernier Vector2D Position du pointeur continu après le premier clic

Vous trouverez ci-dessous l'implémentation de code des variables de classe. J'ai autorisé un écart de 10 ° par rapport aux directions principales. Par exemple, -10 ° -10 ° est considéré comme étant plein est, -80 ° -100 ° est considéré comme étant sud, etc. J'ai également autorisé un écart de 30 ° par rapport à la diagonale. Ainsi, un vecteur dont l'orientation est comprise entre 15 ° et 75 ° sera considéré comme venant du sud-est, etc. En outre, la magnitude minimale à dépasser est 10px.

 private var mainBox: DisplayObjectContainer; directions var privées: vecteur. = nouveau [Nouveau Vector2D (1, 0), // Est nouveau Vector2D (0, 1), // Sud nouveau Vector2D (-1, 0), // Ouest nouveau Vector2D (0, -1), // Nord nouveau Vector2D ( 1, 1), // Nouveau Vector2D Sud - Est (-1, 1), // Nouveau Vector2D Sud - Ouest (-1, -1), // Nouveau Vector2D Nord - Ouest (1, -1) // Nord - est ]; diagonales var privées: Boolean = false; private var _deviationFromMains: Number = Math2.radianOf (10); private var _deviationFromDiagonals: Number = Math2.radianOf (30); private var _minDist: Number = 10; private var _earlier: Vector2D; private var _latter: Vector2D;

Étape 11: Numérotation

Vous l'avez peut-être déjà deviné par référence à la mise en oeuvre du code de directions. Pour plus de précision, voici les représentations entières des directions principales.


Étape 12: Méthodes de classe et propriété

Voici des méthodes de classe pour MGesture.

Les méthodes Contribution Sortie La description
MGesture Conteneur dans lequel les gestes sont détectés vide Initiation de classe, conteneur de réglage à partir duquel les gestes sont détectés
début vide vide Variables pour la détection de geste (_plus tôt, _dernier) initie
mettre à jour vide Vecteur du geste actuel (sans tenir compte de _minDist), Vector2D Mises à jour _dernier et retourne le vecteur de geste actuel (_plus tôt à _dernier)
validMagnitude vide Vecteur du geste actuel (remplit la magnitude minimale de _minDist), Vector2D Vérifie si la magnitude du geste actuel est supérieure à _minDist
evalDirections vide Entier indiquant la direction, int Evalue le geste actuel en comparant son vecteur à ceux de directions

Étape 13: Méthodes

Les méthodes essentielles présentées à l'étape 12 sont toutes documentées ici. Ne lisez les commentaires.

 / ** * Variables initiales * conteneur @param où la souris est détectée à partir de * / fonction publique MGesture (conteneur: DisplayObjectContainer) // conteneur de définition à partir duquel la souris se déplace mainBox = conteneur;  / ** * Méthode pour enregistrer l'emplacement initial de la souris * / public function start (): void var startMX: Number = mainBox.mouseX; var startMY: Number = mainBox.mouseY; _earlier = new Vector2D (startMX, startMY); // emplacement du pointeur, initialement _latter = new Vector2D (startMX, startMY); // emplacement du pointeur, à mettre à jour ultérieurement / ** * Méthode de mise à jour de l'emplacement de la souris * @return un Vector2D de l'emplacement actuel de la souris par rapport à celui-ci lorsque start () est appelée; * / public function update (): Vector2D _latter = new Vector2D (mainBox.mouseX, mainBox.mouseY); var vecUpdate: Vector2D = _latter.minus (_earlier); return vecUpdate;  / ** * Méthode pour valider un geste. * @param newLoc Vector2D vers le nouvel emplacement de la souris * @return null si le geste est invalide, Vector2D si valide * / private function validMagnitude (): Vector2D var gestureVector: Vector2D = update (); var newMag: Number = gestureVector.getMagnitude (); // si la condition de magnitude n'est pas remplie, réinitialisez gestureVector sur null si (newMag < _minDist) gestureVector = null; return gestureVector;  /** * Method to evaluate gesture direction * @return Integer indicative of direction. Invalid gesture, -1. */ public function evalDirections():int  //Pessimistic search (initialise with unsuccessful search) var detectedDirection:int = -1; //validate magnitude condition var newDirection:Vector2D = validMagnitude(); //if gesture exceed minimum magnitude if (newDirection != null)  //evaluation against all directions for (var i:int = 0; i < directions.length; i++)  var angle:Number = directions[i].angleBetween(newDirection); angle = Math.abs(angle); //check against main directions if ( i < 4 && angle < _deviationFromMains)  detectedDirection = i; break;  //check against diagonal directions else if (i > 3 && angle < _deviationFromDiagonals)  detectedDirection = i; break;   //update mouse location for next evaluation _earlier = _latter;  //return detected direction return detectedDirection 

Étape 14: Galerie de photos

Maintenant que le MGesture classe est définie, nous allons procéder à une application de démonstration (galerie de photos). J'ai inclus un fichier source ici. Téléchargez et suivez. Tout d’abord, placez toutes les images dans le dossier "lib" de votre projet existant. Les images que j'ai utilisées ici sont une gracieuseté de ma femme et de ma fille.


Étape 15: Intégrer des images

Créez une nouvelle classe Actionscript et nommez-la. PhotoView. Nous allons utiliser ces images pour construire notre galerie.

  1. Générer du code d'intégration d'images. Ils seront reconnus comme génériques Classe objet.
  2. Jeter Classe dans Bitmap objets afin que nous puissions le manipuler davantage.
  3. Mettez tous ces Bitmap objets dans un Vecteur tableau pour une sélection facile plus tard.
 [Intégrer (source = '… /lib/Week3.jpg')] var privé private3: Classe [Intégrer (source = '… /lib/Family.jpg')] var privé: Famille: Classer [Intégrer (source = '… / lib / FatherDaughter.jpg ')] private var Fille: Classe [Intégrer (source ='… /lib/Jovial.jpg ')] privée var Jovial: Classe [Intégrer (source ='… /lib/NewBorn.jpg ')] var privé NewBorn: Class; [Intégrer (source = '… /lib/Posing.jpg')] var privé posant: Classe [Intégrer (source = '… /lib/Smile.jpg')] var privé: Smile: Classe [Intégrer (source = '… / lib / Surrender.jpg ')] private var Surrender: Liste des variables privées var: Vector. = nouveau  [nouvelle Week3 en tant que bitmap, nouvelle famille en tant que bitmap, nouvelle fille en tant que bitmap, nouveau Jovial en tant que bitmap, nouvelle NewBorn en tant que bitmap, nouvelle Posing en tant que bitmap, nouvelle image en tant que bitmap, nouvelle Week3 en tant que bitmap, nouvelle reddition en tant que bitmap]

Étape 16: Gestion de la liste d'affichage

Il est important de clarifier ici la gestion de PhotoViewla liste d'affichage de. J'ai inclus une présentation Flash ici. Pour l'utiliser, faites un geste à droite ou à gauche. Pour plus de détails, reportez-vous à l'étape 2.


Étape 17: Positionnement de l'image

dans le PhotoViewAvec le constructeur de, nous initions tous les objets d'affichage nécessaires et les positionnons. De plus, nous initions MGesture et attachez des écouteurs d’événements pour lancer la détection des gestes. J'ai mis en évidence les auditeurs de l'événement. Leurs détails sont expliqués au cours des deux prochaines étapes.

 fonction publique PhotoView () panel = new Sprite (); // Initate panel panel.x = stage.stageWidth / 2; // Panneau de centrage horizontalement panel.y = stage.stageHeight / 2; // Centrage vertical du panneau addChild (panel); var currentBmp: int = 0; // Image actuelle sélectionnée pour le positionnement de var bmpGaps: Number = 60; // Espacement entre les images var bmpOnX: int = 3; // Nombre d'images sur l'axe horizontal var bmpOnY: int = 3; // Nombre d'images sur l'axe vertical var bmp: Bitmap; // Objet bitmap contenant l'image var container: Sprite; // conteneur Sprite pour contenir bmp // défilement de Y pour (var j: int = -1 * Math.floor (bmpOnY / 2); j < Math.ceil(bmpOnY/2); j++)  //scrolling through X for (var i:int = -1*Math.floor(bmpOnX/2); i < Math.ceil(bmpOnX/2); i++)  bmp = list[currentBmp]; bmp.x = -1 * bmp.width / 2; //Bitmap centered horizontally in container bmp.y = -1 * bmp.height / 2; //Bitmap centered vertically in container container = new Sprite(); container.x = (bmp.width + bmpGaps )* i; //Positioning container on x accordingly container.y = (bmp.height + bmpGaps )* j; //Positioning container on y accordingly container.addChild(bmp); //Add bitmap into container container.addEventListener(MouseEvent.MOUSE_DOWN, select); panel.addChild(container); //Add container into panel currentBmp++ //Scroll to next bitmap   gesture = new MGesture(stage); //Initiate MGesture for gesture detection stage.addEventListener(MouseEvent.MOUSE_DOWN, start); 

Étape 18: Sélection de l'image à redimensionner

La ligne 99 en surbrillance n’est pas liée à la détection de geste, mais simplement à la sélection d’une image à redimensionner et à la placer au-dessus de toutes les autres images..

 fonction privée select (e: MouseEvent): void // Définition de l’image actuelle à l’échelle & // Placement de celle-ci au-dessus de toutes les autres images ImgSelected = e.currentTarget as Sprite; panel.swapChildrenAt (panel.numChildren - 1, panel.getChildIndex (ImgSelected)); 

Étape 19: Démarrer, terminer et évaluer le geste de la souris

La première fonction ci-dessous est exécutée lorsque la souris est enfoncée. La seconde est exécutée en levant la souris. J'ai mis en évidence début() et evalGesture () ainsi que des auditeurs évant.

 Fonction privée start (e: MouseEvent): void // Démarrez la détection de geste & // Écoutez la souris jusqu'à l'événement gesture.start (); stage.addEventListener (MouseEvent.MOUSE_UP, fin);  private function end (e: MouseEvent): void // Préparer la magnitude du geste actuel à des fins d'animation // implémenter une limite maximale pour la magnitude du geste gestureMag = gesture.update (). getMagnitude () / 2; gestureMag = Math.min (gestureMag, maxMag); // Evalue la direction actuelle du geste = gesture.evalGesture (); // Une fois qu'un geste valide est détecté, lancez l'animation // Aucun autre geste n'est détecté jusqu'à la fin de l'animation si (direction> -1) stage.addEventListener (Event.ENTER_FRAME, move); stage.removeEventListener (MouseEvent.MOUSE_DOWN, début); 

Étape 20: Animation du panneau et des images

Une fois que les directions ont été détectées, l'animation commence. En fonction du geste effectué, tout le panneau peut se déplacer dans quatre directions ou une seule image peut être agrandie ou réduite..

 fonction privée move (e: Event): void var currentMag: Number // Mouvement de la traduction du panneau if (direction < 4)  //Function of easing motion currentMag = gestureMag * Math.cos(currentAngle += 0.1); if (direction == 0) panel.x += currentMag; else if (direction == 1) panel.y += currentMag; else if (direction == 2) panel.x -= currentMag; else if (direction == 3) panel.y -= currentMag;  //Motion of image scaling else  //Setting a maximum cap on motion gestureMag = Math.min(0.30, gestureMag); //Function of easing motion currentMag = gestureMag * Math.cos(currentAngle += 0.1); //Conditions to scale up: //Gesture is to South-East & //Image is not scaled up already if (direction == 4 && ImgSelected.scaleX < 1.30) ImgSelected.scaleX = ImgSelected.scaleY = -1 * currentMag + 1.30  //Conditions to scale down: //Gesture is to North-West & //Image is scaled up else if (direction == 6 && ImgSelected.scaleX > 1) ImgSelected.scaleX = ImgSelected.scaleY = currentMag + 1;  // Si l'angle de la fonction d'accélération dépasse 90 degrés / 0,5 Pi en radian, // arrête l'animation et active la détection des gestes si (currentAngle> Math.PI / 2) stage.removeEventListener (Event.ENTER_FRAME, move); stage.addEventListener (MouseEvent.MOUSE_DOWN, début); direction = -1; // Reset direction currentAngle = 0; // Réinitialiser l'angle

Étape 21: publier PhotoView

Maintenant tout est réglé. Vous pouvez enfin publier votre travail en appuyant sur Ctrl + Entrée sur FlashDevelop. Encore. voici un morceau du produit final.


Conclusion

Ce n'est pas la fin. Dans la partie suivante, nous examinerons la détection d’une séquence de gestes, ce qui sera encore plus intéressant que cette partie (qui vient de montrer les bases). Faites des commentaires et laissez-moi savoir si MGesture vous avait été utile, ainsi que d’éventuels bugs, le cas échéant. Enfin, terima kasih pour la lecture du temps. J'espère divertir mes collègues lecteurs dans la deuxième partie.