Changer de coordonnées dans un canvas

Changement de repère


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.
Code: Select all
<canvas id="canvas1" width="300" height="200" style="border: 2px solid black;"></canvas>
<p id="texte">Clic sur le canvas !</p>

<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);
}

// 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>
Affichage:

Clic sur le canvas !

Tracer de 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:
Code: Select all
<canvas id="canvas2" width="300" height="200" style="border: 2px solid #000";></canvas>

<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>
Affichage:

Voir aussi: