Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox



Afficher, centrer, déplacer et zoomer une image à l'intérieur d'une fenêtre

Compatible ActionScript 2. Cliquer pour en savoir plus sur les compatibilités.Par lilive (Olivier Tarasse)

Article écrit le 04/06/2008 16:34.
Par lilive ( olivier tarasse ).

Bon nombre d'applications graphiques, comme des logiciels de dessins, des visualiseurs de photos et diaporamas, ou encore l'IDE flash de Macromedia, utilisent une interface graphique similaire.
On y trouve une fenêtre de visualisation, dans laquelle s'affiche le contenu graphique. L'utilisateur a la possibilité de zoomer sur différentes parties du contenu, de se déplacer à l'intérieur du contenu s'il est plus grand que la fenêtre, ou encore d'afficher le contenu dans son intégralité.
Je vais présenter ici des éléments utiles pour réaliser ce genre d'interface.
Le code sera en actionscript 2, et en deux articles nous arriverons à ce résultat :

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.


I - Afficher une image à l'intérieur d'une fenêtre rectangulaire

Partons de la situation suivante (fig.1) :

pictinwin-figu-1.jpg
fig.1 : la situation

- Nous avons un MovieClip nommé imageMC contenant une image de n'importe quelle taille.
- Nous avons défini une zone rectangulaire d'affichage. J'utiliserais un objet Rectangle qui permet de stocker dans un seul objet toutes les coordonnées d'un rectangle :

var zoneAffichage:Rectangle = new Rectangle(50,50,300,200);

Nous ne voulons voir d'imageMC que la partie à l'intérieur de cette zone d'affichage :

pictinwin-figu-2.jpg
fig.1 bis : le résultat souhaité

Une telle situation se résout classiquement en utilisant la possibilité de “masquer” un MovieClip. Cela se passe ainsi :
- on dessine un rectangle plein aux dimensions de la zone d'affichage, dans un MovieClip maskMC,
- on définit maskMC comme étant le “masque” de imageMC. A partir de ce moment, imageMC apparaît uniquement “à travers” maskMC. C'est-à-dire que maskMC n'est plus dessiné, et que l'on voit imageMC uniquement là où maskMC aurait été dessiné. Les autres parties de imageMC sont devenues invisibles.

import flash.geom.Rectangle;
// Définition de la zone d'affichage :
var zoneAffichage:Rectangle = new Rectangle(50,50,300,200);
// Création du calque de masque :
var maskMC:MovieClip = this.createEmptyMovieClip("mask", this.getNextHighestDepth());
// Dessin d'une rectangle aux dimensions de zoneAffichage :
maskMC.beginFill(0xffffff, 100)
maskMC.moveTo(zoneAffichage.left, zoneAffichage.top);
maskMC.lineTo(zoneAffichage.right, zoneAffichage.top);
maskMC.lineTo(zoneAffichage.right, zoneAffichage.bottom);
maskMC.lineTo(zoneAffichage.left, zoneAffichage.bottom);
maskMC.endFill();
// Masquage de imageMC par maskMC :
imageMC.setMask(maskMC);

Ce code suppose qu'il y a sur la scène un MovieClip nommé imageMC qui contient une image. Ceci fonctionnerais également avec une animation à la place d'une image statique. Voici le swf résultat :

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.
Le code correspondant est celui de pictInWin1.as


II - Déplacer à la souris une image à l'intérieur d'une fenêtre rectangulaire

Nous avons donc un aperçu de imageMC limité par la zone d'affichage. Nous aimerions maintenant donner à l'utilisateur la possibilité de déplacer l'image à l'intérieur de la fenêtre, pour pouvoir faire apparaître les parties masquées. Le plus commode pour lui sera de pouvoir faire des cliquer-glisser avec sa souris.

En action script c'est très simple, il suffit d'utiliser la méthode startDrag qui fait qu'un MovieClip suit les mouvements de la souris. Rajoutons le code suivant à la suite de ce que l'on a déjà tapé :

// Quand l'utilisateur clique sur imageMC, le clip suit les mouvements de la souris :
imageMC.onPress = function () { this.startDrag(false); }
// Quand l'utilisateur relache le bouton de la souris, imageMC arrête de suivre ses mouvements :
imageMC.onRelease = imageMC.onReleaseOutside = function () { this.stopDrag(); }

Et il n'en faut pas plus pour avoir le résultat. Utilisez la souris pour déplacer l'image :

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.
Le code correspondant est celui de pictInWin2.as


III - Adapter la taille du contenu à celle de la fenêtre

La base est maintenant posée. On a une fenêtre, et un contenu qui bouge dedans. Il reste encore à traiter tout ce qui à trait aux opérations de “zoom”.

La plupart du temps, dans les applications graphiques, il existe la possibilité de zoomer sur l'image de façon à ce que sa taille s'ajuste à celle de la fenêtre, pour qu'elle soit vue entièrement d'un seul coup d'oeil. C'est l'objet de ce chapitre.

a) Modifier la taille d'un MovieClip sans perdre ses proportions

Pour arriver au résultat précédemment énoncé, on pourrait penser qu'il suffit de faire :

// Redimensionner l'image à la taille de la fenêtre :
imageMC._width = zoneAffichage.width;
imageMC._height = zoneAffichage.height;
// Placer l'image au même endroit que la fenêtre
imageMC._x = zoneAffichage.left;
imageMC._y = zoneAffichage.top;

Mais ce n'est pas aussi simple. Cette méthode marcherait uniquement dans le cas où les tailles de l'image et de la fenêtre seraient proportionnelles. Dans le cas contraire, l'image serait déformée.

Voici deux swf générés avec ce code. Dans le premier les dimensions de la zone d'affichage sont proportionnelles à l'image et le résultat est correct. Dans le second la zone d'affichage est cette fois un carré, qui n'a donc pas les mêmes proportions que l'image rectangulaire. Il s'ensuit une déformation de l'image.

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.
zoneAffichage fait 300×200 pour une image de 1500×1000. Tout va bien.

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.
zoneAffichage fait 200×200 pour une image de 1500×1000. Il y a déformation.

Nous allons devoir écrire un code qui redimensionne l'image à la taille de la fenêtre, sans la déformer. Pour cela, en plus des propriétés _width et _height d'un MovieClip, nous allons utiliser _xscale et _yscale qui sont les facteurs d'étirements en largeur et hauteur du MovieClip.

Exemple:
Pour un MovieClip imageMC qui aurait pour largeur d'origine 400 pixels, si on fait imageMC._width=800, alors imageMC._xscale prendra la valeur 200 (en pourcentage de la largeur d'origine). En effet 800 pixels correspond à 2 fois 400 pixels, soit 200%.
Réciproquement, si on fait imageMC._xscale=300, alors imageMC._width prendra la valeur 1200 ( 400 * 3).

Pour s'assurer qu'un MovieClip n'est pas déformé, il suffit de faire en sorte que l'étirement en largeur soit égal à celui en hauteur, c'est-à-dire que _xscale=_yscale.
Voici le code d'une fonction qui redimensionne un clip de façon à ce qu'il rentre entièrement dans un rectangle :

function redimensionnerProportionnellement(imageMC:MovieClip, zoneAffichage:Rectangle) {
        // Dimensionne imageMC à sa taille maximale pour qu'il rentre dans zoneAffichage.
 
        // on met la largeur maximale :
        imageMC._width = zoneAffichage.width;
        // on fait suivre le redimensionnement vertical pour éviter la déformation :
        imageMC._yscale = imageMC._xscale; 
        if (imageMC._height > zoneAffichage.height) {
                // Si le contenu dépasse en hauteur,
                // on rectifie et on adapte la largeur :
                imageMC._height = zoneAffichage.height;
                imageMC._xscale = imageMC._yscale;
        }
}

Cette fonction commence par étirer le MovieClip pour que sa largeur coïncide avec celle du rectangle, puis étire sa hauteur dans la même proportion. Les proportions de l'image sont donc respectées. La hauteur obtenue peut être inférieure, égale, ou supérieure à celle du rectangle d'affichage. Si cette hauteur est inférieure ou égale à celle du rectangle cela nous convient, on a trouvé la plus grande taille possible de l'image pour qu'elle rentre entièrement dans le rectangle. Dans le cas où cette hauteur est supérieure à celle du rectangle, cela ne nous convient pas car le MovieClip dépassera du rectangle. On choisit alors de donner au MovieClip la même hauteur que celle du rectangle et d'étirer sa largeur dans la même proportion. Dans ce cas le MovieClip sera entièrement contenu dans le rectangle, avec une largeur inférieure.

Nous obtenons au final une image qui à soit la même largeur que le rectangle, avec une hauteur inférieure ou égale, soit une image qui à la même hauteur que le rectangle, avec une largeur inférieure ou égale. C'est ce que nous voulions. Il ne nous reste plus qu'à positionner l'image dans le rectangle pour qu'elle soit centrée, ce qui est d'un meilleur effet.

b) Centrer un MovieClip dans un rectangle

Voici un code qui déplace un MovieClip pour que son centre corresponde à celui d'un rectangle. On dit que le MovieClip est “centré” :

function centrer(imageMC:MovieClip, zoneAffichage:Rectangle) {
        // Centre imageMC dans zoneAffichage.
 
        // On calcule les coordonnées du point central de zoneAffichage :
        var centreX:Number = zoneAffichage.width / 2 + zoneAffichage.left;
        var centreY:Number = zoneAffichage.height / 2 + zoneAffichage.top;
        // On place imageMC en fonction de ce point, en tenant compte de sa taille :
        imageMC._x = centreX - imageMC._width / 2;
        imageMC._y = centreY - imageMC._height / 2;
}

Pour mieux comprendre ces calculs, voir le shéma ci-dessous, qui illustre le procédé de centrage horizontal (en x). Le centrage vertical (en y) suit exactement le même principe.

pictinwin-figu-3.jpg
fig.3 : calcul de la position horizontale de l'image pour qu'elle soit centrée


Il ne nous reste plus qu'à utiliser successivement ces deux dernières fonctions pour que l'utilisateur ait à sa disposition un bouton qui redimensionne et centre le contenu de manière à ce qu'il soit entièrement visible :

viewAllBtn.onPress = function () {
        redimensionnerProportionnellement(imageMC, zoneAffichage);
        centrer(imageMC, zoneAffichage);
}

Voici le swf correspondant:

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.
Le code est celui de pictInWin5.as

J'ai ajouté un bouton “voir à 100%” qui remet _xscale et _yscale à 100%.


La suite

Voilà, je m'arrête là pour aujourd'hui. La suite des fonctions de zoom, avec la possibilité de zoomer à n'importe quelle échelle sur l'image, fait l'objet de cet article



Merci de vos commentaires sur ces explications.