Programmmes en javascript

Changer de coordonnées dans un canvas

Changement de repère


Les calculs et formules mathématiques

L'élément canvas de html5 est une zone délimitée de pixels manipulables. Pour ce faire, il faut avant toute chose être capable de situer un ou des pixels dans cette zone.
Par défaut les coordonnées des pixels dans l'élément canvas ont comme origine le coin supérieur gauche de l'élément, et la direction des axes respecte le sens de lecture naturel: de la gauche vers la droite pour 1ère coordonnée (abscisse) et de haut en bas pour la 2ème coordonnée (ordonnée):

\begin{pspicture}(-1,-1)(10,6)
\pspolygon(0,0)(8,0)(8,5)(0,5)
\rput(-.2,5.4){\large(0,0)}
\rput(-.2,-.4){\large(0,Heigth)}
\rput(8.2,-.4){\large(Width,Heigth)}
\rput(8.2,5.4){\large(Width,0)}
\psline[linestyle=dashed](4,5)(4,2.5)(0,2.5)
\rput(4,2.5){\large\bf+}
\rput(4.2,2.){\large(Width/2,Height/2)}
\psline[linewidth=2pt,linecolor=blue,arrowsize=10pt]{->}(-.5,4.6)(-.5,1.6)
\rput{-90}(-.9,3.4){\large\blue Height}
\psline[linewidth=2pt,linecolor=blue,arrowsize=10pt]{->}(1,5.5)(5.4,5.5)
\rput(3.5,5.8){\large\blue Width}
\end{pspicture}


Ce repère n'est pas forcément le plus naturel à utiliser: on peut être plus habituer à compter positivement en ordonnée vers le haut, à avoir et utiliser des symétries, donc aussi par exemple des coordonnées négatives, à avoir l'origine de notre repère au centre, … c'est-à-dire à utiliser plutôt ce type de repère et de coordonnées:

\begin{pspicture}(-1,-1)(10,6)
\pspolygon(0,0)(8,0)(8,5)(0,5)
\rput(-.2,5.4){\large$\left( x_\text{min},y_\text{max}\rp$}
\rput(-.2,-.4){\large$\left( x_\text{min},y_\text{min}\rp$}
\rput(8.2,-.4){\large$\left( x_\text{max},y_\text{min}\rp$}
\rput(8.2,5.4){\large$\left( x_\text{max},y_\text{max}\rp$}
\psline[linewidth=2pt,linecolor=blue,arrowsize=10pt]{->}(-.5,1)(-.5,4.6)
\rput{90}(-.9,2.8){\large\blue y}
\psline[linewidth=2pt,linecolor=blue,arrowsize=10pt]{->}(1.5,-.5)(5.4,-.5)
\rput(3.5,-.8){\large\blue x}
\end{pspicture}

ou aussi, par exemple et suivant les valeurs minimales et maximales en abscisse et ordonnées, l'origine du repère est dans la zone:

\begin{pspicture}(-1,-1)(10,6)
\pspolygon(0,0)(8,0)(8,5)(0,5)
\psline[linewidth=3pt](0,1.75)(0,2.25)\rput(0,2.4){\large$x_\text{min}$}
\psline[linewidth=3pt](8,1.75)(8,2.25)\rput(8,2.4){\large$x_\text{max}$}
\psline[linewidth=3pt](2.75,0)(3.25,0)\rput(2.4,0.15){\large$y_\text{min}$}
\psline[linewidth=3pt](2.75,5)(3.25,5)\rput(2.4,4.85){\large$y_\text{max}$}
\psline[linewidth=2pt,linecolor=blue,arrowsize=8pt]{->}(2.7,2.2)(2.7,3)
\rput(2.4,2.4){\large\blue y}
\psline[linewidth=2pt,linecolor=blue,arrowsize=8pt]{->}(3.2,1.6)(5,1.6)
\rput(3.8,1.3){\large\blue x}
\psline[linestyle=dashed](3,0)(3,5)\psline[linestyle=dashed](0,2)(8,2)
\psline[linecolor=blue,linewidth=2.5pt](2.77,2)(3.25,2)
\psline[linecolor=blue,linewidth=2.5pt](3.01,1.75)(3.01,2.25)
\rput(2.5,1.6){\large\blue$\left( 0;0\rp$}
\psline[linewidth=2pt,linecolor=red,linestyle=dotted](5,2)(5,3)(3,3)
\rput(5.2,3.3){\large\red$\left( x;y\rp$}
\end{pspicture}


Dans la suite, les coordonnées "naturelles" de canvas sont notées en majuscules: X et Y, tandis que celles redéfinies sont notées en minuscules: x et y.

Les relations de passage d'un système de coordonnées à l'autre sont alors:
\la\begin{array}{ll}
			    x&=x_{min}+X\dfrac{x_{max}-x_{min}}{Width}\\[.6cm]
			    y&=y_{min}+\left( Height-Y\rp\dfrac{y_{max}-y_{min}}{Height}
			    \enar\right.


ou inversement:

\la\begin{array}{ll}
			    X&=Width\tm\dfrac{x-x_{min}}{x_{max}-x_{min}}\\[.6cm]
			    Y&=Height-Height\tm\dfrac{y-y_{min}}{y_{max}-y_{min}}
			    =Height\tm\dfrac{y_{max}-y}{y_{max}-y_{min}}
			    \enar\right.

Dans le code javascript qui suit, quatre fonctions opèrent ces changements de coordonnées (en rouge dans le code ci-dessous, et respectant les notations précédentes, minuscules et majuscules). En prime, l'affichage des nouveaux axes et des valeurs minimales et maximales, ainsi que la gestion de la position de la souris lors d'un clic avec affichage des coordonnées de cette position, bien sûr dans les deux systèmes de coordonnées.

Résultat / Affichage

On commence par le résultat: le canvas sur lequel il suffit de cliquer pour afficher les coordonnées dans les deux repères: celui par défaut du canvas et le repère affiché, plus couant en maths.

Clic sur le canvas !


Le html: déclaration du canvas


<canvas id="canvas1" width="300" height="200" style="border: 2px solid black;">
</canvas>
<p id="texte">Clic sur le canvas !</p>

Bien sûr, le style css du canvas peut (doit) être mis à part dans l'en-têtre ou un fichier css distinct.

Le javascript pour piloter le canvas, avec les changements de repère et coordonnées

On récupère les dimensions du canvas Width et Height, ce qui permet de définir les 4 fonctions (en rouge dans le code suivant) de changement de coordonnées, abscisses et ordonnées, et le repère par défaut de canvas et celui qu'on souhaite définir et utiliser.
On pourrait regrouper ces fonctions en 2 seulement qui retrourne directement le couple de coordonnées, à voir…

<script>
// On récupère les dimensions du canvas:
Width=document.getElementById("canvas1").width;
Height=document.getElementById("canvas1").height;
// et on fixe les bornes de nos nouveaux axes:
xmin=-10;xmax=10;ymin=-15;ymax=32;

// Conversions de coordonnees: 
//  [xmin;xmax]<->[0;Width] et [ymin;ymax]<->[0;Height] 
function cnv2x(X) {return X*(xmax-xmin)/Width+xmin;}
function cnv2y(Y) {return (Height-Y)*(ymax-ymin)/Height+ymin;}
function x2cnv(x) {return Width*(x-xmin)/(xmax-xmin);}
function y2cnv(y) {return Height-Height*(y-ymin)/(ymax-ymin);}
// Fonction qui trace les nouveaux axes et affiche les bornes: function Plot_axes() {
// Nouveaux axes: context.beginPath(); context.moveTo(x2cnv(0),y2cnv(ymin));context.lineTo(x2cnv(0),y2cnv(ymax)); context.moveTo(x2cnv(xmin),y2cnv(0));context.lineTo(x2cnv(xmax),y2cnv(0)); context.stroke(); // Affichage des valeurs min et max aux extrémités des axes: context.fillText(xmin,x2cnv(xmin),y2cnv(0)); context.fillText(xmax,x2cnv(xmax)-12,y2cnv(0)); context.fillText(ymin,x2cnv(0),y2cnv(ymin)-2); context.fillText(ymax,x2cnv(0),y2cnv(ymax)+10); }

// Pour l'exemple ici, on affiche les coordonnées au // Click de la souris function MouseClickDown(e){ X = e.pageX - canvas.offsetLeft; Y = e.pageY - canvas.offsetTop; // On efface toute le canvas context.clearRect(0,0,Width,Height); // On retrace les axes Plot_axes(); // On marque par une croix l'emplacement du click: context.fillRect(X-5,Y,10,1);context.fillRect(X,Y-5,1,10); // et on affiche les coordonnées: document.getElementById("texte").innerHTML="(X,Y) = ("+X+" ; "+Y+")"; document.getElementById("texte").innerHTML+="(x,y) = ("+Math.round(cnv2x(X)*100)/100+" ; "+Math.round(cnv2y(Y)*100)/100+")"; }
// Et c'est parti: canvas = document.getElementById("canvas1"); context = canvas.getContext("2d"); Plot_axes();
canvas.onmousedown = MouseClickDown;
</script>


Tracé de la courbe représentative d'une fonction

Dans ce nouveau repère on peut par exemple maintenant simplement tracer la courbe représentative d'une fonction.
Par exemple pour la fonction carré, on trace la parabole dans un système de coordonnées "plus naturel" que celui proposé par défaut par canvas:

Résultat: affichage de la courbe dans son repère

Code html / javascript

Le canvas html

On définit tout d'abord le canvas, avant le javascript pour y dessiner.

<canvas id="canvas2" width="300" height="200" style="border: 2px solid #000";></canvas>

Javascript pour tracer

La première partie du code provient du précédent: récupérer les dimensions du canvas, puis définir les fonctions qui permettent de changer de système de coordonnées.
On définit aussi la fonction f dont on souhaite tracer la courbe (simplement la fonction carré ici).
Ensuite, on trace les axes du repère et suffisament de points de la courbe (1000 ici) pour percevoir une courbe "continue" (si c'est le cas de la fonction comme ici).

<script>
// Dimensions du canvas: Width=document.getElementById("canvas2").width; Height=document.getElementById("canvas2").height; // et on fixe les bornes de nos nouveaux axes: xmin=-10;xmax=10;ymin=-15;ymax=100; // Définition de la fonction à tracer: function f(x) {return x*x;} nb_pts=1000; // nombre de points utilisés pour le tracé de la courbe // Conversions de coordonnees: [xmin;xmax]<->[0;Width] et [ymin;ymax]<->[0;Height] function cnv2x(X) {return X*(xmax-xmin)/Width+xmin;} function cnv2y(Y) {return (Height-Y)*(ymax-ymin)/Height+ymin;} function x2cnv(x) {return (x-xmin)/(xmax-xmin)*Width;} function y2cnv(y) {return Height-(y-ymin)/(ymax-ymin)*Height;} // Fonction qui trace les nouveaux axes et affiche les bornes: function Plot_axes() {  // Nouveaux axes:  context.beginPath();  context.moveTo(x2cnv(0),y2cnv(ymin));context.lineTo(x2cnv(0),y2cnv(ymax));  context.moveTo(x2cnv(xmin),y2cnv(0));context.lineTo(x2cnv(xmax),y2cnv(0));  context.stroke();  // Affichage des valeurs min et max aux extrémités des axes:  context.fillText(xmin,x2cnv(xmin),y2cnv(0));  context.fillText(xmax,x2cnv(xmax)-12,y2cnv(0));  context.fillText(ymin,x2cnv(0),y2cnv(ymin)-2);  context.fillText(ymax,x2cnv(0),y2cnv(ymax)+10); } // Et c'est parti: canvas = document.getElementById("canvas2"); context = canvas.getContext("2d"); Plot_axes(); // Tracer de la courbe de f:  for (var xi=xmin;xi<xmax;xi=xi+(xmax-xmin)/nb_pts) {  context.fillStyle = "blue";  context.fillRect(x2cnv(xi),y2cnv(f(xi)),2,2); } </script>

Un exemple plus complet et détaillé se trouve sur cette page


Voir aussi:
LongPage: h2: 3 - h3: 5