Canvas From Scratch Transformations et dégradés

Dans cet article, je vais vous expliquer les transformations de la zone de travail, ainsi que les ombres et les dégradés. Les transformations constituent un ensemble de méthodes extrêmement précieuses qui vous permettent de commencer à être créatif avec la façon dont vous dessinez des objets sur le canevas. Commençons après le saut!


Mise en place

Vous allez utiliser le même modèle HTML que dans les articles précédents, ouvrez votre éditeur favori et collez le code suivant:

   Toile à partir de zéro          

Ici, nous n’avons rien de plus qu’une page HTML de base avec un Toile élément et du code JavaScript exécuté après le chargement du DOM. Rien de fou.


Traductions en action

Traduire déplace essentiellement le système de coordonnées entier.

Une des transformations les plus simples de la toile est Traduire. Cela vous permet de déplacer le point d'origine du contexte de rendu 2D; la position (0, 0) sur la toile. Laissez moi vous montrer ce que cela signifie.

Tout d’abord, placez un carré dans le canevas à la position (0, 0):

ctx.fillRect (0, 0, 100, 100);

Il va se dessiner sur le bord supérieur gauche de la toile. Toujours rien d’extraordinaire ici.

Maintenant, essayez de traduire le contexte de rendu 2D et de dessiner un autre carré dans la même position:

ctx.save (); ctx.translate (100, 100); ctx.fillStyle = "rgb (0, 0, 255)"; ctx.fillRect (0, 0, 100, 100); ctx.restore ();

Que penses-tu qu'il va se passer? Avoir une étoile d'or si vous avez deviné que le nouveau carré sera tiré à la position (100, 100). Pas de temps de jeu pour ceux qui ont mal deviné. Pardon!

Alors que s'est-il passé ici alors? En ce qui concerne le code pour dessiner le deuxième carré, vous l’avez dessiné au même endroit que le premier. La raison en est que vous avez essentiellement déplacé tout le système de coordonnées de la toile de sorte que sa position (0, 0) se trouve maintenant à l'emplacement (100, 100)..

Cela a-t-il un peu plus de sens maintenant? J'espere. Cela peut prendre un peu de temps, mais c'est un concept simple une fois que vous l'avez compris..

Vous n'utiliserez probablement pas trop cette transformation seule, car vous pourriez simplement dessiner le deuxième carré en (100, 100) pour obtenir le même effet. La beauté de Traduire, cependant, est-ce que vous pouvez le combiner avec d'autres transformations pour faire des choses plutôt cool.

Jetons un coup d'oeil à la prochaine transformation de la liste.


Mise à l'échelle de vos visuels

Comme vous l'avez probablement deviné, le échelle la transformation est utilisée pour le redimensionnement. Plus spécifiquement, la transformation d'échelle est utilisée pour mettre à l'échelle le contexte de rendu 2D.

Supprimez le code sur lequel vous avez travaillé avec le Traduire exemple, et ajoutez le code suivant:

ctx.fillRect (100, 100, 100, 100);

Cela va tracer un carré standard à la position (100, 100), avec une largeur et une hauteur de 100 pixels. Alors, comment pouvons-nous faire évoluer cette?

Les propriétés en échelle sont des multiplicateurs pour les dimensions x et y.

le échelle la transformation est utilisée de manière similaire à Traduire, en ce sens qu'il est appelé avant de dessiner les objets sur lesquels vous souhaitez l'appliquer. Il est important de souligner que les propriétés dans échelle sont des multiplicateurs pour le X et y dimensions. Cela signifie qu'un échelle de (1, 1) multiplierait la taille du contexte de rendu 2D par un, en lui laissant la même taille qu'auparavant. UNE échelle de (5, 5) multiplierait par cinq la taille du contexte de rendu 2D, le rendant ainsi cinq fois plus important qu'auparavant. Simple.

Dans votre cas, vous voulez doubler la taille du carré, vous appliquez donc un échelle de (2, 2):

ctx.save (); échelle de ctx (2, 2); ctx.fillRect (100, 100, 100, 100); ctx.restore ();

Ce qui donne un carré deux fois plus grand:

Cependant, remarquez que le carré est maintenant tracé dans une position différente de celle qui était tracée avant l'application échelle. La raison en est que échelle multiplie la taille de tout dans le contexte de rendu 2d, y compris les coordonnées. Dans votre cas, la position (100, 100) devient maintenant (200, 200); les coordonnées sont deux fois la taille qu'elles seraient sans être mises à l'échelle.

Pour contourner cela, nous pouvons effectuer une Traduire qui déplace l'origine du contexte de rendu 2d vers la position dans laquelle vous voulez dessiner le carré. Si vous postulez alors échelle et tracez le carré à la position (0, 0), sa position ne sera pas modifiée:

ctx.save (); ctx.translate (100, 100); échelle de ctx (2, 2); ctx.fillRect (0, 0, 100, 100); ctx.restore ();

Il en résulte un carré deux fois plus grand que l'original, mais tracé à la même position que l'original:

C'est être conscient de ces petites bizarreries dans les transformations qui les aident vraiment à les utiliser. La plupart des problèmes communs avec les transformations semblent être le résultat de la compréhension de leur fonctionnement..


Éléments rotatifs

Jusqu'à présent, toutes les transformations auxquelles vous avez fait face ont été plutôt anodines. Heureusement, le tourner la transformation est là pour sauver la journée, et il est facilement mon préféré du groupe.

Je suis sûr tourner pas besoin d’introduction, alors sautons directement dans un carré de 45 degrés (rappelez-vous que les degrés doivent être exprimés en radians):

ctx.save (); ctx.rotate (Math.PI / 4); // Rotation de 45 degrés (en radians) ctx.fillRect (100, 100, 100, 100); ctx.restore ();

Qui positionne un carré à (100, 100) et tourne? woah, accrochez-vous! Cela ne semble pas correct:

Vous voyez ce qui s'est passé? Le carré semble tenter d'échapper à la fenêtre du navigateur plutôt que de tourner sur place à la position (100, 100). Ceci est dû au fait tourner, comme toutes les transformations, affecte tout le contexte de rendu 2d, et non les objets individuellement.

Voici une illustration de ce qu’il advient du système de coordonnées lorsque vous effectuez une opération à 45 degrés. tourner:

Remarquez comment le système de coordonnées entier a pivoté de 45 degrés par rapport au point d'origine (0, 0)? C’est ce qui a donné l’impression que le carré s’échappait de la fenêtre du navigateur, tout simplement parce que la position (100, 100) avait subi une rotation..

Le moyen simple de contourner ce problème est de combiner tourner avec Traduire, ainsi:

ctx.save (); ctx.translate (150, 150); // Traduire au centre du carré ctx.rotate (Math.PI / 4); // rotation de 45 degrés ctx.fillRect (-50, -50, 100, 100); // Centre au point de rotation ctx.restore ();

Effectuer le Traduire déplace le point d'origine du contexte de rendu 2d (0, 0) vers ce qui devrait être le point central du carré (150, 150). Cela signifie que toute rotation sera maintenant basée sur la position (150, 150). Si vous dessinez alors un carré avec un négatif X et y position, égale à la moitié de la largeur et de la hauteur du carré, vous finirez par dessiner un carré qui ressemble à une rotation autour de son point central:

le tourner La transformation est probablement le plus difficile à comprendre complètement. Il est important de noter que les transformations sont effectuées sur l'ensemble du contexte de rendu 2D et que, si vous souhaitez faire pivoter une forme autour de son point central, vous devez combiner tourner avec Traduire.

Passons à quelque chose d'un peu plus impressionnant visuellement.


Ajout d'ombres

Ajouter des ombres aux objets est délicieusement simple.

Canvas est fourni avec quelques propriétés permettant de manipuler l'apparence des objets dessinés dessus. Un ensemble de ces propriétés vous permet d'ajouter des ombres..

Ajouter des ombres aux objets est délicieusement simple. Il faut simplement le shadowColor propriété à définir sur le contexte de rendu 2d sur une couleur qui n’est pas transparente en noir, et l’un des shadowBlur, shadowOffsetX, ou shadowOffsetY propriétés à définir sur une valeur autre que 0.

Essayez le code suivant:

ctx.save (); ctx.shadowBlur = 15; ctx.shadowColor = "rgb (0, 0, 0)"; ctx.fillRect (100, 100, 100, 100); ctx.restore ();

Cela donnera à l'ombre un flou de quinze pixels et définira la couleur en noir uni:

Joli truc standard jusqu'à présent.

Si vous définissez le shadowBlur à 0, changez le shadowColor à un gris clair, et donner un positif shadowOffsetX et shadowOffsetY:

ctx.save (); ctx.shadowBlur = 0; ctx.shadowOffsetX = 6; ctx.shadowOffsetY = 6; ctx.shadowColor = "rgba (125, 125, 125, 0,5)"; // gris transparent ctx.fillRect (300, 100, 100, 100); ctx.restore ();

Vous allez vous retrouver avec une ombre pleine qui apparaît légèrement à droite et en dessous de l'objet dessiné:

Même si les ombres sont cool, elles peuvent être un peu une ressource..

Il est important de se rappeler que les ombres affectent tout ce qui est dessiné après leur définition. Il est donc utile d’utiliser le enregistrer et restaurer méthodes pour vous éviter d'avoir à réinitialiser les propriétés de l'ombre une fois que vous les avez utilisées.

N'oubliez pas que les performances peuvent être pénalisées lorsque vous appliquez une ombre à de nombreux objets en même temps. Dans certains cas, il peut être intéressant d’utiliser une image PNG avec une ombre au lieu de dessiner un objet manuellement et d’appliquer une ombre dynamique à l’aide de code. Nous verrons comment utiliser des images avec canevas dans le prochain épisode de cette série..


Créer des dégradés

Vous pouvez créer deux types de dégradés dans le canevas: linéaire et radial..

Les dernières fonctionnalités que je souhaite aborder avec vous dans ce didacticiel sont des dégradés. Il existe deux types de dégradés dans la zone de travail, le premier étant les dégradés linéaires (droits). Vous pouvez créer un dégradé linéaire en utilisant le createLinearGradient méthode (assez surprenant), qui ressemble à ceci dans le pseudo-code:

ctx.createLinearGradient (startX, startY, endX, endY);

Le premier ensemble de deux arguments est le X et y position du début du gradient, et le deuxième ensemble d’arguments est le X et y position de la fin du gradient. Il est également important de souligner qu'un dégradé dans une zone de dessin est en réalité un type de valeur de couleur. Vous devez donc les appliquer à la couleur. fillStyle et strokeStyle Propriétés.

Voici un exemple de création d'un dégradé linéaire allant du haut du canevas jusqu'au bas:

var gradient = ctx.createLinearGradient (0, 0, 0, canvas.height); gradient.addColorStop (0, "rgb (255, 255, 255)"); gradient.addColorStop (1, "rgb (0, 0, 0)"); ctx.save (); ctx.fillStyle = gradient; ctx.fillRect (0, 0, canvas.width, canvas.height); ctx.restore ();

Notez comment vous assignez le dégradé à une variable, puis utilisez cette variable pour appeler le addColorStop méthode. Cette méthode vous permet de définir la couleur à des points particuliers du dégradé. Par exemple, la position 0 représenterait le début du gradient (le premier X et y position), et 1 représenterait la fin de la pente (la seconde X et y position). Vous pouvez également utiliser des points décimaux compris entre 0 et 1 pour attribuer une couleur à un point différent le long du dégradé, par exemple 0,5 serait à mi-chemin.

En appliquant la variable de gradient à la fillStyle bien, vous vous retrouvez avec un joli dégradé qui va du blanc (position 0 en haut de la toile) au noir (position 1 en bas de la toile):

Mais vous ne devez pas toujours utiliser des gradients linéaires; vous pouvez également créer des dégradés radiaux!

Les dégradés radiaux sont créés avec le createRadialGradient méthode, qui ressemble à ceci dans le pseudo-code:

ctx.createRadialGradient (startX, startY, startRadius, endX, endY, endRadius);

Le premier ensemble de trois arguments est le X et y position du cercle ainsi que le rayon du cercle au début du dégradé, les trois derniers arguments représentant le X et y position ainsi que le rayon du cercle à la fin du dégradé.

Cela semble déroutant, non? C'est un peu, alors sautons dedans et créons un dégradé radial pour voir ce qui se passe:

var gradient = ctx.createRadialGradient (350, 350, 0, 50, 50, 100); gradient.addColorStop (0, "rgb (0, 0, 0)"); gradient.addColorStop (1, "rgb (125, 125, 125)"); ctx.save (); ctx.fillStyle = gradient; ctx.fillRect (0, 0, canvas.width, canvas.height); ctx.restore ();

Vous avez créé un dégradé radial dont le point de départ est (350, 350) avec un rayon de 0 et le point final (50, 50) avec un rayon de 100. Pouvez-vous deviner à quoi il ressemblera? 20 points si vous avez deviné que cela ressemblerait à ceci:

Si vous ressemblez à moi, ce n'est pas ce à quoi je m'attendais. J'ai déjà utilisé des dégradés radiaux dans des applications comme Adobe Photoshop, et ils ne ressemblent en rien à ça! Alors, pourquoi ça ressemble à ça alors? Eh bien, c'est ce à quoi il est censé ressembler, étrangement.

Découvrez ce diagramme qui décrit exactement le fonctionnement d'un dégradé radial dans l'espace de travail:

Intéressant, n'est-ce pas? En gros, il vous permet de créer une forme de cône, mais que se passe-t-il si vous voulez créer un dégradé radial approprié, comme celui de Photoshop? Heureusement c'est simple.

Pour créer un dégradé radial approprié, il vous suffit de placer exactement les deux cercles du dégradé. X et y position, en vous assurant que l’un des cercles de dégradé est plus grand que l’autre:

var canvasCentreX = canvas.width / 2; var canvasCentreY = canvas.height / 2; var gradient = ctx.createRadialGradient (canvasCentreX, canvasCentreY, 250, canvasCentreX, canvasCentreY, 0); gradient.addColorStop (0, "rgb (0, 0, 0)"); gradient.addColorStop (1, "rgb (125, 125, 125)"); ctx.save (); ctx.fillStyle = gradient; ctx.fillRect (0, 0, canvas.width, canvas.height); ctx.restore ();

Le code ci-dessus crée un dégradé radial situé au centre de la zone de dessin. Un des cercles du dégradé a un rayon de 0, tandis que l’autre a un rayon de 250. Le résultat est un dégradé radial traditionnel qui se déplace du centre de la toile vers l’extérieur, comme suit:

Cela a l'air mieux! Honnêtement, j'ai été étonné de voir comment les dégradés radiaux étaient mis en œuvre dans la toile. Je parie que beaucoup de gens ont trébuché quand ils voient cette forme de cône. Oh bien, au moins vous savez comment créer les bons maintenant.

Il convient de souligner que les dégradés dans la zone de travail sont également des opérations très intensives. Si vous souhaitez couvrir l'intégralité du canevas dans un dégradé, envisagez d'abord d'appliquer un arrière-plan dégradé CSS3 à l'élément de canevas lui-même..


Emballer

Dans cet article, nous avons expliqué comment effectuer des transformations de base sur le canevas, notamment des traductions, une mise à l'échelle et une rotation. Vous avez également appris à ajouter des ombres à des objets et à créer des dégradés. Cela ne semble pas beaucoup, mais les transformations, en particulier, forment la colonne vertébrale de certains des éléments les plus intéressants pouvant être réalisés dans la toile..

Dans l'entrée suivante dans "Toile de Scratch", nous allons rompre avec le dessin d'objets et examiner comment manipuler les images et la vidéo dans le canevas. C'est là que les choses commencent à devenir vraiment intéressantes! Restez à l'écoute!