From 39f2114f9797eb51994966c6bb8ff1814c9a4da8 Mon Sep 17 00:00:00 2001 From: Florian Merz Date: Thu, 11 Feb 2021 12:36:08 +0100 Subject: unslug fr: move --- .../tutorial/compositing/example/index.html | 295 +++++++++++++++++++++ .../api/canvas_api/tutorial/compositing/index.html | 110 ++++++++ 2 files changed, 405 insertions(+) create mode 100644 files/fr/web/api/canvas_api/tutorial/compositing/example/index.html create mode 100644 files/fr/web/api/canvas_api/tutorial/compositing/index.html (limited to 'files/fr/web/api/canvas_api/tutorial/compositing') diff --git a/files/fr/web/api/canvas_api/tutorial/compositing/example/index.html b/files/fr/web/api/canvas_api/tutorial/compositing/example/index.html new file mode 100644 index 0000000000..8fbb3ec79c --- /dev/null +++ b/files/fr/web/api/canvas_api/tutorial/compositing/example/index.html @@ -0,0 +1,295 @@ +--- +title: Exemple de composition +slug: Web/API/Canvas_API/Tutoriel_canvas/Composition/Example +tags: + - Canvas + - Exemple + - Graphisme + - HTML + - HTML5 + - Tutoriel +translation_of: Web/API/Canvas_API/Tutorial/Compositing/Example +--- +
{{CanvasSidebar}}
+ +

Cet exemple illustre un certain nombre d'opérations de composition. Le résultat donne ceci:

+ +

{{EmbedLiveSample("Exemple_de_composition", "100%", 7250)}}

+ +

Exemple de composition

+ +

Ce code configure les valeurs globales utilisées par le reste du programme.

+ +
var canvas1 = document.createElement("canvas");
+var canvas2 = document.createElement("canvas");
+var gco = [ 'source-over','source-in','source-out','source-atop',
+            'destination-over','destination-in','destination-out','destination-atop',
+            'lighter', 'copy','xor', 'multiply', 'screen', 'overlay', 'darken',
+            'lighten', 'color-dodge', 'color-burn', 'hard-light', 'soft-light',
+            'difference', 'exclusion', 'hue', 'saturation', 'color', 'luminosity'
+          ].reverse();
+var gcoText = [
+"C'est la configuration par défaut, elle dessine les nouvelles formes au-dessus du contenu existant sur le canvas.",
+"La nouvelle forme est dessinée uniquement là où il y a déjà du contenu sur le canvas. Tout le reste est rendu transparent.",
+"La nouvelle forme est dessinée uniquement là où il n'y a pas de contenu sur le canvas.",
+"La nouvelle forme est dessinée uniquement là où il y a déjà du contenu sur le canvas. Elle s'ajoute au contenu existant.",
+"Les nouvelles formes sont dessinées derrière le contenu existant du canvas.",
+"Le contenu existant du canvas est conservé là où il chevauche la nouvelle forme. Tout le reste est rendu transparent.",
+"Le contenu existant du canvas est conservé là où il ne chevauche pas la nouvelle forme.",
+"Le contenu existant du canvas est conservé là où il chevauche la nouvelle forme. La nouvelle forme est dessinée derrière le contenu existant.",
+"La nouvelle forme est ajoutée en additionnant ses couleurs à celles du contenu existant.",
+"Seule la nouvelle forme est affichée.",
+"Les formes sont rendues transparentes lorsqu'elles se chevauchent.",
+"Les pixels de la nouvelle forme sont multipliés avec les pixels du contenu existant. Le résultat est une image plus sombre.",
+"Les pixels sont inversés, multipliés, puis inversés de nouveau. Le résultat est une image plus claire (l'inverse de multiply)",
+"Une combinaison de multiply et screen. Les parties sombres du contenu existant deviennent plus sombres, et les parties claires deviennent plus claires.",
+"Retiens les pixels les plus sombres entre les deux.",
+"Retiens les pixels les plus clairs entre les deux.",
+"Divise le layer inférieur par le layer supérieur inversé.",
+"Divise le layer inférieur inversé par le layer supérieur, puis inverse le résultat.",
+"Une combinaison de multiply et screen (comme overlay), mais avec le layer supérieur et inférieur inversés.",
+"Assombrit ou éclaircit les couleurs, en fonction de la couleur de la forme ajoutée.",
+"Soustrait le layer inférieur au layer supérieur ou inversemment pour toujours obtenir une valeur positive.",
+"Comme difference, mais avec un contraste moins élevé.",
+"Préserve la luminance et saturation du layer inférieur, et utilise la teinte du layer supérieur.",
+"Préserve la luminance et teinte du layer inférieur, et utilise la saturation du layer supérieur.",
+"Préserve la luminance du layer inférieur, et utilise la teinte et saturation du layer supérieur.",
+"Préserve la teinte et saturation du layer inférieur, et utilise la luminance du layer supérieur."
+].reverse();
+var width = 320;
+var height = 340;
+
+ +

Programme principal

+ +

Quand la page se charge, le code suivant s'exécute pour configurer et exécuter l'exemple:

+ +
window.onload = function() {
+    // lum en sRGB
+    var lum = {
+        r: 0.33,
+        g: 0.33,
+        b: 0.33
+    };
+    // redimensionne le canvas
+    canvas1.width = width;
+    canvas1.height = height;
+    canvas2.width = width;
+    canvas2.height = height;
+    lightMix()
+    colorSphere();
+    runComposite();
+    return;
+};
+
+ +

Et dans le code suivant, runComposite() gère la majeure partie du travail, en s'appuyant sur un certain nombre de fonctions utilitaires pour faire les parties difficiles.

+ +
function createCanvas() {
+    var canvas = document.createElement("canvas");
+    canvas.style.background = "url("+op_8x8.data+")";
+    canvas.style.border = "1px solid #000";
+    canvas.style.margin = "5px";
+    canvas.width = width/2;
+    canvas.height = height/2;
+    return canvas;
+}
+
+function runComposite() {
+    var dl = document.createElement("dl");
+    document.body.appendChild(dl);
+    while(gco.length) {
+        var pop = gco.pop();
+        var dt = document.createElement("dt");
+        dt.textContent = pop;
+        dl.appendChild(dt);
+        var dd = document.createElement("dd");
+        var p = document.createElement("p");
+        p.textContent = gcoText.pop();
+        dd.appendChild(p);
+
+        var canvasToDrawOn = createCanvas();
+        var canvasToDrawFrom = createCanvas();
+        var canvasToDrawResult = createCanvas();
+
+        var ctx = canvasToDrawResult.getContext('2d');
+        ctx.clearRect(0, 0, width, height)
+        ctx.save();
+        ctx.drawImage(canvas1, 0, 0, width/2, height/2);
+        ctx.globalCompositeOperation = pop;
+        ctx.drawImage(canvas2, 0, 0, width/2, height/2);
+        ctx.globalCompositeOperation = "source-over";
+        ctx.fillStyle = "rgba(0,0,0,0.8)";
+        ctx.fillRect(0, height/2 - 20, width/2, 20);
+        ctx.fillStyle = "#FFF";
+        ctx.font = "14px arial";
+        ctx.fillText(pop, 5, height/2 - 5);
+        ctx.restore();
+
+        var ctx = canvasToDrawOn.getContext('2d');
+        ctx.clearRect(0, 0, width, height)
+        ctx.save();
+        ctx.drawImage(canvas1, 0, 0, width/2, height/2);
+        ctx.fillStyle = "rgba(0,0,0,0.8)";
+        ctx.fillRect(0, height/2 - 20, width/2, 20);
+        ctx.fillStyle = "#FFF";
+        ctx.font = "14px arial";
+        ctx.fillText('existing content', 5, height/2 - 5);
+        ctx.restore();
+
+        var ctx = canvasToDrawFrom.getContext('2d');
+        ctx.clearRect(0, 0, width, height)
+        ctx.save();
+        ctx.drawImage(canvas2, 0, 0, width/2, height/2);
+        ctx.fillStyle = "rgba(0,0,0,0.8)";
+        ctx.fillRect(0, height/2 - 20, width/2, 20);
+        ctx.fillStyle = "#FFF";
+        ctx.font = "14px arial";
+        ctx.fillText('new content', 5, height/2 - 5);
+        ctx.restore();
+
+        dd.appendChild(canvasToDrawOn);
+        dd.appendChild(canvasToDrawFrom);
+        dd.appendChild(canvasToDrawResult);
+
+        dl.appendChild(dd);
+    }
+};
+
+ +

Fonctions utilitaires

+ +

Notre programme repose sur un certain nombbre de fonctions utilitaires:

+ +
var lightMix = function() {
+    var ctx = canvas2.getContext("2d");
+    ctx.save();
+    ctx.globalCompositeOperation = "lighter";
+    ctx.beginPath();
+    ctx.fillStyle = "rgba(255,0,0,1)";
+    ctx.arc(100, 200, 100, Math.PI*2, 0, false);
+    ctx.fill()
+    ctx.beginPath();
+    ctx.fillStyle = "rgba(0,0,255,1)";
+    ctx.arc(220, 200, 100, Math.PI*2, 0, false);
+    ctx.fill()
+    ctx.beginPath();
+    ctx.fillStyle = "rgba(0,255,0,1)";
+    ctx.arc(160, 100, 100, Math.PI*2, 0, false);
+    ctx.fill();
+    ctx.restore();
+    ctx.beginPath();
+    ctx.fillStyle = "#f00";
+    ctx.fillRect(0,0,30,30)
+    ctx.fill();
+};
+
+ +
var colorSphere = function(element) {
+    var ctx = canvas1.getContext("2d");
+    var width = 360;
+    var halfWidth = width / 2;
+    var rotate = (1 / 360) * Math.PI * 2; // per degree
+    var offset = 0; // scrollbar offset
+    var oleft = -20;
+    var otop = -20;
+    for (var n = 0; n <= 359; n ++) {
+        var gradient = ctx.createLinearGradient(oleft + halfWidth, otop, oleft + halfWidth, otop + halfWidth);
+        var color = Color.HSV_RGB({ H: (n + 300) % 360, S: 100, V: 100 });
+        gradient.addColorStop(0, "rgba(0,0,0,0)");
+        gradient.addColorStop(0.7, "rgba("+color.R+","+color.G+","+color.B+",1)");
+        gradient.addColorStop(1, "rgba(255,255,255,1)");
+        ctx.beginPath();
+        ctx.moveTo(oleft + halfWidth, otop);
+        ctx.lineTo(oleft + halfWidth, otop + halfWidth);
+        ctx.lineTo(oleft + halfWidth + 6, otop);
+        ctx.fillStyle = gradient;
+        ctx.fill();
+        ctx.translate(oleft + halfWidth, otop + halfWidth);
+        ctx.rotate(rotate);
+        ctx.translate(-(oleft + halfWidth), -(otop + halfWidth));
+    }
+    ctx.beginPath();
+    ctx.fillStyle = "#00f";
+    ctx.fillRect(15,15,30,30)
+    ctx.fill();
+    return ctx.canvas;
+};
+
+ +
// HSV (1978) = H: Hue / S: Saturation / V: Value
+Color = {};
+Color.HSV_RGB = function (o) {
+    var H = o.H / 360,
+        S = o.S / 100,
+        V = o.V / 100,
+        R, G, B;
+    var A, B, C, D;
+    if (S == 0) {
+        R = G = B = Math.round(V * 255);
+    } else {
+        if (H >= 1) H = 0;
+        H = 6 * H;
+        D = H - Math.floor(H);
+        A = Math.round(255 * V * (1 - S));
+        B = Math.round(255 * V * (1 - (S * D)));
+        C = Math.round(255 * V * (1 - (S * (1 - D))));
+        V = Math.round(255 * V);
+        switch (Math.floor(H)) {
+            case 0:
+                R = V;
+                G = C;
+                B = A;
+                break;
+            case 1:
+                R = B;
+                G = V;
+                B = A;
+                break;
+            case 2:
+                R = A;
+                G = V;
+                B = C;
+                break;
+            case 3:
+                R = A;
+                G = B;
+                B = V;
+                break;
+            case 4:
+                R = C;
+                G = A;
+                B = V;
+                break;
+            case 5:
+                R = V;
+                G = A;
+                B = B;
+                break;
+        }
+    }
+    return {
+        R: R,
+        G: G,
+        B: B
+    };
+};
+
+var createInterlace = function (size, color1, color2) {
+    var proto = document.createElement("canvas").getContext("2d");
+    proto.canvas.width = size * 2;
+    proto.canvas.height = size * 2;
+    proto.fillStyle = color1; // top-left
+    proto.fillRect(0, 0, size, size);
+    proto.fillStyle = color2; // top-right
+    proto.fillRect(size, 0, size, size);
+    proto.fillStyle = color2; // bottom-left
+    proto.fillRect(0, size, size, size);
+    proto.fillStyle = color1; // bottom-right
+    proto.fillRect(size, size, size, size);
+    var pattern = proto.createPattern(proto.canvas, "repeat");
+    pattern.data = proto.canvas.toDataURL();
+    return pattern;
+};
+
+var op_8x8 = createInterlace(8, "#FFF", "#eee");
diff --git a/files/fr/web/api/canvas_api/tutorial/compositing/index.html b/files/fr/web/api/canvas_api/tutorial/compositing/index.html new file mode 100644 index 0000000000..cc646762dd --- /dev/null +++ b/files/fr/web/api/canvas_api/tutorial/compositing/index.html @@ -0,0 +1,110 @@ +--- +title: Composition et découpe +slug: Web/API/Canvas_API/Tutoriel_canvas/Composition +tags: + - Canvas + - Composition + - dessin +translation_of: Web/API/Canvas_API/Tutorial/Compositing +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Transformations", "Web/API/Canvas_API/Tutorial/Basic_animations")}}
+ +
+

Dans tous nos exemples précédents, les formes étaient toutes dessinées les unes au dessus des autres. C'est plus que suffisant pour la plupart des situations, mais cela limite l'ordre dans lequel les formes composées sont construites. Nous pouvons cependant changer ce comportement en définissant la propriété globalCompositeOperation. En complément, la propriété clip nous permet de cacher les parties des formes que nous ne désirons pas.

+
+ +

globalCompositeOperation

+ +

Nous pouvons non seulement dessiner de nouvelles formes derrière des formes existantes mais nous pouvons aussi les utiliser pour masquer certaines zones, supprimer des sections du canvas (ce n'est pas limité aux rectangles comme pour la méthode {{domxref("CanvasRenderingContext2D.clearRect", "clearRect()")}}) et davantage.

+ +
+
{{domxref("CanvasRenderingContext2D.globalCompositeOperation", "globalCompositeOperation = type")}}
+
Cela configure le type d'opération de composition à appliquer lorsqu'on dessine de nouvelles formes, où le type correspond à une string qui fait référence à une des douze opérations de composition possibles.
+
+ +

Reportez-vous aux exemples de compositon pour le code des exemples suivants.

+ +

{{EmbedLiveSample("Exemple_de_composition", 750, 6750, "" ,"/Tutoriel_canvas/Composition/Example")}}

+ +

Détourage

+ +

Un détourage (clipping path en anglais) est comme une forme de canvas standard, à la différence près qu'elle sert à masquer certaines parties du canvas. Voyez l'image de droite, la forme rouge (en étoile) est un détourage du canvas. Tout ce qui est en dehors du chemin n'est pas dessiné sur le canvas.

+ +

Si nous comparons le détourage à la propriété globalCompositeOperation vue précédemment, nous voyons deux modes de composition qui ont plus ou moins les mémes effets qu'avec source-in et source-atop. La différence la plus significative entre les deux est que le détourage n'est jamais dessiné sur le canvas à proprement parler et il n'est jamais affecté par l'ajout de nouvelles formes. Ça le rend idéal pour dessiner plusieurs formes dans une zone restreinte.

+ +

Dans le chapitre "dessiner des formes avec le canevas", nous n'avions mentionné que les méthodes stroke() et fill(), mais il y en a une troisième: clip() — elle permet de faire des détourages.

+ +
+
{{domxref("CanvasRenderingContext2D.clip", "clip()")}}
+
Transforme le chemin en cours de création en détourage effectif.
+
+ +

Il faut utiliser clip() plutot que closePath() pour fermer un chemin et enfaire un détourage.

+ +

Par défault, l'élément {{HTMLElement("canvas")}} possède un détourage aux mêmes dimensions que le canvas lui-même. Donc, par défaut aucune découpe n'est apparente.

+ +

Un exemple de clip

+ +

Dans cet exemple, nous allons utiliser un détourage circulaire pour restreindre le dessin d'un essemble d'étoiles aléatoires à une zone particulière (et circulaire...).

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  ctx.fillRect(0, 0, 150, 150);
+  ctx.translate(75, 75);
+
+  // Create a circular clipping path
+  ctx.beginPath();
+  ctx.arc(0, 0, 60, 0, Math.PI * 2, true);
+  ctx.clip();
+
+  // draw background
+  var lingrad = ctx.createLinearGradient(0, -75, 0, 75);
+  lingrad.addColorStop(0, '#232256');
+  lingrad.addColorStop(1, '#143778');
+
+  ctx.fillStyle = lingrad;
+  ctx.fillRect(-75, -75, 150, 150);
+
+  // draw stars
+  for (var j = 1; j < 50; j++) {
+    ctx.save();
+    ctx.fillStyle = '#fff';
+    ctx.translate(75 - Math.floor(Math.random() * 150),
+                  75 - Math.floor(Math.random() * 150));
+    drawStar(ctx, Math.floor(Math.random() * 4) + 2);
+    ctx.restore();
+  }
+
+}
+
+function drawStar(ctx, r) {
+  ctx.save();
+  ctx.beginPath();
+  ctx.moveTo(r, 0);
+  for (var i = 0; i < 9; i++) {
+    ctx.rotate(Math.PI / 5);
+    if (i % 2 === 0) {
+      ctx.lineTo((r / 0.525731) * 0.200811, 0);
+    } else {
+      ctx.lineTo(r, 0);
+    }
+  }
+  ctx.closePath();
+  ctx.fill();
+  ctx.restore();
+}
+
+ + + +

Dans les premières lignes de code, nous dessinons un rectangle noir ayant la même taille que le canvas comme toile de fond puis nous déplaçons l'origine au centre de l'image. Ensuite, nous créons le détourage circulaire en dessinant un arc (complet) et en faisant appelle à clip(). Les détourages font aussi partie de l'état de sauvegarde des canvas. Si on voulait garder le détourage d'origine, on pourrait par exemple sauvegarder l'état du canvas au préalable.

+ +

Tout ce qui sera dessiné après la création du détourage n'apparaîtra qu'à l'intérieur de ce chemin. Vous pouvez voir ça clairement avec le dégradé linéaire qui est dessiné après. Ensuite, un ensemble de 50 étoiles aléatoires est dessiné, en utilisant la fonction drawStar(). Nous pouvons voir, une fois de plus, que les éléments (ici les étoiles) n'apparaissent qu'à l'intérieur du détourage.

+ +

{{EmbedLiveSample("A_clip_example", "180", "180", "https://mdn.mozillademos.org/files/208/Canvas_clip.png")}}

+ +

{{PreviousNext("Web/API/Canvas_API/Tutorial/Transformations", "Web/API/Canvas_API/Tutorial/Basic_animations")}}

-- cgit v1.2.3-54-g00ecf