|
|
| Tutoriaux : Charger et exploiter les données d'un fichier XML |
|
1. Introduction |
| Lorsque les scientifiques font des expériences ils utilisent couramment des appareils de mesure qui leur donnent généreusement des milliers de nombres pouvant être stockés sous la forme de fichier texte ou de document XML. Il peut être très utile de mettre ces milliers de nombres sous la forme d'un graphique ou de faire des statistiques sur l'ensemble de ces mesures. Dans ce tutoriel un fichier XML regroupe l'ensemble des ordonnées de 100 points enregistrées durant 100 unités de temps (s ou ms... peut importe). L'idée de ce tutoriel est de vous apprendre à exploiter un document XML pour créer une animation qui permettra de visualiser le déplacement de ces 100 points. L'animation ci-dessous charge un fichier XML contenant 10 000 ordonnées (100x100=10 000) qui permettent de gérer les déplacement des 100 points que vous voyez à l'écran. |
|
|
| 2. Dans la bibliothèque, sur la scène principale, document XML |
| - Ouvrez le logiciel Flash et créez un nouveau document. Définissez les dimensions de l'animation : 550 pixels de largeur et 400 pixels de hauteur. - Dans le panneau "propriétés du document", définissez la cadence de l'animation à 25 images par seconde. - A côté de votre animation flash doit se trouver un fichier XML qui contient l'ensemble des ordonnées des 100 points. Vous pouvez télécharger ce document qui s'appelle "ordonnees.xml" afin de comprendre sa structure et suivre ce tutoriel. - La bibliothèque et la scène principale sont vides : nous allons pouvoir passer au code ! |
| 3. Le code |
| Dans la première image clé de la scène principale, placez le code suivant : |
xmax = 525; xmin = 25; ymin = 375; ymax = 25; vxmin = 0; dvx = 0.1; ngradx = 10; vxmax = vxmin+ngradx*dvx; vymin = 0; dvy = 0.2; ngrady = 10; vymax = vymin+ngrady*dvy; format = new TextFormat(); format.size = 11; format.font = "Comic Sans MS"; creerUnChampDeTexte = function (clip, depth, legende, x, y, l, h) { var texte = clip.createTextField("texte"+depth, depth, x, y, l, h); texte.selectable = false; texte.border = false; texte.text = legende; texte.setTextFormat(format); }; largeur = 30; hauteur = 20; this.createEmptyMovieClip("grille", 0); grille.beginFill(0xCCCCCC, 20); grille.moveTo(xmin, ymax); grille.lineTo(xmax, ymax); grille.lineTo(xmax, ymin); grille.lineTo(xmin, ymin); grille.lineTo(xmin, ymax); grille.endFill(); format.align = "center"; grille.lineStyle(0, 0, 25); for (var i = 0; i<=ngradx; i++) { var x = xmin+i*(xmax-xmin)/ngradx; grille.moveTo(x, ymin); grille.lineTo(x, ymax); creerUnChampDeTexte(grille, i, i*dvx, x-0.5*largeur, ymin, largeur, hauteur); } format.align = "right"; for (var i = 0; i<=ngrady; i++) { var y = ymin+i*(ymax-ymin)/ngrady; grille.moveTo(xmin, y); grille.lineTo(xmax, y); if (i != 0) { creerUnChampDeTexte(grille, i+ngradx+1, i*dvy, xmin-largeur, y-0.5*hauteur, largeur, hauteur); } } grille.onPress = function() { courbe._visible = !courbe._visible; points._visible = !points._visible; }; this.createEmptyMovieClip("points", 1); this.createEmptyMovieClip("courbe", 2); points._y = courbe._y=ymin; points._visible = true; courbe._visible = false; this.createEmptyMovieClip("chargement", 3); chargement._x = 275; chargement._y = 200; format.align = "center"; creerUnChampDeTexte(chargement, 0, "chargement", -275, 0, 550, hauteur); symboleRight = ""; symboleLeft = ""; chargement.onEnterFrame = function() { symboleRight += ">"; symboleLeft += "<"; if (symboleLeft.length>15) { symboleLeft = symboleRight=""; } this.texte0.text = symboleLeft+"chargement du fichier xml"+symboleRight; this.texte0.setTextFormat(format); }; var fichierXML = new XML(); fichierXML.ignoreWhite = true; graph = new Array(); fichierXML.onLoad = function(succes) { if (succes) { var donnees = this.firstChild.childNodes; for (var i = 0; i<100; i++) { graph[i] = new Array(); for (var j = 0; j<100; j++) { var s = donnees[i*100+j].firstChild; s = s.toString(); s = (ymax-ymin)*(s-vymin)/(vymax-vymin); graph[i].push(s); } } for (var i = 0; i<100; i++) { var point = points.createEmptyMovieClip("p"+i, i); point.lineStyle(2, 0, 100); point.moveTo(0, 0); point.lineTo(0.2, 0); point._x = xmin+i*(xmax-xmin)/99; point._y = graph[0][i]; } index = 0; onEnterFrame = function () { index++; if (index>100) {index = 0;} courbe.clear(); courbe.lineStyle(2, 0xFF0000, 100); points.p0._y = graph[index][0]; courbe.moveTo(points.p0._x, points.p0._y); for (var i = 1; i<100; i++) { var p = points["p"+i]; p._y = graph[index][i]; courbe.lineTo(p._x, p._y); } }; removeMovieClip("chargement"); } else { delete chargement.onEnterFrame; chargement.texte0.text = "Désolé, le document xml n'a pas été chargé !"; chargement.texte0.setTextFormat(format); } }; fichierXML.load("ordonnees.xml"); |
| 4. Le code avec ses commentaires |
| Bon je vous avoue que je n'ai pas le courage de vous commenter les 121 lignes de ce script ligne par ligne... Vous allez devoir vous contenter de quelques remarques par paragraphes : pour les plaintes, n'hésitez pas à poussez une gueulante sur le livre d'or ! Signalez moi les passages obscurs qui selon vous exigeraient un plus de détails ! |
| xmax et xmin sont respectivement les abscisses maximales et minimales du graphique. |
| xmax = 525; xmin = 25; |
| Grâce à votre esprit cartésien vous avez déjà compris que ymin et ymax sont respectivement les ordonnées minimales et maximales du graphique. J'entends déjà la critique ymax et plus petit que ymin... zoneflash c'est du n'importe quoi ! Oui mais dans Flash, l'axe des ordonnées est orienté vers le bas. |
| ymin = 375; ymax = 25; |
| vxmin est la valeur minimale qui sera affichée sur l'axe des abscisses, tandis que dvx représente la variation de la grandeur représentée sur l'axe des abscisses entre deux graduations consécutives. ngradx est le nombre de graduations affichées sur l'axe des abscisses. Après un savant calcul, on définit la valeur de vxmax qui sera alors la valeur maximale affichée sur l'axe des abscisses. Ainsi avec les paramètres ci-dessous, l'axe des abscisses représentera l'ensemble des nombres compris entre 0 et 1 avec une graduation tous les dixièmes d'unité. |
| vxmin = 0; dvx = 0.1; ngradx = 10; vxmax = vxmin+ngradx*dvx; |
| Je pense que vous n'aurez aucun mal à comprendre les lignes suivantes : on gradue l'axe des ordonnées afin qu'il représente l'ensemble des nombres compris entre 0 et 2 avec une graduation tous les 2 dixièmes d'unité. |
| vymin = 0; dvy = 0.2; ngrady = 10; vymax = vymin+ngrady*dvy; |
| On définit la taille et la police de lettres que nous utiliserons pour remplir les champs de texte dynamiques qui permettront de graduer les deux axes. |
| format = new TextFormat(); format.size = 11; format.font = "Comic Sans MS"; |
| Nous définissons une fonction permettant de créer un champ de texte qui sera placé à l'intérieur d'un clip dont nous passons le nom en premier argument. Ce champ de texte est rempli à l'aide de l'argument "legende" puis il est formaté à l'aide des options définies précédemment. |
| creerUnChampDeTexte = function (clip, depth, legende, x, y, l, h) { var texte = clip.createTextField("texte"+depth, depth, x, y, l, h); texte.selectable = false; texte.border = false; texte.text = legende; texte.setTextFormat(format); }; |
| Ces deux paramètres permettent de définir la largeur et la hauteur des champs de texte que nous placerons parallèlement aux axes. |
| largeur = 30; hauteur = 20; |
| Nous créons un clip vide nommé "grille" dans lequel nous traçons un rectangle gris aux dimensions de notre futur graphique. |
| this.createEmptyMovieClip("grille", 0); grille.beginFill(0xCCCCCC, 20); grille.moveTo(xmin, ymax); grille.lineTo(xmax, ymax); grille.lineTo(xmax, ymin); grille.lineTo(xmin, ymin); grille.lineTo(xmin, ymax); grille.endFill(); |
| Nous traçons dans le clip "grille" des lignes verticales et plaçons simultanément des champs de texte pour indiquer les abscisses de ces lignes. Le plus difficile dans cette opération est de définir avec précision les coordonnées des champs de texte de façon à obtenir un affichage "propre" des abscisses. Pour parvenir à ce résultat un bon truc consiste à doter les champs de texte de bordure afin de mieux voir leur placement dans l'animation : pour cela il suffit de revenir à la fonction "creerUnChampDeTexte" et de mettre "texte.border=true"... |
| format.align = "center"; grille.lineStyle(0, 0, 25); for (var i = 0; i<=ngradx; i++) { var x = xmin+i*(xmax-xmin)/ngradx; grille.moveTo(x, ymin); grille.lineTo(x, ymax); creerUnChampDeTexte(grille, i, i*dvx, x-0.5*largeur, ymin, largeur, hauteur); } |
| Nous traçons dans le clip "grille" des lignes horizontales et plaçons simultanément des champs de texte pour indiquer les ordonnées de ces lignes. |
| format.align = "right"; for (var i = 0; i<=ngrady; i++) { var y = ymin+i*(ymax-ymin)/ngrady; grille.moveTo(xmin, y); grille.lineTo(xmax, y); if (i != 0) { creerUnChampDeTexte(grille, i+ngradx+1, i*dvy, xmin-largeur, y-0.5*hauteur, largeur, hauteur); } } |
| Les lignes suivantes permettent de transformer le clip "grille" en un bouton. Un clic sur la grille permettra de modifier la visibilité des clips "courbe" et "points" que nous allons créer dans le paragraphe suivant. |
| grille.onPress = function() { courbe._visible = !courbe._visible; points._visible = !points._visible; }; |
| Nous créons deux clips vides : "points" et "courbe". Le premier est visible tandis que le second ne l'est pas (au chargement de l'animation). C'est en cliquant sur le clip "grille" que le clip "courbe" deviendra visible... |
| this.createEmptyMovieClip("points", 1); this.createEmptyMovieClip("courbe", 2); points._y = courbe._y=ymin; points._visible = true; courbe._visible = false; |
| Nous créons un clip vide (encore !) nommé "chargement" que nous plaçons au centre de la scène. Ce clip contiendra un champ de texte contenant le message "chargement du fichier xml"... Uun effet de texte basique permettra de faire patienter les visiteurs lors du chargement du volumineux fichier xml (161 Ko). |
| this.createEmptyMovieClip("chargement", 3); chargement._x = 275; chargement._y = 200; format.align = "center"; creerUnChampDeTexte(chargement, 0, "chargement", -275, 0, 550, hauteur); symboleRight = ""; symboleLeft = ""; chargement.onEnterFrame = function() { symboleRight += ">"; symboleLeft += "<"; if (symboleLeft.length>15) { symboleLeft = symboleRight=""; } this.texte0.text = symboleLeft+"chargement du fichier xml"+symboleRight; this.texte0.setTextFormat(format); }; |
| Nous créons un objet XML afin de pouvoir appeler les méthodes de la classe XML et lire les données numériques qui se trouvent dans notre document "ordonnees.xml". Lorsque la propriété "ignoreWhite" est true, les noeuds de texte qui contiennent un espace vierge avant ou après leur nom ne sont pas affectés. |
| var fichierXML = new XML(); fichierXML.ignoreWhite = true; |
| Nous créons un tableau qui contiendra toutes les ordonnées qui se trouvent dans le fichier XML. graph[0] contiendra les 100 premières ordonnées, graph[1] contiendra les 100 ordonnées suivantes... et enfin graph[99] contiendra les 100 dernières ordonnées du fichier "ordonnnees.xml". |
| graph = new Array(); |
| Nous créons une fonction qui sera appelée par le Flash Player lorsque le document XML sera reçu en provenance du serveur. Si le document XML est bien reçu, le paramètre "succes" est true. Si le document n'a pas été reçu, le paramètre "succes" renvoie false. |
| fichierXML.onLoad = function(succes) { |
| Si le fichier XML a bien été reçu... |
| if (succes) { |
| On définit une variable "donnees" qui est un tableau contenant toutes les ordonnées du fichier XML. |
| var donnees = this.firstChild.childNodes; |
| On remplit le tableau "graph" qui nous permettra de manipuler facilement les ordonnées des 100 points. On transforme les valeurs numériques du document XML de manière à obtenir les valeurs des ordonnées "correspondantes" à l'écran (en pixels). Ainsi, les calculs seront faits une fois et une seule fois ! |
| for (var i = 0; i<100; i++) { graph[i] = new Array(); for (var j = 0; j<100; j++) { var s = donnees[i*100+j].firstChild; s = s.toString(); s = (ymax-ymin)*(s-vymin)/(vymax-vymin); graph[i].push(s); } } |
| On crée 100 clips vides (c'est de la folie !), dans lesquels on trace un tout "petit" segment horizontal qui nous donnera l'illusion d'un point (il suffit de prendre un trait suffisamment épais). L'abscisse de chaque point est définie et ne variera pas au cours de l'animation. Les ordonnées de ces points seront définies par les valeurs numériques enregistrées dans le tableau "graph". |
| for (var i = 0; i<100; i++) { var point = points.createEmptyMovieClip("p"+i, i); point.lineStyle(2, 0, 100); point.moveTo(0, 0); point.lineTo(0.2, 0); point._x = xmin+i*(xmax-xmin)/99; point._y = graph[0][i]; } |
| Cette variable permet de définir le "numéro" du graphique à tracer : le premier graphique utilise les 100 premières ordonnées, le second graphique utilise les 100 ordonnées suivantes et ainsi de suite... |
| index = 0; |
| Nous définissons une fonction qui sera appelée à chaque image de la timeline de la scène principale. Cette fonction majore la variable "index" de une unité et s'assure que celle-ci reste comprise entre 0 et 99. Ainsi les différents graphiques se succèderont... A chaque image, on modifie les ordonnées des 100 points et on trace dans le clip "courbe" une ligne rouge reliant les 100 points entre eux. |
| onEnterFrame = function () { index++; if (index>100) {index = 0;} courbe.clear(); courbe.lineStyle(2, 0xFF0000, 100); points.p0._y = graph[index][0]; courbe.moveTo(points.p0._x, points.p0._y); for (var i = 1; i<100; i++) { var p = points["p"+i]; p._y = graph[index][i]; courbe.lineTo(p._x, p._y); } }; |
| On enlève de la scène principale le clip "chargement" qui ne sert plus à rien puisque le fichier XML a été reçu. |
| removeMovieClip("chargement"); |
| ... sinon, si le fichier XML n'a pas été reçu : on annule l'effet de texte dans le clip "chargement" et on affiche un message d'erreur. |
| } else { delete chargement.onEnterFrame; chargement.texte0.text = "Désolé, le document xml n'a pas été chargé !"; chargement.texte0.setTextFormat(format); } |
| Fin de la fonction onLoad. |
| }; |
| On charge le fichier XML qui s'appelle "ordonnees.xml". |
| fichierXML.load("ordonnees.xml"); |
| 5. Remarques |
| Dans ce tutoriel la structure du fichier XML est extrêmement simple et la lecture des données est facile... Ce tutoriel n'est donc pas un tour d'horizon des interactions entre Flash et le XML. |
|
|