Informations
Le sujet que vous avez demandé est indiqué ci-dessous. Toutefois, ce sujet ne figure pas dans la bibliothèque.

Mandelbrot Explorer

.NET Framework 3.0

S’appuyant sur les informations présentées dans Utilisation de threads de travail Web, nous découvrons ici comment améliorer Mandelbrot 8 pour produire la version finale - Mandelbrot Explorer.

Nous avons apporté les améliorations suivantes à Mandelbrot 8 pour produire Mandelbrot Explorer :

  • État du dessin : le message discret calculating... a été remplacé par une animation plus visible positionnée au centre de la zone de dessin.
  • Dessin de la zone d’agrandissement : vous pouvez maintenant dessiner une zone d’agrandissement en partant de n’importe quel coin et ses performances d’animation sont améliorées.
  • Alternative aux threads de travail Web : bien que la prise en charge des threads de travail Web offre de meilleures performances, le navigateur n’a pas besoin de prendre en charge les threads de travail Web pour que Mandelbrot Explorer fonctionne.

État du dessin

Pour vous aider à vous assurer que votre image Mandelbrot est réellement dessinée, le message calculating... placé en haut à gauche est remplacé par une animation positionnée au centre de la zone de dessin à l’aide de l’élément <progress>. Pour positionner l’élément progress au centre de la zone de dessin, utilisez le code HTML suivant :


<div id="canvasWrapper">
  <progress id="progressIndicator"></progress>
  <canvas width="600" height="400" oncontextmenu="return false;">
    Canvas not supported - upgrade your browser (after checking that your browser is in the correct mode).
  </canvas>
</div>


Le wrapper <div id="canvasWrapper"> est utilisé pour trouver aisément le centre de la zone de dessin et positionner l’élément progress par rapport à lui, à l’aide du code CSS suivant (un commentaire explique chaque propriété CSS) :


##canvasWrapper {
  position: relative; /* Allows any absolutely positioned child element to be positioned relative to this (parent) element. */
  width: 604px; /* Account for the two 2px wide borders of the 600px wide canvas element. */
  margin: 0 auto; /* Center the canvas wrapper on the page. */
}

progress {
  display: block; /* For browsers that do not recognize <progress> tags, this makes them work as expected (i.e., as a generic DIV element would). */
}

#progressIndicator {
  color: red; /* Make the progress bar highly visible. */
  display: none; /* Only display the <progress> tag when the Mandelbrot set is being calculated. */
  position: absolute; /* This is positioned relative to the #canvasWrapper DIV element. */
  width: 400px; /* The width of the progress bar. */
  height: 20px; /* The height of the progress bar. */
  left: 102px; /* The canvas is 600px wide, the progress bar is 400px wide, so to center the progress bar, the progress bar must start 100px from the left of the canvas plus a 2px border. */
  top: 192px; /* The canvas is 400px high, the progress bar is 20px tall, so to center the progress bar, the progress bar must start 190px from the top of the canvas plus a 2px border. */
}

À présent, pour afficher l’indicateur de progression, nous basculons par programme sa propriété CSS display de progressIndicator.style.display = "none" à progressIndicator.style.display = "block".

Dessin de la zone d’agrandissement

L’un des problèmes liés à la mise en œuvre existante de la zone d’agrandissement est que vous devez dessiner la zone d’agrandissement du coin supérieur gauche vers le coin inférieur droit. Nous expliquons ici comment supprimer cette limitation de sorte que l’utilisateur puisse dessiner une zone d’agrandissement à partir de n’importe quel coin :

Quatre exemples de zone d’agrandissement, chacun ayant un point de départ dans un coin différent

Comme vous pouvez le constater, une zone d’agrandissement peut être définie en partant de n’importe quel coin (x1, y1) et en finissant dans le coin opposé (x2, y2).

Le traitement de la zone d’agrandissement étant géré par le gestionnaire d’événements handlePointer, handlePointer est modifié comme indiqué par la police rouge dans le tableau avant/après ci-dessous :

Comparaison entre le code de cet exemple et celui de l’exemple précédent

La première différence est la ligne var point = {x: 0, y: 0}. Cet objet contient le point du coin supérieur gauche de la zone d’agrandissement, quelle que soit la manière dont celle-ci est dessinée.

Ensuite, nous enveloppons la clause d’événement d’appui dans une instruction if pour nous assurer que le code de l’événement d’appui ne s’exécute qu’une seule fois :


if (!globals.pointer.down) {
  globals.pointer.down = true;      
  globals.pointer.x1 = canvasX;
  globals.pointer.y1 = canvasY;          
}

Dans la clause d’événement de déplacement, nous utilisons requestAnimationFrame pour améliorer les performances d’animation de la zone d’agrandissement en dessinant uniquement une zone d’agrandissement (et l’image Mandelbrot sous-jacente) aux intervalles appropriés :


case 'MSGestureChange':                  
case 'mousemove':
  if (globals.pointer.down) {
    zoomBoxHeight = Math.abs(canvasY - globals.pointer.y1); 
    zoomBoxWidth = zoomBoxHeight * canvasWidthHeightRatio; 
               
    if (window.requestAnimationFrame.id) { 
      window.cancelAnimationFrame(window.requestAnimationFrame.id); 
    } 
    window.requestAnimationFrame.id = window.requestAnimationFrame(function() { 
      ctx.putImageData(ctx.imageDataObject, 0, 0); 
      point = getTopLeftZoomBoxPoint(globals.pointer.x1, globals.pointer.y1, canvasX, canvasY);
      ctx.fillRect(point.x, point.y, zoomBoxWidth, zoomBoxHeight); 
    });                        
  } 
  break;

Dans handleLoad, si requestAnimationFrame n’est pas pris en charge, setTimeout est utilisé à la place :


if (!window.requestAnimationFrame) {
  window.cancelAnimationFrame = function(ID) {
    window.clearInterval(ID);
  }
  
  window.requestAnimationFrame = function(callback) { 
    return window.setTimeout(callback, 16.7);
  }
}

Comme vous pouvez le constater dans la clause d’événement de déplacement, au cours d’un événement de déplacement, getTopLeftZoomBoxPoint est appelé et renvoie le coin supérieur gauche de la zone d’agrandissement, de sorte que celle-ci puisse être dessinée à l’aide de fillRect :


point = getTopLeftZoomBoxPoint(globals.pointer.x1, globals.pointer.y1, canvasX, canvasY);
ctx.fillRect(point.x, point.y, zoomBoxWidth, zoomBoxHeight);

Cette fonction est définie comme suit :


function getTopLeftZoomBoxPoint(x1, y1, x2, y2) {
/* 
  (x1, y1) is where the down pointer event occurred. (x2, y2) is where the move or up pointer event occurred.
*/
  if (x1 <= x2) {
    if (y1 <= y2) {
      return {x: x1, y: y1}; // User has drawn (or is drawing) a zoom box from the upper-left toward the lower-right.
    } else { // y1 > y2
      return {x: x1, y: y1 - zoomBoxHeight}; // User has drawn (or is drawing) a zoom box from the lower-left toward the upper-right.
    } // if-else
  } else { // x1 > x2
    if (y1 <= y2) {
      return {x: x1 - zoomBoxWidth, y: y1}; // User has drawn (or is drawing) a zoom box from the upper-right toward the lower-left.
    } else { // y1 > y2
      return {x: x1 - zoomBoxWidth, y: y1 - zoomBoxHeight}; // User has drawn (or is drawing) a zoom box from the lower-right toward the upper-left.
    } // if-else
  } // if-else
} // getTopLeftZoomBoxPoint

Vous pouvez comprendre les clauses if-else en examinant l’image ci-dessous, qui montre les quatre manières possibles de dessiner une zone d’agrandissement d’un coin à un autre :

Quatre exemples de zone d’agrandissement, chacun ayant un point de départ dans un coin différent

Considérez le cas dans lequel l’utilisateur commence en bas à gauche et finit en haut à droite (à savoir, x1 < x2 et y1 > y2). Dans ce cas, getTopLeftZoomBoxPoint renvoie le point {x: x1, y: y1 - zoomBoxHeight} car x1 est la coordonnée x pour le coin supérieur gauche de la zone d’agrandissement et y1 - zoomBoxHeight est la coordonnée y pour le coin supérieur gauche de la zone d’agrandissement. Les trois possibilités restantes pour dessiner une zone d’agrandissement sont calculées de façon similaire.

Pour revenir à handlePointer, la principale modification apportée à la clause d’événement de décollement est la vérification globals.holdGesture :


if (zoomBoxHeight == 0 || globals.holdGesture)

Si, durant un mouvement d’appui prolongé, un événement de décollement se produit, nous exécutons le même code que lorsqu’aucune zone d’agrandissement n’a été dessinée (c’est-à-dire zoomBoxHeight == 0). Notez que globals.holdGesture est initialisé avec la valeur false dans l’événement handleLoad (la clause d’événement MSGestureHold affecte à globals.holdGesture la valeur true).

Threads de travail Web

Mandelbrot 8 annonce simplement que des threads de travail Web sont requis et s’arrête, ce qui ne constitue pas une expérience utilisateur des plus convaincantes. Pour s’adapter aux navigateurs qui ne prennent pas en charge les threads de travail Web, nous empruntons le code Mandelbrot dépourvu de références aux threads de travail Web à partir de Mandelbrot 7 (en le renommant drawMandelbrotWithoutWebWorkers) et nous l’appelons, si nécessaire, dans handleHashChange :


if (window.Worker) {
  initializeWebWorkers('mandelbrotWebWorker.js');
  drawMandelbrotWithWebWorkers(globals.ReMax, globals.ReMin, globals.ImMax, globals.ImMin, globals.grayscaleFactor);              
}
else {
  drawMandelbrotWithoutWebWorkers(globals.ReMax, globals.ReMin, globals.ImMax, globals.ImMin, globals.grayscaleFactor);      
}

En résumé, le didacticiel Comment explorer l’ensemble de Mandelbrot à l’aide de HTML5 a démontré les fonctionnalités clés suivantes de HTML5 :

Ces fonctionnalités, ainsi que quelques autres, ont été utilisées conjointement pour créer une application Web performante capable d’explorer l’un des objets mathématiques les plus complexes et les plus beaux connus : l’ensemble de Mandelbrot. Le tableau suivant fournit des liens vers certaines régions particulièrement intéressantes/inhabituelles de l’ensemble de Mandelbrot, qui vous inciteront à explorer par vous-même cet ensemble remarquable :

Lien
Black Spiral
Blatweasel
Boomerang
Cyclopes
Diamond Fur
Feather Ball
Fern Curl
Four Star
Galactic Spin
Lace
Mandel Swirl
North Star
River Styx
Round Square
Sparkler
Spiderweb
Star Cluster
Straight and Narrow
Swirly Bob
Twiggy

 

Rubriques associées

Comment explorer l’ensemble de Mandelbrot à l’aide de HTML5

 

 

Afficher:
© 2014 Microsoft. Tous droits réservés.