Espace de pixels permettant de dessiner à l'aide d'une multitude de méthodes javascript
Le flash killer ?
Can I Use : http://caniuse.com/#feat=canvas
var canvas = document.querySelector('.canvas'),
context = canvas.getContext('2d');
Ce code ne sera pas répété dans les exemples qui suivent
Pour dessiner, la méthode classique consiste à
Lignes
context.beginPath(); // Commencer un tracé
context.moveTo(50,50); // Placer le tracé
context.lineTo(200,200); // Tracer une ligne
context.lineTo(50,200); // Tracer autre une ligne
context.closePath(); // Tracer une dernière ligne qui ferme la forme (pas obligatoire)
context.stroke(); // Faire apparaitre les lignes tracées
Lignes
Remplissages
context.beginPath(); // Commencer un tracé
context.moveTo(50,50); // Placer le tracé
context.lineTo(200,200); // Tracer une ligne
context.lineTo(50,200); // Tracer autre une ligne
context.fill(); // Faire apparaitre la forme dessinée
Remplissages
Il existe de nombreuses propriétés pour changer le style du dessin
Cela peut concerner les lignes ou le remplissage
Le style s'appliquera sur tous les dessins suivant le changement de propriété
Modifier le style de la ligne
context.beginPath();
context.moveTo(50,50);
context.lineTo(200,200);
context.lineTo(50,200);
context.lineWidth = 20; // Largeur de la ligne
context.lineCap = 'round'; // Fin de ligne (round | butt | square)
context.lineJoin = 'bevel'; // Jointure des lignes (bevel | round | mitter)
context.strokeStyle = 'orange'; // Couleur de la ligne
context.stroke();
Modifier le style de la ligne
Modifier le style de remplissage
context.beginPath();
context.moveTo(50,50);
context.lineTo(200,200);
context.lineTo(50,200);
context.fillStyle = 'rgba(255,0,0,0.5)'; //Couleur du remplissage
context.fill();
Modifier le style de remplissage
Ombres
context.beginPath();
context.moveTo(50,50);
context.lineTo(200,200);
context.lineTo(50,200);
context.fillStyle = 'rgba(255,0,0,1)';
context.shadowColor = 'blue'; // Couleur de l'ombre
context.shadowBlur = 50; // Largeur du flou
context.shadowOffsetX = 5; // Décalage en X
context.shadowOffsetY = 10; // Décalage en Y
context.fill();
Ombres
Certaines méthodes permettent de dessiner autre chose que des lignes
rect() permet de dessiner un rectangle
arc() permet de dessiner un arc de cercle
La variable globale Math possède plusieurs propriétés et méthodes mathématiques
Celle que nous allons utilisé est Math.PI permettant d'obtenir le nombre π utile pour dessiner des arc de cercle
// Style
contexts.fillStyle = 'orange';
contexts.strokeStyle = 'orange';
// Remplissage d'un rectangle
contexts.beginPath();
contexts.rect(50,50,200,100);
contexts.fill();
// Remplissage d'un demi cercle
contexts.beginPath();
contexts.arc(400,50,100,0,Math.PI,false);
contexts.fill();
// Countour d'un recangle
contexts.beginPath();
contexts.fillStyle = 'orange';
contexts.rect(50,200,200,100);
contexts.stroke();
// Contour d'un demi cercle
contexts.beginPath();
contexts.arc(400,200,100,0,Math.PI,false);
contexts.stroke();
fillRect() permet de remplir un rectangle sans passer par beginPath() et fill()
clearRect() permet d'effacer un rectangle
context.fillStyle = 'orange';
context.fillRect(50,50,300,160);
context.clearRect(50,50,100,80);
context.fillStyle = '#00EEFF';
context.fillRect(160,60,20,70);
context.beginPath();
context.fillStyle = 'black';
context.arc(280,210,50,0,Math.PI,false);
context.arc(120,210,50,0,Math.PI,false);
context.fill();
var text = 'Lorem ipsum dolor sit amet';
context.font = '40px Arial'; // Font
context.textAlign = 'center'; // Alignement horizontal (left | center | right)
context.textBaseline = 'top'; // Alignement vertical (top | bottom | middle | alphabetic | hanging)
console.log(context.measureText(text).width); // Affiche la largeur du texte dans la console (sans le dessiner)
context.fillText(text,300,100); // Faire apparaitre le texte
context.strokeText(text,300,160); // Faire apparaitre le contour du texte
Pour dessiner une image, il est nécessaire de l'avoir chargé
Il faut donc créer, en javascript, un objet Image et écouter son événement load
// Créé la variable image
var image = new Image();
// Écoute l'événement load
image.onload = function()
{
// Dessine l'image
context.drawImage(image,0,0,image.width / 6,image.height / 6);
};
// Ajoute le chemin de l'image
image.src = 'image-1.jpg';
Dégradé linéaire
var gradient = context.createLinearGradient(50,50,250,250); // x1, y1, x2, y2
gradient.addColorStop(0, 'rgb(255,80,0)'); // Départ
gradient.addColorStop(0.5,'rgb(255,191,0)'); // Milieu
gradient.addColorStop(1, 'rgb(255,246,155)'); // Arrivée
context.fillStyle = gradient; // Le dégradé devient le style de remplissage
context.fillRect(
0, // X du premier point
0, // Y du premier point
400, // X du second point
400 // Y du second point
);
Dégradé linéaire
Dégradé Radial
var gradient = context.createRadialGradient(
0, // X du premier cercle
0, // Y du premier cercle
50, // Rayon du premier cercle
0, // X du second cercle
250, // Y du second cercle
350 // Rayon du second cercle
);
gradient.addColorStop(0, 'rgb(255,80,0)'); // Couleur de départ
gradient.addColorStop(0.5,'rgb(255,191,0)'); // Couleur de milieu
gradient.addColorStop(1, 'rgb(255,246,155)'); // Couleur de arrivée
context.fillStyle = gradient; // Le dégradé devient le style de remplissage
context.fillRect(0,0,400,400); // Faire apparaître
Dégradé Radial
Les fonctions save() et restore() permettent de sauvegarder l'état du style et de le restaurer
Cela équivaut à un historique de pinceau
context.beginPath();
context.moveTo(50,50);
context.lineTo(300,50);
context.save(); // Sauvegarde les propriétés du context
context.lineWidth = 20; // Changement d'une des propriétés
context.stroke(); // Dessin du trait
context.beginPath();
context.moveTo(50,100);
context.lineTo(300,100);
context.save(); // Nouvelle sauvegarde des propriétés du context
context.strokeStyle = 'red'; // Changement d'une autre propriété
context.stroke(); // Dessin du trait
context.beginPath();
context.moveTo(50,150);
context.lineTo(300,150);
context.restore(); // Restauration des propriétés à la derniène sauvegarde
context.restore(); // Restauration des propriétés à la sauvegarde encore avant
context.stroke(); // Dessin du trait
Les méthodes bezierCurveTo() et quadraticCurveTo() permettent de dessiner des courbes de bézier en spécifiant chacun des points
Courbe de bézier
context.beginPath();
context.moveTo(50,50); // X et Y du point de départ
context.bezierCurveTo(
300, // X du premier point de tension
100, // Y du premier point de tension
100, // X du second point de tension
300, // Y du second point de tension
300, // X du point d'arrivée
300 // Y du point d'arrivée
);
context.stroke();
Courbe de bézier
Courbe de quadratique (de bézier)
context.beginPath();
context.moveTo(50,50); // X et Y du point de départ
context.quadraticCurveTo(
300, // X du seul point de tension
100, // Y du seul point de tension
300, // X du point d'arrivée
300 // Y du point d'arrivée
);
context.stroke();
Courbe de quadratique (de bézier)
context.globalAlpha = 0.3; /* Réduction de l'opacité */
context.fillStyle = '#ff0000';
context.fillRect(50,50,200,200);
context.fillStyle = '#00ff00';
context.fillRect(100,100,200,200);
context.fillStyle = '#0000ff';
context.fillRect(150,150,200,200);
La propriété globalCopositeOperation permet de spécifier comment doivent se comporter les tracés en cours (source) par rapport aux tracés initiaux (destination)
Équivalent au pathfinder d'illustrator
context.globalCompositeOperation = 'lighter';
context.fillStyle = '#ff0000';
context.fillRect(50,50,200,200);
context.fillStyle = '#00ff00';
context.fillRect(100,100,200,200);
context.fillStyle = '#0000ff';
context.fillRect(150,150,200,200);
context.fillStyle = 'red';
context.fillRect(200,200,200,200);
context.globalCompositeOperation = 'destination-out'; /* source-over | source-in | source-out | source-atop | destination-over | destination-in | destination-out | desination-atop | lighter | copy | xor */
context.beginPath();
context.fillStyle = 'blue';
context.arc(200,250,100,0,Math.PI,false);
context.fill();
/* Si vous utilisez une image dans le canvas, lancez MAMP/WAMP pour éviter les proplème de cross-domain */
var image = new Image();
image.onload = function()
{
/* Dessiner l'image chargée dans le canvas */
context.drawImage(image,0,0,image.width / 6,image.height / 6);
/* Récupérer les pixels dans image_data */
var image_data = context.getImageData(0,0,image.width / 6,image.height / 6);
/* parcourir les pixels 4 par 4 */
for(var i = 0; i < image_data.data.length; i += 4)
{
/* Traiter ces pixels couleur par couleur */
/* Ici on rend l'image noir et blanc */
var b = 0.4 * image_data.data[i] + 0.4 * image_data.data[i + 1] + 0.4 * image_data.data[i + 2];
image_data.data[i] = b;
image_data.data[i + 1] = b;
image_data.data[i + 2] = b;
// image_data.data[i + 3] = 1; /* On ne touche pas à l'apha */
}
/* Dessiner la nouvelle image par dessus */
context.putImageData(image_data,0,0);
};
image.src = 'image-1.jpg';
Ne fonctionne pas en local !
Pour animer un canvas, on l'efface complètement et on le redessine à chaque frame (jusqu'à 60 fois par seconde)
Il nous faut donc un fonction qui se déclenche à interval régulier : requestAnimationFrame
Request Animation Frame
/*
La fonction loop sera appelée dès que possible
Plus l'ordinateur est performant, plus la fréquence sera rapide
La fonction ne sera pas appelée tant que l'ordinateur n'est pas prêt
*/
function loop()
{
window.requestAnimationFrame(loop);
console.log('loop');
}
window.requestAnimationFrame(loop);
Can I Use : http://caniuse.com/#feat=requestanimationframe
Le polyfill proposé par Paul Irish
/* Compatible avec tous les navigateurs */
(function() {
var lastTime = 0;
var vendors = ['webkit', 'moz'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame =
window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());
Exemple d'animation
var coords = {x:0,y:200};
function loop()
{
requestAnimationFrame(loop); //Avant d'effectuer d'autre action
//Mettre à jour la position
coords.x += 4;
if(coords.x > canvas.width + 50)
coords.x = -50;
//Redessiner le canvas
context.clearRect(0,0,canvas.width,canvas.height);
context.beginPath();
context.arc(coords.x,coords.y,50,0,Math.PI*2);
context.fillStyle = 'orange';
context.fill();
}
loop();
Exemple d'animation