diff options
author | Florian Merz <me@fiji-flo.de> | 2021-02-11 12:36:08 +0100 |
---|---|---|
committer | Florian Merz <me@fiji-flo.de> | 2021-02-11 12:36:08 +0100 |
commit | 39f2114f9797eb51994966c6bb8ff1814c9a4da8 (patch) | |
tree | 66dbd9c921f56e440f8816ed29ac23682a1ac4ef /files/fr/web/api/canvas_api/tutorial/compositing | |
parent | 8260a606c143e6b55a467edf017a56bdcd6cba7e (diff) | |
download | translated-content-39f2114f9797eb51994966c6bb8ff1814c9a4da8.tar.gz translated-content-39f2114f9797eb51994966c6bb8ff1814c9a4da8.tar.bz2 translated-content-39f2114f9797eb51994966c6bb8ff1814c9a4da8.zip |
unslug fr: move
Diffstat (limited to 'files/fr/web/api/canvas_api/tutorial/compositing')
-rw-r--r-- | files/fr/web/api/canvas_api/tutorial/compositing/example/index.html | 295 | ||||
-rw-r--r-- | files/fr/web/api/canvas_api/tutorial/compositing/index.html | 110 |
2 files changed, 405 insertions, 0 deletions
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 +--- +<div>{{CanvasSidebar}}</div> + +<p>Cet exemple illustre un certain nombre d'<a href="/fr/docs/Web/API/CanvasRenderingContext2D.globalCompositeOperation">opérations de composition</a>. Le résultat donne ceci:</p> + +<p>{{EmbedLiveSample("Exemple_de_composition", "100%", 7250)}}</p> + +<h2 id="Exemple_de_composition">Exemple de composition</h2> + +<p>Ce code configure les valeurs globales utilisées par le reste du programme.</p> + +<pre class="brush: js notranslate">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; +</pre> + +<h3 id="Programme_principal">Programme principal</h3> + +<p>Quand la page se charge, le code suivant s'exécute pour configurer et exécuter l'exemple:</p> + +<pre class="brush: js notranslate">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; +}; +</pre> + +<p>Et dans le code suivant, <code>runComposite()</code> gère la majeure partie du travail, en s'appuyant sur un certain nombre de fonctions utilitaires pour faire les parties difficiles.</p> + +<pre class="brush: js notranslate">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); + } +}; +</pre> + +<h3 id="Fonctions_utilitaires">Fonctions utilitaires</h3> + +<p>Notre programme repose sur un certain nombbre de fonctions utilitaires:</p> + +<pre class="brush: js notranslate">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(); +}; +</pre> + +<pre class="brush: js notranslate">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; +}; +</pre> + +<pre class="brush: js notranslate">// 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");</pre> 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 +--- +<div>{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Transformations", "Web/API/Canvas_API/Tutorial/Basic_animations")}}</div> + +<div class="summary"> +<p>Dans tous nos <a href="/en-US/docs/Web/API/Canvas_API/Tutorial/Transformations">exemples précédents</a>, 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é <code>globalCompositeOperation</code>. En complément, la propriété <code>clip</code> nous permet de cacher les parties des formes que nous ne désirons pas.</p> +</div> + +<h2 id="globalCompositeOperation" name="globalCompositeOperation"><code>globalCompositeOperation</code></h2> + +<p>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.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.globalCompositeOperation", "globalCompositeOperation = type")}}</dt> + <dd>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.</dd> +</dl> + +<p>Reportez-vous aux <a href="/fr/docs/Tutoriel_canvas/Composition/Example">exemples de compositon</a> pour le code des exemples suivants.</p> + +<p>{{EmbedLiveSample("Exemple_de_composition", 750, 6750, "" ,"/Tutoriel_canvas/Composition/Example")}}</p> + +<h2 id="Clipping_paths" name="Clipping_paths">Détourage</h2> + +<p><img alt="" class="internal" src="https://mdn.mozillademos.org/files/209/Canvas_clipping_path.png" style="float: right;">Un détourage (<em>clipping path</em> 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.</p> + +<p>Si nous comparons le détourage à la propriété <code>globalCompositeOperation</code> vue précédemment, nous voyons deux modes de composition qui ont plus ou moins les mémes effets qu'avec <code>source-in</code> et <code>source-atop</code>. 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.</p> + +<p>Dans le chapitre "<a href="/en-US/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes" title="Web/Guide/HTML/Canvas_tutorial/Drawing_shapes#Drawing_paths">dessiner des formes avec le canevas</a>", nous n'avions mentionné que les méthodes <code>stroke()</code> et <code>fill()</code>, mais il y en a une troisième: <code>clip()</code> — elle permet de faire des détourages.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.clip", "clip()")}}</dt> + <dd>Transforme le chemin en cours de création en détourage effectif.</dd> +</dl> + +<p>Il faut utiliser <code>clip()</code> plutot que <code>closePath()</code> pour fermer un chemin et enfaire un détourage.</p> + +<p>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 <span class="ht">apparente</span>.</p> + +<h3 id="A_clip_example" name="A_clip_example">Un exemple de <code>clip</code></h3> + +<p>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...).</p> + +<pre class="brush: js;highlight[9] notranslate">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(); +} +</pre> + +<div class="hidden"> +<pre class="brush: html notranslate"><canvas id="canvas" width="150" height="150"></canvas></pre> + +<pre class="brush: js notranslate">draw();</pre> +</div> + +<p>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 à <code>clip()</code>. 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.</p> + +<p>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 <code>drawStar()</code>. Nous pouvons voir, une fois de plus, que les éléments (ici les étoiles) n'apparaissent qu'à l'intérieur du détourage.</p> + +<p>{{EmbedLiveSample("A_clip_example", "180", "180", "https://mdn.mozillademos.org/files/208/Canvas_clip.png")}}</p> + +<p>{{PreviousNext("Web/API/Canvas_API/Tutorial/Transformations", "Web/API/Canvas_API/Tutorial/Basic_animations")}}</p> |