From cb9e359a51c3249d8f5157db69d43fd413ddeda6 Mon Sep 17 00:00:00 2001 From: Florian Merz Date: Thu, 11 Feb 2021 14:45:12 +0100 Subject: unslug ca: move --- .../tutorial/advanced_animations/index.html | 380 +++++++++++ .../animacions_avan\303\247ades/index.html" | 380 ----------- .../animacions_b\303\240siques/index.html" | 335 ---------- .../tutorial/aplicar_estils_i_colors/index.html | 733 --------------------- .../tutorial/applying_styles_and_colors/index.html | 733 +++++++++++++++++++++ .../tutorial/basic_animations/index.html | 335 ++++++++++ .../api/canvas_api/tutorial/basic_usage/index.html | 158 +++++ .../tutorial/composici\303\263/index.html" | 113 ---- .../api/canvas_api/tutorial/compositing/index.html | 113 ++++ .../canvas_api/tutorial/dibuixar_text/index.html | 165 ----- .../canvas_api/tutorial/drawing_text/index.html | 165 +++++ .../manipular_p\303\255xels_amb_canvas/index.html" | 307 --------- .../pixel_manipulation_with_canvas/index.html | 307 +++++++++ .../canvas_api/tutorial/transformacions/index.html | 290 -------- .../canvas_api/tutorial/transformations/index.html | 290 ++++++++ .../tutorial/\303\272s_b\303\240sic/index.html" | 158 ----- 16 files changed, 2481 insertions(+), 2481 deletions(-) create mode 100644 files/ca/web/api/canvas_api/tutorial/advanced_animations/index.html delete mode 100644 "files/ca/web/api/canvas_api/tutorial/animacions_avan\303\247ades/index.html" delete mode 100644 "files/ca/web/api/canvas_api/tutorial/animacions_b\303\240siques/index.html" delete mode 100644 files/ca/web/api/canvas_api/tutorial/aplicar_estils_i_colors/index.html create mode 100644 files/ca/web/api/canvas_api/tutorial/applying_styles_and_colors/index.html create mode 100644 files/ca/web/api/canvas_api/tutorial/basic_animations/index.html create mode 100644 files/ca/web/api/canvas_api/tutorial/basic_usage/index.html delete mode 100644 "files/ca/web/api/canvas_api/tutorial/composici\303\263/index.html" create mode 100644 files/ca/web/api/canvas_api/tutorial/compositing/index.html delete mode 100644 files/ca/web/api/canvas_api/tutorial/dibuixar_text/index.html create mode 100644 files/ca/web/api/canvas_api/tutorial/drawing_text/index.html delete mode 100644 "files/ca/web/api/canvas_api/tutorial/manipular_p\303\255xels_amb_canvas/index.html" create mode 100644 files/ca/web/api/canvas_api/tutorial/pixel_manipulation_with_canvas/index.html delete mode 100644 files/ca/web/api/canvas_api/tutorial/transformacions/index.html create mode 100644 files/ca/web/api/canvas_api/tutorial/transformations/index.html delete mode 100644 "files/ca/web/api/canvas_api/tutorial/\303\272s_b\303\240sic/index.html" (limited to 'files/ca/web/api/canvas_api') diff --git a/files/ca/web/api/canvas_api/tutorial/advanced_animations/index.html b/files/ca/web/api/canvas_api/tutorial/advanced_animations/index.html new file mode 100644 index 0000000000..4aebb46529 --- /dev/null +++ b/files/ca/web/api/canvas_api/tutorial/advanced_animations/index.html @@ -0,0 +1,380 @@ +--- +title: Animacions avançades +slug: Web/API/Canvas_API/Tutorial/Animacions_avançades +tags: + - Canvas + - Graphics + - Tutorial +translation_of: Web/API/Canvas_API/Tutorial/Advanced_animations +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_animations", "Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas")}}
+ +
+

En l'últim capítol vam fer algunes animacions bàsiques i vam conèixer maneres de fer moure les coses. En aquesta part veurem més d'a prop el moviment en si i afegirem una mica de física per fer que les nostres animacions siguin més avançades.

+
+ +

Dibuixar una bola

+ +

Usarem una bola per als nostres estudis d'animació, així que primer dibuixarem aquesta bola sobre el llenç. El següent codi ens configurarà.

+ +
<canvas id="canvas" width="600" height="300"></canvas>
+
+ +

Com és habitual, primer necessitem un context de dibuix. Per dibuixar la bola, hem crear un objecte ball que contingui propietats i un mètode draw() per pintar-la sobre el llenç.

+ +
var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+
+var ball = {
+  x: 100,
+  y: 100,
+  radius: 25,
+  color: 'blue',
+  draw: function() {
+    ctx.beginPath();
+    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
+    ctx.closePath();
+    ctx.fillStyle = this.color;
+    ctx.fill();
+  }
+};
+
+ball.draw();
+ +

Aquí no hi ha res especial, la bola és en realitat un cercle senzill i es dibuixa amb l'ajuda del mètode {{domxref("CanvasRenderingContext2D.arc()", "arc()")}}.

+ +

Afegir velocitat

+ +

Ara que tenim la bola, estem preparats per afegir una animació bàsica tal com hem après en l'últim capítol d'aquest tutorial. Novament, {{domxref("window.requestAnimationFrame()")}} ens ajuda a controlar l'animació. La bola es mou en afegir un vector de velocitat a la posició. Per a cada fotograma, també {{domxref("CanvasRenderingContext2D.clearRect", "clear", "", 1)}} el llenç per eliminar cercles antics de fotogrames anteriors.

+ +
var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+var raf;
+
+var ball = {
+  x: 100,
+  y: 100,
+  vx: 5,
+  vy: 2,
+  radius: 25,
+  color: 'blue',
+  draw: function() {
+    ctx.beginPath();
+    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
+    ctx.closePath();
+    ctx.fillStyle = this.color;
+    ctx.fill();
+  }
+};
+
+function draw() {
+  ctx.clearRect(0,0, canvas.width, canvas.height);
+  ball.draw();
+  ball.x += ball.vx;
+  ball.y += ball.vy;
+  raf = window.requestAnimationFrame(draw);
+}
+
+canvas.addEventListener('mouseover', function(e) {
+  raf = window.requestAnimationFrame(draw);
+});
+
+canvas.addEventListener('mouseout', function(e) {
+  window.cancelAnimationFrame(raf);
+});
+
+ball.draw();
+
+ +

Límits

+ +

Sense cap prova de col·lisió de límits, la nostra bola surt ràpidament del llenç. Hem de comprovar si la posició x i y de la bola està fora de les dimensions del llenç i invertir la direcció dels vectors de velocitat. Per fer-ho, afegim les següents comprovacions al mètode draw:

+ +
if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
+  ball.vy = -ball.vy;
+}
+if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
+  ball.vx = -ball.vx;
+}
+ +

Primera demostració

+ +

Vegem com es veu en acció fins ara. Movem el ratolí en el llenç per iniciar l'animació.

+ + + +

{{EmbedLiveSample("First_demo", "610", "310")}}

+ +

Acceleració

+ +

Per fer el moviment més real, es pots jugar amb la velocitat d'aquesta manera, per exemple:

+ +
ball.vy *= .99;
+ball.vy += .25;
+ +

Això retarda la velocitat vertical de cada fotograma, de manera que la bola només rebotarà en el sòl al final.

+ + + +

{{EmbedLiveSample("Second_demo", "610", "310")}}

+ +

Efecte cua

+ +

Fins ara, hem utilitzat el mètode {{domxref("CanvasRenderingContext2D.clearRect", "clearRect")}} per esborrar fotogrames anteriors. Si reemplacem aquest mètode per un semi-transparent {{domxref("CanvasRenderingContext2D.fillRect", "fillRect")}}, es pot crear fàcilment un efecte cua.

+ +
ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
+ctx.fillRect(0, 0, canvas.width, canvas.height);
+ + + +

{{EmbedLiveSample("Third_demo", "610", "310")}}

+ +

Afegir control al ratolí

+ +

Per tenir una mica de control sobre la bola, podem fer que segueixi al ratolí usant l'esdeveniment mousemove, per exemple. L'esdeveniment click allibera la bola i la deixa rebotar de nou.

+ + + +
var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+var raf;
+var running = false;
+
+var ball = {
+  x: 100,
+  y: 100,
+  vx: 5,
+  vy: 1,
+  radius: 25,
+  color: 'blue',
+  draw: function() {
+    ctx.beginPath();
+    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
+    ctx.closePath();
+    ctx.fillStyle = this.color;
+    ctx.fill();
+  }
+};
+
+function clear() {
+  ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
+  ctx.fillRect(0,0,canvas.width,canvas.height);
+}
+
+function draw() {
+  clear();
+  ball.draw();
+  ball.x += ball.vx;
+  ball.y += ball.vy;
+
+  if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
+    ball.vy = -ball.vy;
+  }
+  if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
+    ball.vx = -ball.vx;
+  }
+
+  raf = window.requestAnimationFrame(draw);
+}
+
+canvas.addEventListener('mousemove', function(e) {
+  if (!running) {
+    clear();
+    ball.x = e.clientX;
+    ball.y = e.clientY;
+    ball.draw();
+  }
+});
+
+canvas.addEventListener('click', function(e) {
+  if (!running) {
+    raf = window.requestAnimationFrame(draw);
+    running = true;
+  }
+});
+
+canvas.addEventListener('mouseout', function(e) {
+  window.cancelAnimationFrame(raf);
+  running = false;
+});
+
+ball.draw();
+
+ +

Moure la bola amb el ratolí i allibera-la amb un clic.

+ +

{{EmbedLiveSample("Adding_mouse_control", "610", "310")}}

+ +

Escapada

+ +

Aquest breu capítol només explica algunes tècniques per crear animacions més avançades. Hi ha molts més! Què tal afegir una paleta, alguns maons, i convertir aquesta demostració en un joc Escapada? Consulta la nostra àrea de desenvolupament de jocs per veure més articles relacionats amb els jocs.

+ +

Vegeu també

+ + + +

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

diff --git "a/files/ca/web/api/canvas_api/tutorial/animacions_avan\303\247ades/index.html" "b/files/ca/web/api/canvas_api/tutorial/animacions_avan\303\247ades/index.html" deleted file mode 100644 index 4aebb46529..0000000000 --- "a/files/ca/web/api/canvas_api/tutorial/animacions_avan\303\247ades/index.html" +++ /dev/null @@ -1,380 +0,0 @@ ---- -title: Animacions avançades -slug: Web/API/Canvas_API/Tutorial/Animacions_avançades -tags: - - Canvas - - Graphics - - Tutorial -translation_of: Web/API/Canvas_API/Tutorial/Advanced_animations ---- -
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_animations", "Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas")}}
- -
-

En l'últim capítol vam fer algunes animacions bàsiques i vam conèixer maneres de fer moure les coses. En aquesta part veurem més d'a prop el moviment en si i afegirem una mica de física per fer que les nostres animacions siguin més avançades.

-
- -

Dibuixar una bola

- -

Usarem una bola per als nostres estudis d'animació, així que primer dibuixarem aquesta bola sobre el llenç. El següent codi ens configurarà.

- -
<canvas id="canvas" width="600" height="300"></canvas>
-
- -

Com és habitual, primer necessitem un context de dibuix. Per dibuixar la bola, hem crear un objecte ball que contingui propietats i un mètode draw() per pintar-la sobre el llenç.

- -
var canvas = document.getElementById('canvas');
-var ctx = canvas.getContext('2d');
-
-var ball = {
-  x: 100,
-  y: 100,
-  radius: 25,
-  color: 'blue',
-  draw: function() {
-    ctx.beginPath();
-    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
-    ctx.closePath();
-    ctx.fillStyle = this.color;
-    ctx.fill();
-  }
-};
-
-ball.draw();
- -

Aquí no hi ha res especial, la bola és en realitat un cercle senzill i es dibuixa amb l'ajuda del mètode {{domxref("CanvasRenderingContext2D.arc()", "arc()")}}.

- -

Afegir velocitat

- -

Ara que tenim la bola, estem preparats per afegir una animació bàsica tal com hem après en l'últim capítol d'aquest tutorial. Novament, {{domxref("window.requestAnimationFrame()")}} ens ajuda a controlar l'animació. La bola es mou en afegir un vector de velocitat a la posició. Per a cada fotograma, també {{domxref("CanvasRenderingContext2D.clearRect", "clear", "", 1)}} el llenç per eliminar cercles antics de fotogrames anteriors.

- -
var canvas = document.getElementById('canvas');
-var ctx = canvas.getContext('2d');
-var raf;
-
-var ball = {
-  x: 100,
-  y: 100,
-  vx: 5,
-  vy: 2,
-  radius: 25,
-  color: 'blue',
-  draw: function() {
-    ctx.beginPath();
-    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
-    ctx.closePath();
-    ctx.fillStyle = this.color;
-    ctx.fill();
-  }
-};
-
-function draw() {
-  ctx.clearRect(0,0, canvas.width, canvas.height);
-  ball.draw();
-  ball.x += ball.vx;
-  ball.y += ball.vy;
-  raf = window.requestAnimationFrame(draw);
-}
-
-canvas.addEventListener('mouseover', function(e) {
-  raf = window.requestAnimationFrame(draw);
-});
-
-canvas.addEventListener('mouseout', function(e) {
-  window.cancelAnimationFrame(raf);
-});
-
-ball.draw();
-
- -

Límits

- -

Sense cap prova de col·lisió de límits, la nostra bola surt ràpidament del llenç. Hem de comprovar si la posició x i y de la bola està fora de les dimensions del llenç i invertir la direcció dels vectors de velocitat. Per fer-ho, afegim les següents comprovacions al mètode draw:

- -
if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
-  ball.vy = -ball.vy;
-}
-if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
-  ball.vx = -ball.vx;
-}
- -

Primera demostració

- -

Vegem com es veu en acció fins ara. Movem el ratolí en el llenç per iniciar l'animació.

- - - -

{{EmbedLiveSample("First_demo", "610", "310")}}

- -

Acceleració

- -

Per fer el moviment més real, es pots jugar amb la velocitat d'aquesta manera, per exemple:

- -
ball.vy *= .99;
-ball.vy += .25;
- -

Això retarda la velocitat vertical de cada fotograma, de manera que la bola només rebotarà en el sòl al final.

- - - -

{{EmbedLiveSample("Second_demo", "610", "310")}}

- -

Efecte cua

- -

Fins ara, hem utilitzat el mètode {{domxref("CanvasRenderingContext2D.clearRect", "clearRect")}} per esborrar fotogrames anteriors. Si reemplacem aquest mètode per un semi-transparent {{domxref("CanvasRenderingContext2D.fillRect", "fillRect")}}, es pot crear fàcilment un efecte cua.

- -
ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
-ctx.fillRect(0, 0, canvas.width, canvas.height);
- - - -

{{EmbedLiveSample("Third_demo", "610", "310")}}

- -

Afegir control al ratolí

- -

Per tenir una mica de control sobre la bola, podem fer que segueixi al ratolí usant l'esdeveniment mousemove, per exemple. L'esdeveniment click allibera la bola i la deixa rebotar de nou.

- - - -
var canvas = document.getElementById('canvas');
-var ctx = canvas.getContext('2d');
-var raf;
-var running = false;
-
-var ball = {
-  x: 100,
-  y: 100,
-  vx: 5,
-  vy: 1,
-  radius: 25,
-  color: 'blue',
-  draw: function() {
-    ctx.beginPath();
-    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
-    ctx.closePath();
-    ctx.fillStyle = this.color;
-    ctx.fill();
-  }
-};
-
-function clear() {
-  ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
-  ctx.fillRect(0,0,canvas.width,canvas.height);
-}
-
-function draw() {
-  clear();
-  ball.draw();
-  ball.x += ball.vx;
-  ball.y += ball.vy;
-
-  if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) {
-    ball.vy = -ball.vy;
-  }
-  if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) {
-    ball.vx = -ball.vx;
-  }
-
-  raf = window.requestAnimationFrame(draw);
-}
-
-canvas.addEventListener('mousemove', function(e) {
-  if (!running) {
-    clear();
-    ball.x = e.clientX;
-    ball.y = e.clientY;
-    ball.draw();
-  }
-});
-
-canvas.addEventListener('click', function(e) {
-  if (!running) {
-    raf = window.requestAnimationFrame(draw);
-    running = true;
-  }
-});
-
-canvas.addEventListener('mouseout', function(e) {
-  window.cancelAnimationFrame(raf);
-  running = false;
-});
-
-ball.draw();
-
- -

Moure la bola amb el ratolí i allibera-la amb un clic.

- -

{{EmbedLiveSample("Adding_mouse_control", "610", "310")}}

- -

Escapada

- -

Aquest breu capítol només explica algunes tècniques per crear animacions més avançades. Hi ha molts més! Què tal afegir una paleta, alguns maons, i convertir aquesta demostració en un joc Escapada? Consulta la nostra àrea de desenvolupament de jocs per veure més articles relacionats amb els jocs.

- -

Vegeu també

- - - -

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

diff --git "a/files/ca/web/api/canvas_api/tutorial/animacions_b\303\240siques/index.html" "b/files/ca/web/api/canvas_api/tutorial/animacions_b\303\240siques/index.html" deleted file mode 100644 index e4a3751d1e..0000000000 --- "a/files/ca/web/api/canvas_api/tutorial/animacions_b\303\240siques/index.html" +++ /dev/null @@ -1,335 +0,0 @@ ---- -title: Animacions bàsiques -slug: Web/API/Canvas_API/Tutorial/Animacions_bàsiques -tags: - - Canvas - - Graphics - - HTML - - HTML5 - - Intermediate - - Tutorial -translation_of: Web/API/Canvas_API/Tutorial/Basic_animations ---- -
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Compositing", "Web/API/Canvas_API/Tutorial/Advanced_animations")}}
- -
-

Atès que estem usant Javascript per controlar els elements {{HTMLElement("canvas")}}, també és molt fàcil fer animacions (interactives). En aquest capítol veurem com fer algunes animacions bàsiques.

-
- -

Probablement, la major limitació és que, una vegada que es dibuixa una forma, aquesta es manté així. Si necessitem moure-la, hem de tornar a dibuixar-la i tot el que s'ha dibuixat abans. Es necessita molt temps per tornar a dibuixar quadres complexos i el rendiment depèn en gran manera de la velocitat de l'equip en el qual s'està executant.

- -

Passos bàsics d'animació

- -

Aquests són els passos que s'han de seguir per dibuixar un marc:

- -
    -
  1. Esborrar el llenç
    - A menys que les formes que es dibuixin omplin el llenç complet (per exemple, una imatge de fons), és necessari esborrar qualsevol forma que s'hi hagi dibuixat prèviament. La manera més fàcil de fer-ho, és usant el mètode {{domxref("CanvasRenderingContext2D.clearRect", "clearRect()")}}.
  2. -
  3. Guardar l'estat del llenç
    - Si es canvia qualsevol configuració (com ara estils, transformacions, etc.) que afectin a l'estat del llenç i ens volem assegurar que l'estat original s'utilitza cada vegada que es dibuixa un marc, hem de guardar aquest estat original.
  4. -
  5. Dibuixar formes animades
    - El pas on es fa la representació del marc real.
  6. -
  7. Restaurar l'estat del llenç
    - Si s'ha guardat l'estat, ho hem de restaurar abans de dibuixar un nou marc.
  8. -
- -

Controlar una animació

- -

Les formes es dibuixen al llenç usant els mètodes de canvas directament o cridant a les funcions personalitzades. En circumstàncies normals, només veiem que aquests resultats apareixen en el llenç quan el script acaba d'executar-se. Per exemple, no és possible fer una animació des d'un bucle for.

- -

Això significa que necessitem una forma d'executar les nostres funcions de dibuix durant un període de temps. Hi ha dues maneres de controlar una animació com aquesta.

- -

Actualitzacions programades

- -

Primer estan les funcions {{domxref("window.setInterval()")}}, {{domxref("window.setTimeout()")}} i {{domxref("window.requestAnimationFrame()")}}, que es poden utilitzar per cridar a una funció específica durant un període de temps determinat.

- -
-
{{domxref("WindowTimers.setInterval", "setInterval(function, delay)")}}
-
Inicia repetidament l'execució de la funció especificada per la funció, cada mil·lisegons de retard.
-
{{domxref("WindowTimers.setTimeout", "setTimeout(function, delay)")}}
-
Executa la funció especificada per la function en mil·lisegons de delay.
-
{{domxref("Window.requestAnimationFrame()", "requestAnimationFrame(callback)")}}
-
Li diu al navegador que desitja realitzar una animació i sol·licita al navegador que cridi a una funció especifica per actualitzar una animació abans del proper repintat.
-
- -

Si no es vol cap interacció amb l'usuari, es pot utilitzar la funció setInterval() que executa repetidament el codi proporcionat. Si volguéssim fer un joc, podríem usar esdeveniments de teclat o ratolí per controlar l'animació i usar setTimeout(). En establir {{domxref("EventListener")}}s, capturem qualsevol interacció de l'usuari i s'executan les nostres funcions d'animació

- -
-

En els exemples següents, utilitzarem el mètode {{domxref("window.requestAnimationFrame()")}} per controlar l'animació. El mètode requestAnimationFrame proporciona una manera fluïda i eficient per a l'animació, cridant al marc d'animació quan el sistema estigui preparat per pintar el marc. El nombre de crides retornades és generalment 60 vegades per segon i pot reduir-se a una taxa més baixa quan s'executa en les pestanyes de fons. Per a més informació sobre el bucle d'animació, especialment per a jocs, veure l'article Anatomia d'un videojoc en la nostra Zona de desenvolupament de jocs.

-
- -

Un sistema solar animat

- -

Aquest exemple anima un petit model del nostre sistema solar.

- -
var sun = new Image();
-var moon = new Image();
-var earth = new Image();
-function init() {
-  sun.src = 'https://mdn.mozillademos.org/files/1456/Canvas_sun.png';
-  moon.src = 'https://mdn.mozillademos.org/files/1443/Canvas_moon.png';
-  earth.src = 'https://mdn.mozillademos.org/files/1429/Canvas_earth.png';
-  window.requestAnimationFrame(draw);
-}
-
-function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-
-  ctx.globalCompositeOperation = 'destination-over';
-  ctx.clearRect(0, 0, 300, 300); // clear canvas
-
-  ctx.fillStyle = 'rgba(0, 0, 0, 0.4)';
-  ctx.strokeStyle = 'rgba(0, 153, 255, 0.4)';
-  ctx.save();
-  ctx.translate(150, 150);
-
-  // Earth
-  var time = new Date();
-  ctx.rotate(((2 * Math.PI) / 60) * time.getSeconds() + ((2 * Math.PI) / 60000) * time.getMilliseconds());
-  ctx.translate(105, 0);
-  ctx.fillRect(0, -12, 50, 24); // Shadow
-  ctx.drawImage(earth, -12, -12);
-
-  // Moon
-  ctx.save();
-  ctx.rotate(((2 * Math.PI) / 6) * time.getSeconds() + ((2 * Math.PI) / 6000) * time.getMilliseconds());
-  ctx.translate(0, 28.5);
-  ctx.drawImage(moon, -3.5, -3.5);
-  ctx.restore();
-
-  ctx.restore();
-
-  ctx.beginPath();
-  ctx.arc(150, 150, 105, 0, Math.PI * 2, false); // Earth orbit
-  ctx.stroke();
-
-  ctx.drawImage(sun, 0, 0, 300, 300);
-
-  window.requestAnimationFrame(draw);
-}
-
-init();
-
- - - -

{{EmbedLiveSample("An_animated_solar_system", "310", "310", "https://mdn.mozillademos.org/files/202/Canvas_animation1.png")}}

- -

Un rellotge animat

- -

Aquest exemple dibuixa un rellotge animat que mostra l'hora actual.

- -
function clock() {
-  var now = new Date();
-  var ctx = document.getElementById('canvas').getContext('2d');
-  ctx.save();
-  ctx.clearRect(0, 0, 150, 150);
-  ctx.translate(75, 75);
-  ctx.scale(0.4, 0.4);
-  ctx.rotate(-Math.PI / 2);
-  ctx.strokeStyle = 'black';
-  ctx.fillStyle = 'white';
-  ctx.lineWidth = 8;
-  ctx.lineCap = 'round';
-
-  // Hour marks
-  ctx.save();
-  for (var i = 0; i < 12; i++) {
-    ctx.beginPath();
-    ctx.rotate(Math.PI / 6);
-    ctx.moveTo(100, 0);
-    ctx.lineTo(120, 0);
-    ctx.stroke();
-  }
-  ctx.restore();
-
-  // Minute marks
-  ctx.save();
-  ctx.lineWidth = 5;
-  for (i = 0; i < 60; i++) {
-    if (i % 5!= 0) {
-      ctx.beginPath();
-      ctx.moveTo(117, 0);
-      ctx.lineTo(120, 0);
-      ctx.stroke();
-    }
-    ctx.rotate(Math.PI / 30);
-  }
-  ctx.restore();
-
-  var sec = now.getSeconds();
-  var min = now.getMinutes();
-  var hr  = now.getHours();
-  hr = hr >= 12 ? hr - 12 : hr;
-
-  ctx.fillStyle = 'black';
-
-  // write Hours
-  ctx.save();
-  ctx.rotate(hr * (Math.PI / 6) + (Math.PI / 360) * min + (Math.PI / 21600) *sec);
-  ctx.lineWidth = 14;
-  ctx.beginPath();
-  ctx.moveTo(-20, 0);
-  ctx.lineTo(80, 0);
-  ctx.stroke();
-  ctx.restore();
-
-  // write Minutes
-  ctx.save();
-  ctx.rotate((Math.PI / 30) * min + (Math.PI / 1800) * sec);
-  ctx.lineWidth = 10;
-  ctx.beginPath();
-  ctx.moveTo(-28, 0);
-  ctx.lineTo(112, 0);
-  ctx.stroke();
-  ctx.restore();
-
-  // Write seconds
-  ctx.save();
-  ctx.rotate(sec * Math.PI / 30);
-  ctx.strokeStyle = '#D40000';
-  ctx.fillStyle = '#D40000';
-  ctx.lineWidth = 6;
-  ctx.beginPath();
-  ctx.moveTo(-30, 0);
-  ctx.lineTo(83, 0);
-  ctx.stroke();
-  ctx.beginPath();
-  ctx.arc(0, 0, 10, 0, Math.PI * 2, true);
-  ctx.fill();
-  ctx.beginPath();
-  ctx.arc(95, 0, 10, 0, Math.PI * 2, true);
-  ctx.stroke();
-  ctx.fillStyle = 'rgba(0, 0, 0, 0)';
-  ctx.arc(0, 0, 3, 0, Math.PI * 2, true);
-  ctx.fill();
-  ctx.restore();
-
-  ctx.beginPath();
-  ctx.lineWidth = 14;
-  ctx.strokeStyle = '#325FA2';
-  ctx.arc(0, 0, 142, 0, Math.PI * 2, true);
-  ctx.stroke();
-
-  ctx.restore();
-
-  window.requestAnimationFrame(clock);
-}
-
-window.requestAnimationFrame(clock);
- - - -

{{EmbedLiveSample("An_animated_clock", "180", "180", "https://mdn.mozillademos.org/files/203/Canvas_animation2.png")}}

- -

Un panorama en bucle

- -

En aquest exemple, es desplaça una imatge panoràmica d'esquerra a dreta. Estem usant una imatge del Parc Nacional Yosemite, que hem pres de Wikipedia, però es pot usar qualsevol imatge que sigui més gran que el llenç.

- -
var img = new Image();
-
-// User Variables - customize these to change the image being scrolled, its
-// direction, and the speed.
-
-img.src = 'https://mdn.mozillademos.org/files/4553/Capitan_Meadows,_Yosemite_National_Park.jpg';
-var CanvasXSize = 800;
-var CanvasYSize = 200;
-var speed = 30; // lower is faster
-var scale = 1.05;
-var y = -4.5; // vertical offset
-
-// Main program
-
-var dx = 0.75;
-var imgW;
-var imgH;
-var x = 0;
-var clearX;
-var clearY;
-var ctx;
-
-img.onload = function() {
-    imgW = img.width * scale;
-    imgH = img.height * scale;
-
-    if (imgW > CanvasXSize) {
-        // image larger than canvas
-        x = CanvasXSize - imgW;
-    }
-    if (imgW > CanvasXSize) {
-        // image width larger than canvas
-        clearX = imgW;
-    } else {
-        clearX = CanvasXSize;
-    }
-    if (imgH > CanvasYSize) {
-        // image height larger than canvas
-        clearY = imgH;
-    } else {
-        clearY = CanvasYSize;
-    }
-
-    // get canvas context
-    ctx = document.getElementById('canvas').getContext('2d');
-
-    // set refresh rate
-    return setInterval(draw, speed);
-}
-
-function draw() {
-    ctx.clearRect(0, 0, clearX, clearY); // clear the canvas
-
-    // if image is <= Canvas Size
-    if (imgW <= CanvasXSize) {
-        // reset, start from beginning
-        if (x > CanvasXSize) {
-            x = -imgW + x;
-        }
-        // draw additional image1
-        if (x > 0) {
-            ctx.drawImage(img, -imgW + x, y, imgW, imgH);
-        }
-        // draw additional image2
-        if (x - imgW > 0) {
-            ctx.drawImage(img, -imgW * 2 + x, y, imgW, imgH);
-        }
-    }
-
-    // image is > Canvas Size
-    else {
-        // reset, start from beginning
-        if (x > (CanvasXSize)) {
-            x = CanvasXSize - imgW;
-        }
-        // draw aditional image
-        if (x > (CanvasXSize-imgW)) {
-            ctx.drawImage(img, x - imgW + 1, y, imgW, imgH);
-        }
-    }
-    // draw image
-    ctx.drawImage(img, x, y,imgW, imgH);
-    // amount to move
-    x += dx;
-}
-
- -

A continuació un {{HTMLElement("canvas")}} en què es desplaça la imatge. Hem de tenir en compte que l'amplada i l'alçada especificades aquí, han de coincidir amb els valors de les variables CanvasXZSize i CanvasYSize en el codi JavaScript.

- -
<canvas id="canvas" width="800" height="200"></canvas>
- -

{{EmbedLiveSample("A_looping_panorama", "830", "230")}}

- -

Altres exemples

- -
-
Una roda de raigs bàsica
-
Un bon exemple de com fer animacions usant els controls del teclat.
-
Animacions avançades
-
En el proper capítol veurem algunes tècniques avançades d'animació i física.
-
- -

{{PreviousNext("Web/API/Canvas_API/Tutorial/Compositing", "Web/API/Canvas_API/Tutorial/Advanced_animations")}}

diff --git a/files/ca/web/api/canvas_api/tutorial/aplicar_estils_i_colors/index.html b/files/ca/web/api/canvas_api/tutorial/aplicar_estils_i_colors/index.html deleted file mode 100644 index 9adcc2d5f4..0000000000 --- a/files/ca/web/api/canvas_api/tutorial/aplicar_estils_i_colors/index.html +++ /dev/null @@ -1,733 +0,0 @@ ---- -title: Aplicar estils i colors -slug: Web/API/Canvas_API/Tutorial/Aplicar_estils_i_colors -tags: - - Canvas - - Graphics - - HTML - - HTML5 - - Intermediate - - Tutorial -translation_of: Web/API/Canvas_API/Tutorial/Applying_styles_and_colors ---- -
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Drawing_shapes", "Web/API/Canvas_API/Tutorial/Drawing_text")}}
- -
-

En el capítol sobre dibuixar formes, hem utilitzat només els estils de línia i de farciment predeterminats. Aquí explorarem les opcions de canvas que tenim a la nostra disposició per fer els nostres dibuixos una mica més atractius. Aprendreu com afegir diferents colors, estils de línies, gradients, patrons i ombres als vostres dibuixos.

-
- -

Colors

- -

Fins ara només hem vist mètodes del context de dibuix. Si volem aplicar colors a una forma, hi ha dues propietats importants que podem utilitzar: fillStyle i strokeStyle.

- -
-
{{domxref("CanvasRenderingContext2D.fillStyle", "fillStyle = color")}}
-
Estableix l'estil utilitzat per emplenar formes.
-
{{domxref("CanvasRenderingContext2D.strokeStyle", "strokeStyle = color")}}
-
Estableix l'estil per als contorns de les formes.
-
- -

color és una cadena que representa un {{cssxref("<color>")}} CSS, un objecte degradat o un objecte patró. Veurem els objectes de degradat i patró més endavant. Per defecte, el traç i el color del farciment estan establerts en negre (valor de color CSS #000000).

- -
-

Nota: Quan es defineix la propietat strokeStyle i/o fillStyle, el nou valor es converteix en el valor predeterminat per a totes les formes que s'estan dibuixant a partir d'aquest moment. Per a cada forma que desitgeu en un color diferent, haureu de tornar a assignar la propietat fillStyle o strokeStyle.

-
- -

Les cadenes vàlides que podeu introduir han de ser, segons l'especificació, valors de {{cssxref("<color>")}} CSS. Cadascun dels següents exemples descriu el mateix color.

- -
// these all set the fillStyle to 'orange'
-
-ctx.fillStyle = 'orange';
-ctx.fillStyle = '#FFA500';
-ctx.fillStyle = 'rgb(255, 165, 0)';
-ctx.fillStyle = 'rgba(255, 165, 0, 1)';
-
- -

Un exemple de fillStyle

- -

En aquest exemple, una vegada més, usem dos bucles for per dibuixar una graella de rectangles, cadascun en un color diferent. La imatge resultant hauria de ser similar a la captura de pantalla. Aquí no succeeix res espectacular. Utilitzem les dues variables i i j per generar un color RGB únic per a cada quadrat, i només modifiquen els valors vermell i verd. El canal blau té un valor fix. Modificant els canals, es poden generar tot tipus de paletes. En augmentar els passos, es pot aconseguir alguna cosa que se sembli a les paletes de color que utilitza Photoshop.

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-  for (var i = 0; i < 6; i++) {
-    for (var j = 0; j < 6; j++) {
-      ctx.fillStyle = 'rgb(' + Math.floor(255 - 42.5 * i) + ', ' +
-                       Math.floor(255 - 42.5 * j) + ', 0)';
-      ctx.fillRect(j * 25, i * 25, 25, 25);
-    }
-  }
-}
- - - -

The result looks like this:

- -

{{EmbedLiveSample("A_fillStyle_example", 160, 160, "https://mdn.mozillademos.org/files/5417/Canvas_fillstyle.png")}}

- -

Un exemple de strokeStyle

- -

Aquest exemple és similar a l'anterior, però usa la propietat strokeStyle per canviar els colors dels contorns de les formes. Usem el mètode arc() per dibuixar cercles en lloc de quadrats.

- -
  function draw() {
-    var ctx = document.getElementById('canvas').getContext('2d');
-    for (var i = 0; i < 6; i++) {
-      for (var j = 0; j < 6; j++) {
-        ctx.strokeStyle = 'rgb(0, ' + Math.floor(255 - 42.5 * i) + ', ' +
-                         Math.floor(255 - 42.5 * j) + ')';
-        ctx.beginPath();
-        ctx.arc(12.5 + j * 25, 12.5 + i * 25, 10, 0, Math.PI * 2, true);
-        ctx.stroke();
-      }
-    }
-  }
-
- - - -

El resultat és així:

- -

{{EmbedLiveSample("A_strokeStyle_example", "180", "180", "https://mdn.mozillademos.org/files/253/Canvas_strokestyle.png")}}

- -

Transparència

- -

A més de dibuixar formes opaques al llenç, també podem dibuixar formes semitransparents (o translúcides). Això es fa, ja sigui configurant la propietat globalAlpha o assignant un color semitransparent a l'estil de traç i/o d'ompliment.

- -
-
{{domxref("CanvasRenderingContext2D.globalAlpha", "globalAlpha = transparencyValue")}}
-
Aplica el valor de transparència especificat a totes les formes futures dibuixades en el llenç. El valor ha d'estar entre 0,0 (totalment transparent) a 1.0 (totalment opac). Aquest valor és 1.0 (totalment opac) per defecte.
-
- -

La propietat globalAlpha pot ser útil si voleu dibuixar moltes formes al llenç amb una transparència similar, però en general, és més útil establir la transparència en formes individuals quan establiu els seus colors.

- -

Atès que les propietats strokeStyle and fillStyle accepten valors de color CSS rgba, podem utilitzar la notació següent per assignar un color transparent a ells.

- -
// Assignar colors transparents a l'estil de traç i ompliment
-
-ctx.strokeStyle = 'rgba(255, 0, 0, 0.5)';
-ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
-
- -

La funció rgba() és similar a la funció rgb() però té un paràmetre addicional. L'últim paràmetre estableix el valor de transparència d'aquest color en particular. El rang vàlid se situa de nou entre 0.0 (totalment transparent) i 1.0 (completament opac).

- -

Un exemple de globalAlpha

- -

En aquest exemple, dibuixarem un fons de quatre quadrats de colors diferents. A més d'això, dibuixarem un conjunt de cercles semitransparents. La propietat globalAlpha s'estableix en 0.2 que s'utilitzarà per a totes les formes des d'aquest punt. Cada pas en el bucle for dibuixa un conjunt de cercles amb un radi creixent. El resultat final és un gradient radial. En superposar cada vegada més cercles un damunt de l'altre, reduïm efectivament la transparència dels cercles que ja s'han dibuixat. En augmentar el recompte de passos i, en efecte, dibuixar més cercles, el fons desapareixeria completament del centre de la imatge.

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-  // draw background
-  ctx.fillStyle = '#FD0';
-  ctx.fillRect(0, 0, 75, 75);
-  ctx.fillStyle = '#6C0';
-  ctx.fillRect(75, 0, 75, 75);
-  ctx.fillStyle = '#09F';
-  ctx.fillRect(0, 75, 75, 75);
-  ctx.fillStyle = '#F30';
-  ctx.fillRect(75, 75, 75, 75);
-  ctx.fillStyle = '#FFF';
-
-  // set transparency value
-  ctx.globalAlpha = 0.2;
-
-  // Draw semi transparent circles
-  for (i = 0; i < 7; i++) {
-    ctx.beginPath();
-    ctx.arc(75, 75, 10 + 10 * i, 0, Math.PI * 2, true);
-    ctx.fill();
-  }
-}
- - - -

{{EmbedLiveSample("A_globalAlpha_example", "180", "180", "https://mdn.mozillademos.org/files/232/Canvas_globalalpha.png")}}

- -

Un exemple usant rgba()

- -

En aquest segon exemple, fem alguna cosa semblant a l'anterior, però en comptes de dibuixar cercles un damunt de l'altre, dibuixem petits rectangles amb opacitat creixent. L'ús de rgba() dóna una mica més de control i flexibilitat, perquè podem definir l'estil d'emplenament i traç individualment.

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-
-  // Draw background
-  ctx.fillStyle = 'rgb(255, 221, 0)';
-  ctx.fillRect(0, 0, 150, 37.5);
-  ctx.fillStyle = 'rgb(102, 204, 0)';
-  ctx.fillRect(0, 37.5, 150, 37.5);
-  ctx.fillStyle = 'rgb(0, 153, 255)';
-  ctx.fillRect(0, 75, 150, 37.5);
-  ctx.fillStyle = 'rgb(255, 51, 0)';
-  ctx.fillRect(0, 112.5, 150, 37.5);
-
-  // Draw semi transparent rectangles
-  for (var i = 0; i < 10; i++) {
-    ctx.fillStyle = 'rgba(255, 255, 255, ' + (i + 1) / 10 + ')';
-    for (var j = 0; j < 4; j++) {
-      ctx.fillRect(5 + i * 14, 5 + j * 37.5, 14, 27.5);
-    }
-  }
-}
- - - -

{{EmbedLiveSample("An_example_using_rgba()", "180", "180", "https://mdn.mozillademos.org/files/246/Canvas_rgba.png")}}

- -

Estils de línia

- -

Hi ha diverses propietats que ens permeten donar estil a les línies.

- -
-
{{domxref("CanvasRenderingContext2D.lineWidth", "lineWidth = value")}}
-
Estableix l'amplària de les línies dibuixades en el futur.
-
{{domxref("CanvasRenderingContext2D.lineCap", "lineCap = type")}}
-
Estableix l'aparença dels extrems de les línies.
-
{{domxref("CanvasRenderingContext2D.lineJoin", "lineJoin = type")}}
-
Estableix l'aparença de les "cantonades" on s'uneixen les línies.
-
{{domxref("CanvasRenderingContext2D.miterLimit", "miterLimit = value")}}
-
Estableix un límit en la mitra, quan dues línies s'uneixen en un angle agut, per permetre-li controlar el grossor de la unió.
-
{{domxref("CanvasRenderingContext2D.getLineDash", "getLineDash()")}}
-
Retorna la matriu de patró de guió de la línia actual que conté un nombre parell de nombres no negatius.
-
{{domxref("CanvasRenderingContext2D.setLineDash", "setLineDash(segments)")}}
-
Estableix el patró de guió de línia actual.
-
{{domxref("CanvasRenderingContext2D.lineDashOffset", "lineDashOffset = value")}}
-
Especifica on iniciar una matriu de guions en una línia.
-
- -

Obtindreu una millor comprensió del que fan, en mirar els exemples a continuació.

- -

Un exemple de lineWidth

- -

Aquesta propietat estableix el gruix de la línia actual. Els valors han de ser nombres positius. Per defecte, aquest valor es fixa en 1.0 unitats.

- -

L'amplada de la línia és el gruix del traç centrat en la trajectòria indicada. En altres paraules, l'àrea que es dibuixa s'estén a la meitat de l'amplària de línia a cada costat de la trajectòria. Com que les coordenades del llenç no fan referència directa als píxels, s'ha de tenir especial cura per obtenir línies horitzontals i verticals nítides.

- -

En el següent exemple, es dibuixen 10 línies rectes amb amplades de línia creixents. La línia en l'extrem esquerre té 1.0 unitats d'ample. No obstant això, les línies de grossor més a l'esquerra i totes les altres d'ample imparell no apareixen nítides a causa del posicionament de la trajectòria.

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-  for (var i = 0; i < 10; i++) {
-    ctx.lineWidth = 1 + i;
-    ctx.beginPath();
-    ctx.moveTo(5 + i * 14, 5);
-    ctx.lineTo(5 + i * 14, 140);
-    ctx.stroke();
-  }
-}
-
- - - -

{{EmbedLiveSample("A_lineWidth_example", "180", "180", "https://mdn.mozillademos.org/files/239/Canvas_linewidth.png")}}

- -

L'obtenció de línies nítides requereix entendre com es tracen les trajectòries. En les imatges següents, la graella representa la graella de coordenades del llenç. Els quadrats entre les línies de la graella són píxels reals en pantalla. En la primera imatge de graella que apareix a continuació, s'emplena un rectangle de (2,1) a (5,5). Tota l'àrea entre ells (vermell clar) cau en els límits de píxels, per la qual cosa el rectangle emplenat resultant tindrà vores nítides.

- -

- -

Si es considera una trajectòria de (3,1) a (3,5) amb un gruix de línia  1.0, s'acaba amb la situació en la segona imatge. L'àrea real a emplenar (blau fosc) només s'estén fins a la meitat dels píxels a cada costat de la trajectòria. S'ha de representar una aproximació d'això, la qual cosa significa que aquests píxels estan ombrejats parcialment, i dóna com a resultat que tota l'àrea (blau clar i blau fosc) s'ompli amb un color la meitat de fosc que el color de traç real. Això és el que succeeix amb la línia d'ample 1.0 en el codi d'exemple anterior .

- -

Per arreglar això, s'ha de ser molt precís en la creació de la trajectòria. Sabent que una línia a 1.0 d'ample s'estendrà mitja unitat a cada costat de la trajectòria, creant la trajectòria de (3.5,1) a (3.5,5) resulta que la situació, en la tercera imatge, la línia d'ample 1.0 acaba completa i omplint, precisament, una sola línia vertical de píxels.

- -
-

Nota: Hem de tenir en compte que en el nostre exemple de línia vertical, la posició Y encara fa referència a una posició sencera de la graella; si no fos així, veuríem píxels amb una cobertura parcial en els punts finals (però també, hem de tenir en compte que aquest comportament depèn de l'estil actual de lineCap, el valor predeterminat del qual és butt; és possible que desitgem calcular traços uniformes amb coordenades de mig píxel per a línies d'ample imparell, establint l'estil lineCap a estil square, de manera que el límit exterior del traç al voltant del punt final s'ampliï automàticament per cobrir tot el píxel exactament).

- -

Tinguem en compte, també, que només es veuran afectats els extrems d'inici i fi d'una trajectòria: si es tanca una trajectòria amb closePath(), no hi ha un punt d'inici i final; en el seu lloc, tots els extrems de la trajectòria es connecten al segment anterior i següent utilitzant, la configuració actual de l'estil lineJoin, el valor predeterminat del qual és miter, amb l'efecte d'estendre automàticament els límits exteriors dels segments connectats al seu punt d'intersecció, de manera que el traç representat cobreixi exactament els píxels complets centrats en cada punt final, si aquests segments connectats són horitzontals i/o verticals). Vegeu les dues seccions següents per a les demostracions d'aquests estils de línia addicionals..

-
- -

Per a les línies d'ample parell, cada meitat acaba sent una quantitat sencera de píxels, per la qual cosa es desitjable una trajectòria que estigui entre els píxels (és a dir, (3,1) a (3,5)), en lloc de baixar per la mitad dels píxels

- -

Tot i que és lleugerament dolorós quan inicialment es treballa amb gràfics 2D escalables, si ens fixem en la graella de píxels i la posició de les trajectòries, ens hem d'assegurar que els dibuixos es vegin correctes, independentment de l'escalat o qualsevol altra transformació. Una línia vertical de 1.0 d'ample dibuixada en la posició correcta, es convertirà en una línia nítida de 2 píxels quan s'ampliï per 2, i apareixerà en la posició correcta.

- -

Un exemple de lineCap

- -

La propietat lineCap determina com es dibuixen els punts finals de cada línia. Hi ha tres valors possibles per a aquesta propietat i aquests són: butt, round i square. Per defecte, aquesta propietat està configurada com a butt.

- -

- -
-
butt
-
Els extrems de les línies es quadren en els punts finals.
-
round
-
Els extrems de les línies són arrodonits.
-
square
-
Els extrems de les línies es quadren en afegir una caixa amb un ample igual i la meitat de l'alçada del gruix de la línia.
-
- -

En aquest exemple, dibuixarem tres línies, cadascuna amb un valor diferent per a la propietat lineCap. També afegim dues guies per veure les diferències exactes entre les tres. Cadascuna d'aquestes línies comença i acaba exactament en aquestes guies.

- -

La línia de l'esquerra utilitza l'opció predeterminada butt. Notarem que està dibuixada completament al ras amb les guies. La segona s'estableix, utilitzant l'opció round. Això afegeix un semicercle al extrem que té un radi de la meitat de l'ample de la línia. La línia de la dreta utilitza l'opció square. Això afegeix una caixa amb un ample igual i la meitat de l'alçada del gruix de la línia.

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-  var lineCap = ['butt', 'round', 'square'];
-
-  // Draw guides
-  ctx.strokeStyle = '#09f';
-  ctx.beginPath();
-  ctx.moveTo(10, 10);
-  ctx.lineTo(140, 10);
-  ctx.moveTo(10, 140);
-  ctx.lineTo(140, 140);
-  ctx.stroke();
-
-  // Draw lines
-  ctx.strokeStyle = 'black';
-  for (var i = 0; i < lineCap.length; i++) {
-    ctx.lineWidth = 15;
-    ctx.lineCap = lineCap[i];
-    ctx.beginPath();
-    ctx.moveTo(25 + i * 50, 10);
-    ctx.lineTo(25 + i * 50, 140);
-    ctx.stroke();
-  }
-}
-
- - - -

{{EmbedLiveSample("A_lineCap_example", "180", "180", "https://mdn.mozillademos.org/files/236/Canvas_linecap.png")}}

- -

Un exemple de lineJoin

- -

La propietat lineJoin determina com s'uneixen dos segments de connexió (de línies, arcs o corbes) amb longituds diferents de zero en una forma (els segments degenerats amb longituds zero, que els punts finals i punts de control especificats estan exactament en la mateixa posició, s'ometen).

- -

Hi ha tres possibles valors per a aquesta propietat: round, bevel i miter. Per defecte aquesta propietat s'estableix a miter. Hem de tenir en compte que la configuració lineJoin no té cap efecte si els dos segments connectats tenen la mateixa direcció, ja que en aquest cas no s'afegirà cap àrea d'unió.

- -

- -
-
round
-
Arrodoneix les cantonades d'una forma emplenant un sector addicional del disc centrat en el punt final comú dels segments connectats. El radi per a aquestes cantonades arrodonides és igual a la meitat de l'amplada de la línia.
-
bevel
-
Emplena un àrea triangular addicional entre el punt final comú dels segments connectats i les cantonades rectangulars exteriors separades de cada segment..
-
miter
-
Els segments connectats s'uneixen estenent les seves vores exteriors per connectar-se en un sol punt, amb l'efecte d'emplenar un àrea addicional en forma de rombe. Aquest ajust s'efectua mitjançant la propietat miterLimit, que s'explica a continuació.
-
- -

L'exemple següent dibuixa tres trajectòries diferents, demostrant cadascuna d'aquestes tres configuracions de la propietat lineJoin; la sortida es mostra a dalt..

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-  var lineJoin = ['round', 'bevel', 'miter'];
-  ctx.lineWidth = 10;
-  for (var i = 0; i < lineJoin.length; i++) {
-    ctx.lineJoin = lineJoin[i];
-    ctx.beginPath();
-    ctx.moveTo(-5, 5 + i * 40);
-    ctx.lineTo(35, 45 + i * 40);
-    ctx.lineTo(75, 5 + i * 40);
-    ctx.lineTo(115, 45 + i * 40);
-    ctx.lineTo(155, 5 + i * 40);
-    ctx.stroke();
-  }
-}
-
- - - -

{{EmbedLiveSample("A_lineJoin_example", "180", "180", "https://mdn.mozillademos.org/files/237/Canvas_linejoin.png")}}

- -

Una demostració de la propietat miterLimit

- -

Com s'ha vist en l'exemple anterior, en unir dues línies amb l'opció miter, les vores exteriors de les dues línies d'unió s'estenen fins al punt on es troben. En el cas de línies que tenen angles grans entre si, aquest punt no està lluny del punt de connexió interior. No obstant això, a mesura que els angles entre cada línia disminueixen, la distància (longitud de miter) entre aquests punts augmenta exponencialment.

- -

La propietat miterLimit determina quant lluny es pot col·locar el punt de connexió exterior des del punt de connexió interior. Si dues línies excedeixen aquest valor, es dibuixa una unió bisellada. S'ha de tenir en compte que la longitud màxima de miter és el producte de l'amplada de línia mesurat en el sistema de coordenades actual, pel valor d'aquesta propietat miterLimit  (el valor per defecte és 10.0 en HTML {{HTMLElement("canvas")}}), per la qual cosa miterLimit pot ajustar-se independentment de l'escala de visualització actual o de qualsevol transformació afí de les trajectòries: només influeix en la forma efectiva de les vores de la línia representada.

- -

Més exactament, el límit de miter és la proporció màxima permesa de la longitud de l'extensió (en el llenç HTML, es mesura entre la cantonada exterior de les vores unides de la línia i el punt final comú dels segments de connexió especificats en la trajectòria) a la meitat de l'ample de la línia. La seva definició equival a la relació màxima permesa entre la distància dels punts interiors i exteriors de la unió de les vores i l'amplada total de la línia. Llavors, aixó és igual a la cosecant de la meitat de l'angle intern mínim dels segments de connexió per sota dels quals no es representarà cap unió miter, sinó només una unió bisellada:

- - - -

Aquí tenim una petita demostració en la qual es pot configura miterLimit dinàmicament i veure com aquest afecta a les formes en el llenç. Les línies blaves mostren on es troben els punts d'inici i fi per a cadascuna de les línies en el patró de zig-zag.

- -

Si s'especifica un valor de miterLimit inferior a 4.2, en aquesta demostració, cap de les cantonades visibles s'unirà amb una extensió de miter, només hi haurà un petit bisell prop de les línies blaves; amb un miterLimit superior a 10, la majoria de les cantonades d'aquesta demostració haurien d'unir-se amb un miter allunyat de les línies blaves, i l'alçada del qual disminuiria entre les cantonades, d'esquerra a dreta perquè es connectarien amb angles creixents ; amb valors intermedis, les cantonades del costat esquerre només s'uneixen amb un bisell prop de les línies blaves, i les cantonades del costat dret amb una extensió de miter (també amb una altçada decreixent).

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-
-  // Clear canvas
-  ctx.clearRect(0, 0, 150, 150);
-
-  // Draw guides
-  ctx.strokeStyle = '#09f';
-  ctx.lineWidth   = 2;
-  ctx.strokeRect(-5, 50, 160, 50);
-
-  // Set line styles
-  ctx.strokeStyle = '#000';
-  ctx.lineWidth = 10;
-
-  // check input
-  if (document.getElementById('miterLimit').value.match(/\d+(\.\d+)?/)) {
-    ctx.miterLimit = parseFloat(document.getElementById('miterLimit').value);
-  } else {
-    alert('Value must be a positive number');
-  }
-
-  // Draw lines
-  ctx.beginPath();
-  ctx.moveTo(0, 100);
-  for (i = 0; i < 24 ; i++) {
-    var dy = i % 2 == 0 ? 25 : -25;
-    ctx.lineTo(Math.pow(i, 1.5) * 2, 75 + dy);
-  }
-  ctx.stroke();
-  return false;
-}
-
- - - -

{{EmbedLiveSample("A_demo_of_the_miterLimit_property", "400", "180", "https://mdn.mozillademos.org/files/240/Canvas_miterlimit.png")}}

- -

Ús de guions de línia

- -

El mètode setLineDash i la propietat lineDashOffset especifiquen el patró de guió per a les línies. El mètode setLineDash accepta una llista de nombres que especifica distàncies per dibuixar alternativament una línia i un buit i la propietat lineDashOffset estableix un desplaçament on començar el patró

- -

En aquest exemple estem creant un efecte de formigues marxant. És una tècnica d'animació que es troba sovint en les eines de selecció de programes gràfics d'ordinador. Ajuda a l'usuari a distingir la vora de selecció del fons de la imatge, animant la vora. Més endavant, en aquest tutorial, podeu aprendre com fer-ho i altres animacions bàsiques.

- - - -
var ctx = document.getElementById('canvas').getContext('2d');
-var offset = 0;
-
-function draw() {
-  ctx.clearRect(0, 0, canvas.width, canvas.height);
-  ctx.setLineDash([4, 2]);
-  ctx.lineDashOffset = -offset;
-  ctx.strokeRect(10, 10, 100, 100);
-}
-
-function march() {
-  offset++;
-  if (offset > 16) {
-    offset = 0;
-  }
-  draw();
-  setTimeout(march, 20);
-}
-
-march();
- -

{{EmbedLiveSample("Using_line_dashes", "120", "120", "https://mdn.mozillademos.org/files/9853/marching-ants.png")}}

- -

Gradients

- -

Igual que qualsevol altre programa normal de dibuix , podem emplenar i traçar formes usant, gradients lineals i radials. Es crea un objecte {{domxref("CanvasGradient")}} utilitzant un dels mètodes següents. A continuació, podem assignar aquest objecte a les propietats fillStyle o strokeStyle.

- -
-
{{domxref("CanvasRenderingContext2D.createLinearGradient", "createLinearGradient(x1, y1, x2, y2)")}}
-
Crea un objecte de degradat lineal amb un punt inicial de (x1, y1) i un punt final de (x2, y2).
-
{{domxref("CanvasRenderingContext2D.createRadialGradient", "createRadialGradient(x1, y1, r1, x2, y2, r2)")}}
-
Crea un degradat radial. Els paràmetres representen dos cercles, un amb el seu centre en (x1, y1) i un radi de r1, i l'altre amb el seu centre en (x2, y2) amb un radi de r2.
-
- -

Per exemple:

- -
var lineargradient = ctx.createLinearGradient(0, 0, 150, 150);
-var radialgradient = ctx.createRadialGradient(75, 75, 0, 75, 75, 100);
-
- -

Una vegada s'ha creat un objecte CanvasGradient se li pot assignar colors usant el mètode addColorStop().

- -
-
{{domxref("CanvasGradient.addColorStop", "gradient.addColorStop(position, color)")}}
-
Crea una nova parada de color en l'objecte gradient. position és un nombre entre 0.0 i 1.0 i defineix la posició relativa del color en el degradat,  i l'argument color, ha de ser una cadena que representi un {{cssxref("<color>")}} CSS, indicant el color que el gradient ha d'aconseguir en aquest desplaçament en la transició.
-
- -

Es pot afegir tantes parades de color, a un gardient, com es necessiti. A continuació, es mostra un gradient lineal molt simple de blanc a negre.

- -
var lineargradient = ctx.createLinearGradient(0, 0, 150, 150);
-lineargradient.addColorStop(0, 'white');
-lineargradient.addColorStop(1, 'black');
-
- -

Un exemple de createLinearGradient

- -

En aquest exemple, es crearà dos gradientss diferents. Com es podrà veure aquí, tant les propietats strokeStyle com fillStyle poden acceptar un objecte canvasGradient com a entrada vàlida.

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-
-  // Create gradients
-  var lingrad = ctx.createLinearGradient(0, 0, 0, 150);
-  lingrad.addColorStop(0, '#00ABEB');
-  lingrad.addColorStop(0.5, '#fff');
-  lingrad.addColorStop(0.5, '#26C000');
-  lingrad.addColorStop(1, '#fff');
-
-  var lingrad2 = ctx.createLinearGradient(0, 50, 0, 95);
-  lingrad2.addColorStop(0.5, '#000');
-  lingrad2.addColorStop(1, 'rgba(0, 0, 0, 0)');
-
-  // assign gradients to fill and stroke styles
-  ctx.fillStyle = lingrad;
-  ctx.strokeStyle = lingrad2;
-
-  // draw shapes
-  ctx.fillRect(10, 10, 130, 130);
-  ctx.strokeRect(50, 50, 50, 50);
-
-}
-
- - - -

El primer és un gradient de fons. Com es veu, s'assignen dos colors a la mateixa posició. Això es fa per fer transicions de color molt nítides, en aquest cas del blanc al verd. No importa en quina ordre es defineixin les parades de color, però en aquest cas especial, ho fa de forma significativa. Si es mantenen les tasques en l'ordre en què es desitja que apareguin, això no serà un problema.

- -

En el segon gradient, no s'assigna el color inicial (a la posició 0.0), ja que no és estrictament necessari, perquè automàticament assumirà el color de la següent parada de color. Per tant, l'assignació del color negre en la posició 0.5, automàticament fa que el gradient, des de l'inici fins a aquest punt, sigui negre.

- -

{{EmbedLiveSample("A_createLinearGradient_example", "180", "180", "https://mdn.mozillademos.org/files/235/Canvas_lineargradient.png")}}

- -

Un exemple de createRadialGradient

- -

En aquest exemple, definim quatre gradients radials diferents. Com que tenim el control sobre els punts d'inici i de tancament del gradient, podem aconseguir efectes més complexos del que normalment tindríem en els gradients radials "clàssics" que veiem, per exemple, en Photoshop (és a dir, un gradient amb un únic punt central, on el gradient s'expandeix cap a l'exterior en forma circular).

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-
-  // Create gradients
-  var radgrad = ctx.createRadialGradient(45, 45, 10, 52, 50, 30);
-  radgrad.addColorStop(0, '#A7D30C');
-  radgrad.addColorStop(0.9, '#019F62');
-  radgrad.addColorStop(1, 'rgba(1, 159, 98, 0)');
-
-  var radgrad2 = ctx.createRadialGradient(105, 105, 20, 112, 120, 50);
-  radgrad2.addColorStop(0, '#FF5F98');
-  radgrad2.addColorStop(0.75, '#FF0188');
-  radgrad2.addColorStop(1, 'rgba(255, 1, 136, 0)');
-
-  var radgrad3 = ctx.createRadialGradient(95, 15, 15, 102, 20, 40);
-  radgrad3.addColorStop(0, '#00C9FF');
-  radgrad3.addColorStop(0.8, '#00B5E2');
-  radgrad3.addColorStop(1, 'rgba(0, 201, 255, 0)');
-
-  var radgrad4 = ctx.createRadialGradient(0, 150, 50, 0, 140, 90);
-  radgrad4.addColorStop(0, '#F4F201');
-  radgrad4.addColorStop(0.8, '#E4C700');
-  radgrad4.addColorStop(1, 'rgba(228, 199, 0, 0)');
-
-  // draw shapes
-  ctx.fillStyle = radgrad4;
-  ctx.fillRect(0, 0, 150, 150);
-  ctx.fillStyle = radgrad3;
-  ctx.fillRect(0, 0, 150, 150);
-  ctx.fillStyle = radgrad2;
-  ctx.fillRect(0, 0, 150, 150);
-  ctx.fillStyle = radgrad;
-  ctx.fillRect(0, 0, 150, 150);
-}
-
- - - -

En aquest cas, hem desplaçat lleugerament el punt d'inici des del punt final per aconseguir un efecte 3D esfèric. Lo millor es tractar d'evitar que els cercles interns i externs se superposin, ja que això genera efectes estranys que són difícils de predir.

- -

L'última parada de color en cadascun dels quatre gradients, utilitza un color completament transparent. Si es desitja tenir una bona transició, d'aquesta a la parada de color anterior, tots dos colors han de ser iguals. Això no és molt obvi del codi, perquè utilitza dos mètodes de color CSS diferents com a demostració, però en el primer gradient #019F62 = rgba(1,159,98,1).

- -

{{EmbedLiveSample("A_createRadialGradient_example", "180", "180", "https://mdn.mozillademos.org/files/244/Canvas_radialgradient.png")}}

- -

Patrons

- -

En un dels exemples de la pàgina anterior, hem utilitzat una sèrie de bucles per crear un patró d'imatges. Hi ha, però, un mètode molt més senzill: el mètode createPattern().

- -
-
{{domxref("CanvasRenderingContext2D.createPattern", "createPattern(image, type)")}}
-
Crea i retorna un nou objecte de patró canvas. image es un {{domxref("CanvasImageSource")}} (és a dir, un {{domxref("HTMLImageElement")}}, altre llenç, un element {{HTMLElement("video")}} o similar. type és una cadena que indica com utilitzar la imatge.
-
- -

Type, especifica com utilitzar la imatge per crear el patró, i ha de ser un dels següents valors de cadena:

- -
-
repeat
-
Teixeix la imatge en ambdues direccions vertical i horitzontal.
-
repeat-x
-
Teixeix la imatge horitzontalment però no verticalment.
-
repeat-y
-
Teixeix la imatge verticalment però no horitzontalment.
-
no-repeat
-
No teixeix la imatge. S'utilitza només una vegada.
-
- -

S'utilitzar aquest mètode per crear un objecte {{domxref("CanvasPattern")}} que és molt similar als mètodes de gradient que hem vist anteriorment. Una vegada que s'ha creat un patró, se li pot assignar les propietats fillStyle o strokeStyle. Per exemple:

- -
var img = new Image();
-img.src = 'someimage.png';
-var ptrn = ctx.createPattern(img, 'repeat');
-
- -
-

Nota: Igual que amb el mètode drawImage(), ens hem d'assegurar que la imatge que utilitzem s'hagi carregat abans de cridar a aquest mètode o que el patró es dibuixi incorrectament.

-
- -

Un exemple de createPattern

- -

En aquest últim exemple, crearem un patró per assignar a la propietat fillStyle. L'únic que cal esmentar, és l'ús del controlador onload de la imatge. Això és per assegurar-se de que la imatge es carregui abans que s'assigni el patró.

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-
-  // create new image object to use as pattern
-  var img = new Image();
-  img.src = 'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png';
-  img.onload = function() {
-
-    // create pattern
-    var ptrn = ctx.createPattern(img, 'repeat');
-    ctx.fillStyle = ptrn;
-    ctx.fillRect(0, 0, 150, 150);
-
-  }
-}
-
- - - -

{{EmbedLiveSample("A_createPattern_example", "180", "180", "https://mdn.mozillademos.org/files/222/Canvas_createpattern.png")}}

- -

Ombres (Shadows)

- -

L'ús d'ombres implica només quatre propietats:

- -
-
{{domxref("CanvasRenderingContext2D.shadowOffsetX", "shadowOffsetX = float")}}
-
Indica la distància horitzontal que l'ombra ha d'estendre's des de l'objecte. Aquest valor no es veu afectat per la matriu de transformació. El valor predeterminat és 0.
-
{{domxref("CanvasRenderingContext2D.shadowOffsetY", "shadowOffsetY = float")}}
-
Indica la distància vertical que l'ombra ha d'estendre's des de l'objecte. Aquest valor no es veu afectat per la matriu de transformació. El valor predeterminat és 0.
-
{{domxref("CanvasRenderingContext2D.shadowBlur", "shadowBlur = float")}}
-
Indica la grandària de l'efecte de desenfocament; aquest valor no es correspon a un nombre de píxels i no es veu afectat per la matriu de transformació actual. El valor per defecte és 0.
-
{{domxref("CanvasRenderingContext2D.shadowColor", "shadowColor = color")}}
-
Un valor de color CSS estàndard, que indica el color de l'efecte d'ombra; per defecte, és negre completament transparent.
-
- -

Les propietats shadowOffsetX i shadowOffsetY indiquen fins a on ha d'estendre's l'ombra des de l'objecte en les direccions X i Y; aquests valors no es veuen afectats per la matriu de transformació actual. Utilitzar valors negatius per fer que l'ombra s'estengui cap amunt o cap a l'esquerra, i valors positius perquè l'ombra s'estengui cap avall o cap a la dreta. Tots dos són 0 per defecte.

- -

La propietat shadowBlur indica la grandària de l'efecte de desenfocament; aquest valor no es correspon a un nombre de píxels i no es veu afectat per la matriu de transformació actual. El valor per defecte és 0.

- -

La propietat shadowColor és un valor de color CSS estàndard, que indica el color de l'efecte d'ombra; per defecte, és negre completament transparent.

- -
-

Nota: Les ombres només es dibuixen per a operacions de composició de fonts.

-
- -

Un exemple de text ombrejat

- -

Aquest exemple dibuixa una cadena de text amb un efecte d'ombra.

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-
-  ctx.shadowOffsetX = 2;
-  ctx.shadowOffsetY = 2;
-  ctx.shadowBlur = 2;
-  ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';
-
-  ctx.font = '20px Times New Roman';
-  ctx.fillStyle = 'Black';
-  ctx.fillText('Sample String', 5, 30);
-}
-
- - - -

{{EmbedLiveSample("A_shadowed_text_example", "180", "100", "https://mdn.mozillademos.org/files/2505/shadowed-string.png")}}

- -

Veurem la propietat font i el mètode fillText en el següent capítol sobre com dibuixar text.

- -

Regles de farciment del llenç

- -

Quan s'utilitza fill (o {{domxref("CanvasRenderingContext2D.clip", "clip")}} i {{domxref("CanvasRenderingContext2D.isPointInPath", "isPointinPath")}}) es pot proporcionar opcionalment un algorisme de regles de farciment per determinar si un punt està dins o fora d'una trajectòria i, per tant, si s'emplena o no. Això és útil quan una trajectòria es creua o es nia.
-
- Dos valors són possibles:

- - - -

En aquest exemple estem usant la regla evenodd.

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-  ctx.beginPath();
-  ctx.arc(50, 50, 30, 0, Math.PI * 2, true);
-  ctx.arc(50, 50, 15, 0, Math.PI * 2, true);
-  ctx.fill('evenodd');
-}
- - - -

{{EmbedLiveSample("Canvas_fill_rules", "110", "110", "https://mdn.mozillademos.org/files/9855/fill-rule.png")}}

- -

{{PreviousNext("Web/API/Canvas_API/Tutorial/Drawing_shapes", "Web/API/Canvas_API/Tutorial/Drawing_text")}}

diff --git a/files/ca/web/api/canvas_api/tutorial/applying_styles_and_colors/index.html b/files/ca/web/api/canvas_api/tutorial/applying_styles_and_colors/index.html new file mode 100644 index 0000000000..9adcc2d5f4 --- /dev/null +++ b/files/ca/web/api/canvas_api/tutorial/applying_styles_and_colors/index.html @@ -0,0 +1,733 @@ +--- +title: Aplicar estils i colors +slug: Web/API/Canvas_API/Tutorial/Aplicar_estils_i_colors +tags: + - Canvas + - Graphics + - HTML + - HTML5 + - Intermediate + - Tutorial +translation_of: Web/API/Canvas_API/Tutorial/Applying_styles_and_colors +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Drawing_shapes", "Web/API/Canvas_API/Tutorial/Drawing_text")}}
+ +
+

En el capítol sobre dibuixar formes, hem utilitzat només els estils de línia i de farciment predeterminats. Aquí explorarem les opcions de canvas que tenim a la nostra disposició per fer els nostres dibuixos una mica més atractius. Aprendreu com afegir diferents colors, estils de línies, gradients, patrons i ombres als vostres dibuixos.

+
+ +

Colors

+ +

Fins ara només hem vist mètodes del context de dibuix. Si volem aplicar colors a una forma, hi ha dues propietats importants que podem utilitzar: fillStyle i strokeStyle.

+ +
+
{{domxref("CanvasRenderingContext2D.fillStyle", "fillStyle = color")}}
+
Estableix l'estil utilitzat per emplenar formes.
+
{{domxref("CanvasRenderingContext2D.strokeStyle", "strokeStyle = color")}}
+
Estableix l'estil per als contorns de les formes.
+
+ +

color és una cadena que representa un {{cssxref("<color>")}} CSS, un objecte degradat o un objecte patró. Veurem els objectes de degradat i patró més endavant. Per defecte, el traç i el color del farciment estan establerts en negre (valor de color CSS #000000).

+ +
+

Nota: Quan es defineix la propietat strokeStyle i/o fillStyle, el nou valor es converteix en el valor predeterminat per a totes les formes que s'estan dibuixant a partir d'aquest moment. Per a cada forma que desitgeu en un color diferent, haureu de tornar a assignar la propietat fillStyle o strokeStyle.

+
+ +

Les cadenes vàlides que podeu introduir han de ser, segons l'especificació, valors de {{cssxref("<color>")}} CSS. Cadascun dels següents exemples descriu el mateix color.

+ +
// these all set the fillStyle to 'orange'
+
+ctx.fillStyle = 'orange';
+ctx.fillStyle = '#FFA500';
+ctx.fillStyle = 'rgb(255, 165, 0)';
+ctx.fillStyle = 'rgba(255, 165, 0, 1)';
+
+ +

Un exemple de fillStyle

+ +

En aquest exemple, una vegada més, usem dos bucles for per dibuixar una graella de rectangles, cadascun en un color diferent. La imatge resultant hauria de ser similar a la captura de pantalla. Aquí no succeeix res espectacular. Utilitzem les dues variables i i j per generar un color RGB únic per a cada quadrat, i només modifiquen els valors vermell i verd. El canal blau té un valor fix. Modificant els canals, es poden generar tot tipus de paletes. En augmentar els passos, es pot aconseguir alguna cosa que se sembli a les paletes de color que utilitza Photoshop.

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  for (var i = 0; i < 6; i++) {
+    for (var j = 0; j < 6; j++) {
+      ctx.fillStyle = 'rgb(' + Math.floor(255 - 42.5 * i) + ', ' +
+                       Math.floor(255 - 42.5 * j) + ', 0)';
+      ctx.fillRect(j * 25, i * 25, 25, 25);
+    }
+  }
+}
+ + + +

The result looks like this:

+ +

{{EmbedLiveSample("A_fillStyle_example", 160, 160, "https://mdn.mozillademos.org/files/5417/Canvas_fillstyle.png")}}

+ +

Un exemple de strokeStyle

+ +

Aquest exemple és similar a l'anterior, però usa la propietat strokeStyle per canviar els colors dels contorns de les formes. Usem el mètode arc() per dibuixar cercles en lloc de quadrats.

+ +
  function draw() {
+    var ctx = document.getElementById('canvas').getContext('2d');
+    for (var i = 0; i < 6; i++) {
+      for (var j = 0; j < 6; j++) {
+        ctx.strokeStyle = 'rgb(0, ' + Math.floor(255 - 42.5 * i) + ', ' +
+                         Math.floor(255 - 42.5 * j) + ')';
+        ctx.beginPath();
+        ctx.arc(12.5 + j * 25, 12.5 + i * 25, 10, 0, Math.PI * 2, true);
+        ctx.stroke();
+      }
+    }
+  }
+
+ + + +

El resultat és així:

+ +

{{EmbedLiveSample("A_strokeStyle_example", "180", "180", "https://mdn.mozillademos.org/files/253/Canvas_strokestyle.png")}}

+ +

Transparència

+ +

A més de dibuixar formes opaques al llenç, també podem dibuixar formes semitransparents (o translúcides). Això es fa, ja sigui configurant la propietat globalAlpha o assignant un color semitransparent a l'estil de traç i/o d'ompliment.

+ +
+
{{domxref("CanvasRenderingContext2D.globalAlpha", "globalAlpha = transparencyValue")}}
+
Aplica el valor de transparència especificat a totes les formes futures dibuixades en el llenç. El valor ha d'estar entre 0,0 (totalment transparent) a 1.0 (totalment opac). Aquest valor és 1.0 (totalment opac) per defecte.
+
+ +

La propietat globalAlpha pot ser útil si voleu dibuixar moltes formes al llenç amb una transparència similar, però en general, és més útil establir la transparència en formes individuals quan establiu els seus colors.

+ +

Atès que les propietats strokeStyle and fillStyle accepten valors de color CSS rgba, podem utilitzar la notació següent per assignar un color transparent a ells.

+ +
// Assignar colors transparents a l'estil de traç i ompliment
+
+ctx.strokeStyle = 'rgba(255, 0, 0, 0.5)';
+ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
+
+ +

La funció rgba() és similar a la funció rgb() però té un paràmetre addicional. L'últim paràmetre estableix el valor de transparència d'aquest color en particular. El rang vàlid se situa de nou entre 0.0 (totalment transparent) i 1.0 (completament opac).

+ +

Un exemple de globalAlpha

+ +

En aquest exemple, dibuixarem un fons de quatre quadrats de colors diferents. A més d'això, dibuixarem un conjunt de cercles semitransparents. La propietat globalAlpha s'estableix en 0.2 que s'utilitzarà per a totes les formes des d'aquest punt. Cada pas en el bucle for dibuixa un conjunt de cercles amb un radi creixent. El resultat final és un gradient radial. En superposar cada vegada més cercles un damunt de l'altre, reduïm efectivament la transparència dels cercles que ja s'han dibuixat. En augmentar el recompte de passos i, en efecte, dibuixar més cercles, el fons desapareixeria completament del centre de la imatge.

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  // draw background
+  ctx.fillStyle = '#FD0';
+  ctx.fillRect(0, 0, 75, 75);
+  ctx.fillStyle = '#6C0';
+  ctx.fillRect(75, 0, 75, 75);
+  ctx.fillStyle = '#09F';
+  ctx.fillRect(0, 75, 75, 75);
+  ctx.fillStyle = '#F30';
+  ctx.fillRect(75, 75, 75, 75);
+  ctx.fillStyle = '#FFF';
+
+  // set transparency value
+  ctx.globalAlpha = 0.2;
+
+  // Draw semi transparent circles
+  for (i = 0; i < 7; i++) {
+    ctx.beginPath();
+    ctx.arc(75, 75, 10 + 10 * i, 0, Math.PI * 2, true);
+    ctx.fill();
+  }
+}
+ + + +

{{EmbedLiveSample("A_globalAlpha_example", "180", "180", "https://mdn.mozillademos.org/files/232/Canvas_globalalpha.png")}}

+ +

Un exemple usant rgba()

+ +

En aquest segon exemple, fem alguna cosa semblant a l'anterior, però en comptes de dibuixar cercles un damunt de l'altre, dibuixem petits rectangles amb opacitat creixent. L'ús de rgba() dóna una mica més de control i flexibilitat, perquè podem definir l'estil d'emplenament i traç individualment.

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  // Draw background
+  ctx.fillStyle = 'rgb(255, 221, 0)';
+  ctx.fillRect(0, 0, 150, 37.5);
+  ctx.fillStyle = 'rgb(102, 204, 0)';
+  ctx.fillRect(0, 37.5, 150, 37.5);
+  ctx.fillStyle = 'rgb(0, 153, 255)';
+  ctx.fillRect(0, 75, 150, 37.5);
+  ctx.fillStyle = 'rgb(255, 51, 0)';
+  ctx.fillRect(0, 112.5, 150, 37.5);
+
+  // Draw semi transparent rectangles
+  for (var i = 0; i < 10; i++) {
+    ctx.fillStyle = 'rgba(255, 255, 255, ' + (i + 1) / 10 + ')';
+    for (var j = 0; j < 4; j++) {
+      ctx.fillRect(5 + i * 14, 5 + j * 37.5, 14, 27.5);
+    }
+  }
+}
+ + + +

{{EmbedLiveSample("An_example_using_rgba()", "180", "180", "https://mdn.mozillademos.org/files/246/Canvas_rgba.png")}}

+ +

Estils de línia

+ +

Hi ha diverses propietats que ens permeten donar estil a les línies.

+ +
+
{{domxref("CanvasRenderingContext2D.lineWidth", "lineWidth = value")}}
+
Estableix l'amplària de les línies dibuixades en el futur.
+
{{domxref("CanvasRenderingContext2D.lineCap", "lineCap = type")}}
+
Estableix l'aparença dels extrems de les línies.
+
{{domxref("CanvasRenderingContext2D.lineJoin", "lineJoin = type")}}
+
Estableix l'aparença de les "cantonades" on s'uneixen les línies.
+
{{domxref("CanvasRenderingContext2D.miterLimit", "miterLimit = value")}}
+
Estableix un límit en la mitra, quan dues línies s'uneixen en un angle agut, per permetre-li controlar el grossor de la unió.
+
{{domxref("CanvasRenderingContext2D.getLineDash", "getLineDash()")}}
+
Retorna la matriu de patró de guió de la línia actual que conté un nombre parell de nombres no negatius.
+
{{domxref("CanvasRenderingContext2D.setLineDash", "setLineDash(segments)")}}
+
Estableix el patró de guió de línia actual.
+
{{domxref("CanvasRenderingContext2D.lineDashOffset", "lineDashOffset = value")}}
+
Especifica on iniciar una matriu de guions en una línia.
+
+ +

Obtindreu una millor comprensió del que fan, en mirar els exemples a continuació.

+ +

Un exemple de lineWidth

+ +

Aquesta propietat estableix el gruix de la línia actual. Els valors han de ser nombres positius. Per defecte, aquest valor es fixa en 1.0 unitats.

+ +

L'amplada de la línia és el gruix del traç centrat en la trajectòria indicada. En altres paraules, l'àrea que es dibuixa s'estén a la meitat de l'amplària de línia a cada costat de la trajectòria. Com que les coordenades del llenç no fan referència directa als píxels, s'ha de tenir especial cura per obtenir línies horitzontals i verticals nítides.

+ +

En el següent exemple, es dibuixen 10 línies rectes amb amplades de línia creixents. La línia en l'extrem esquerre té 1.0 unitats d'ample. No obstant això, les línies de grossor més a l'esquerra i totes les altres d'ample imparell no apareixen nítides a causa del posicionament de la trajectòria.

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  for (var i = 0; i < 10; i++) {
+    ctx.lineWidth = 1 + i;
+    ctx.beginPath();
+    ctx.moveTo(5 + i * 14, 5);
+    ctx.lineTo(5 + i * 14, 140);
+    ctx.stroke();
+  }
+}
+
+ + + +

{{EmbedLiveSample("A_lineWidth_example", "180", "180", "https://mdn.mozillademos.org/files/239/Canvas_linewidth.png")}}

+ +

L'obtenció de línies nítides requereix entendre com es tracen les trajectòries. En les imatges següents, la graella representa la graella de coordenades del llenç. Els quadrats entre les línies de la graella són píxels reals en pantalla. En la primera imatge de graella que apareix a continuació, s'emplena un rectangle de (2,1) a (5,5). Tota l'àrea entre ells (vermell clar) cau en els límits de píxels, per la qual cosa el rectangle emplenat resultant tindrà vores nítides.

+ +

+ +

Si es considera una trajectòria de (3,1) a (3,5) amb un gruix de línia  1.0, s'acaba amb la situació en la segona imatge. L'àrea real a emplenar (blau fosc) només s'estén fins a la meitat dels píxels a cada costat de la trajectòria. S'ha de representar una aproximació d'això, la qual cosa significa que aquests píxels estan ombrejats parcialment, i dóna com a resultat que tota l'àrea (blau clar i blau fosc) s'ompli amb un color la meitat de fosc que el color de traç real. Això és el que succeeix amb la línia d'ample 1.0 en el codi d'exemple anterior .

+ +

Per arreglar això, s'ha de ser molt precís en la creació de la trajectòria. Sabent que una línia a 1.0 d'ample s'estendrà mitja unitat a cada costat de la trajectòria, creant la trajectòria de (3.5,1) a (3.5,5) resulta que la situació, en la tercera imatge, la línia d'ample 1.0 acaba completa i omplint, precisament, una sola línia vertical de píxels.

+ +
+

Nota: Hem de tenir en compte que en el nostre exemple de línia vertical, la posició Y encara fa referència a una posició sencera de la graella; si no fos així, veuríem píxels amb una cobertura parcial en els punts finals (però també, hem de tenir en compte que aquest comportament depèn de l'estil actual de lineCap, el valor predeterminat del qual és butt; és possible que desitgem calcular traços uniformes amb coordenades de mig píxel per a línies d'ample imparell, establint l'estil lineCap a estil square, de manera que el límit exterior del traç al voltant del punt final s'ampliï automàticament per cobrir tot el píxel exactament).

+ +

Tinguem en compte, també, que només es veuran afectats els extrems d'inici i fi d'una trajectòria: si es tanca una trajectòria amb closePath(), no hi ha un punt d'inici i final; en el seu lloc, tots els extrems de la trajectòria es connecten al segment anterior i següent utilitzant, la configuració actual de l'estil lineJoin, el valor predeterminat del qual és miter, amb l'efecte d'estendre automàticament els límits exteriors dels segments connectats al seu punt d'intersecció, de manera que el traç representat cobreixi exactament els píxels complets centrats en cada punt final, si aquests segments connectats són horitzontals i/o verticals). Vegeu les dues seccions següents per a les demostracions d'aquests estils de línia addicionals..

+
+ +

Per a les línies d'ample parell, cada meitat acaba sent una quantitat sencera de píxels, per la qual cosa es desitjable una trajectòria que estigui entre els píxels (és a dir, (3,1) a (3,5)), en lloc de baixar per la mitad dels píxels

+ +

Tot i que és lleugerament dolorós quan inicialment es treballa amb gràfics 2D escalables, si ens fixem en la graella de píxels i la posició de les trajectòries, ens hem d'assegurar que els dibuixos es vegin correctes, independentment de l'escalat o qualsevol altra transformació. Una línia vertical de 1.0 d'ample dibuixada en la posició correcta, es convertirà en una línia nítida de 2 píxels quan s'ampliï per 2, i apareixerà en la posició correcta.

+ +

Un exemple de lineCap

+ +

La propietat lineCap determina com es dibuixen els punts finals de cada línia. Hi ha tres valors possibles per a aquesta propietat i aquests són: butt, round i square. Per defecte, aquesta propietat està configurada com a butt.

+ +

+ +
+
butt
+
Els extrems de les línies es quadren en els punts finals.
+
round
+
Els extrems de les línies són arrodonits.
+
square
+
Els extrems de les línies es quadren en afegir una caixa amb un ample igual i la meitat de l'alçada del gruix de la línia.
+
+ +

En aquest exemple, dibuixarem tres línies, cadascuna amb un valor diferent per a la propietat lineCap. També afegim dues guies per veure les diferències exactes entre les tres. Cadascuna d'aquestes línies comença i acaba exactament en aquestes guies.

+ +

La línia de l'esquerra utilitza l'opció predeterminada butt. Notarem que està dibuixada completament al ras amb les guies. La segona s'estableix, utilitzant l'opció round. Això afegeix un semicercle al extrem que té un radi de la meitat de l'ample de la línia. La línia de la dreta utilitza l'opció square. Això afegeix una caixa amb un ample igual i la meitat de l'alçada del gruix de la línia.

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  var lineCap = ['butt', 'round', 'square'];
+
+  // Draw guides
+  ctx.strokeStyle = '#09f';
+  ctx.beginPath();
+  ctx.moveTo(10, 10);
+  ctx.lineTo(140, 10);
+  ctx.moveTo(10, 140);
+  ctx.lineTo(140, 140);
+  ctx.stroke();
+
+  // Draw lines
+  ctx.strokeStyle = 'black';
+  for (var i = 0; i < lineCap.length; i++) {
+    ctx.lineWidth = 15;
+    ctx.lineCap = lineCap[i];
+    ctx.beginPath();
+    ctx.moveTo(25 + i * 50, 10);
+    ctx.lineTo(25 + i * 50, 140);
+    ctx.stroke();
+  }
+}
+
+ + + +

{{EmbedLiveSample("A_lineCap_example", "180", "180", "https://mdn.mozillademos.org/files/236/Canvas_linecap.png")}}

+ +

Un exemple de lineJoin

+ +

La propietat lineJoin determina com s'uneixen dos segments de connexió (de línies, arcs o corbes) amb longituds diferents de zero en una forma (els segments degenerats amb longituds zero, que els punts finals i punts de control especificats estan exactament en la mateixa posició, s'ometen).

+ +

Hi ha tres possibles valors per a aquesta propietat: round, bevel i miter. Per defecte aquesta propietat s'estableix a miter. Hem de tenir en compte que la configuració lineJoin no té cap efecte si els dos segments connectats tenen la mateixa direcció, ja que en aquest cas no s'afegirà cap àrea d'unió.

+ +

+ +
+
round
+
Arrodoneix les cantonades d'una forma emplenant un sector addicional del disc centrat en el punt final comú dels segments connectats. El radi per a aquestes cantonades arrodonides és igual a la meitat de l'amplada de la línia.
+
bevel
+
Emplena un àrea triangular addicional entre el punt final comú dels segments connectats i les cantonades rectangulars exteriors separades de cada segment..
+
miter
+
Els segments connectats s'uneixen estenent les seves vores exteriors per connectar-se en un sol punt, amb l'efecte d'emplenar un àrea addicional en forma de rombe. Aquest ajust s'efectua mitjançant la propietat miterLimit, que s'explica a continuació.
+
+ +

L'exemple següent dibuixa tres trajectòries diferents, demostrant cadascuna d'aquestes tres configuracions de la propietat lineJoin; la sortida es mostra a dalt..

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  var lineJoin = ['round', 'bevel', 'miter'];
+  ctx.lineWidth = 10;
+  for (var i = 0; i < lineJoin.length; i++) {
+    ctx.lineJoin = lineJoin[i];
+    ctx.beginPath();
+    ctx.moveTo(-5, 5 + i * 40);
+    ctx.lineTo(35, 45 + i * 40);
+    ctx.lineTo(75, 5 + i * 40);
+    ctx.lineTo(115, 45 + i * 40);
+    ctx.lineTo(155, 5 + i * 40);
+    ctx.stroke();
+  }
+}
+
+ + + +

{{EmbedLiveSample("A_lineJoin_example", "180", "180", "https://mdn.mozillademos.org/files/237/Canvas_linejoin.png")}}

+ +

Una demostració de la propietat miterLimit

+ +

Com s'ha vist en l'exemple anterior, en unir dues línies amb l'opció miter, les vores exteriors de les dues línies d'unió s'estenen fins al punt on es troben. En el cas de línies que tenen angles grans entre si, aquest punt no està lluny del punt de connexió interior. No obstant això, a mesura que els angles entre cada línia disminueixen, la distància (longitud de miter) entre aquests punts augmenta exponencialment.

+ +

La propietat miterLimit determina quant lluny es pot col·locar el punt de connexió exterior des del punt de connexió interior. Si dues línies excedeixen aquest valor, es dibuixa una unió bisellada. S'ha de tenir en compte que la longitud màxima de miter és el producte de l'amplada de línia mesurat en el sistema de coordenades actual, pel valor d'aquesta propietat miterLimit  (el valor per defecte és 10.0 en HTML {{HTMLElement("canvas")}}), per la qual cosa miterLimit pot ajustar-se independentment de l'escala de visualització actual o de qualsevol transformació afí de les trajectòries: només influeix en la forma efectiva de les vores de la línia representada.

+ +

Més exactament, el límit de miter és la proporció màxima permesa de la longitud de l'extensió (en el llenç HTML, es mesura entre la cantonada exterior de les vores unides de la línia i el punt final comú dels segments de connexió especificats en la trajectòria) a la meitat de l'ample de la línia. La seva definició equival a la relació màxima permesa entre la distància dels punts interiors i exteriors de la unió de les vores i l'amplada total de la línia. Llavors, aixó és igual a la cosecant de la meitat de l'angle intern mínim dels segments de connexió per sota dels quals no es representarà cap unió miter, sinó només una unió bisellada:

+ + + +

Aquí tenim una petita demostració en la qual es pot configura miterLimit dinàmicament i veure com aquest afecta a les formes en el llenç. Les línies blaves mostren on es troben els punts d'inici i fi per a cadascuna de les línies en el patró de zig-zag.

+ +

Si s'especifica un valor de miterLimit inferior a 4.2, en aquesta demostració, cap de les cantonades visibles s'unirà amb una extensió de miter, només hi haurà un petit bisell prop de les línies blaves; amb un miterLimit superior a 10, la majoria de les cantonades d'aquesta demostració haurien d'unir-se amb un miter allunyat de les línies blaves, i l'alçada del qual disminuiria entre les cantonades, d'esquerra a dreta perquè es connectarien amb angles creixents ; amb valors intermedis, les cantonades del costat esquerre només s'uneixen amb un bisell prop de les línies blaves, i les cantonades del costat dret amb una extensió de miter (també amb una altçada decreixent).

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  // Clear canvas
+  ctx.clearRect(0, 0, 150, 150);
+
+  // Draw guides
+  ctx.strokeStyle = '#09f';
+  ctx.lineWidth   = 2;
+  ctx.strokeRect(-5, 50, 160, 50);
+
+  // Set line styles
+  ctx.strokeStyle = '#000';
+  ctx.lineWidth = 10;
+
+  // check input
+  if (document.getElementById('miterLimit').value.match(/\d+(\.\d+)?/)) {
+    ctx.miterLimit = parseFloat(document.getElementById('miterLimit').value);
+  } else {
+    alert('Value must be a positive number');
+  }
+
+  // Draw lines
+  ctx.beginPath();
+  ctx.moveTo(0, 100);
+  for (i = 0; i < 24 ; i++) {
+    var dy = i % 2 == 0 ? 25 : -25;
+    ctx.lineTo(Math.pow(i, 1.5) * 2, 75 + dy);
+  }
+  ctx.stroke();
+  return false;
+}
+
+ + + +

{{EmbedLiveSample("A_demo_of_the_miterLimit_property", "400", "180", "https://mdn.mozillademos.org/files/240/Canvas_miterlimit.png")}}

+ +

Ús de guions de línia

+ +

El mètode setLineDash i la propietat lineDashOffset especifiquen el patró de guió per a les línies. El mètode setLineDash accepta una llista de nombres que especifica distàncies per dibuixar alternativament una línia i un buit i la propietat lineDashOffset estableix un desplaçament on començar el patró

+ +

En aquest exemple estem creant un efecte de formigues marxant. És una tècnica d'animació que es troba sovint en les eines de selecció de programes gràfics d'ordinador. Ajuda a l'usuari a distingir la vora de selecció del fons de la imatge, animant la vora. Més endavant, en aquest tutorial, podeu aprendre com fer-ho i altres animacions bàsiques.

+ + + +
var ctx = document.getElementById('canvas').getContext('2d');
+var offset = 0;
+
+function draw() {
+  ctx.clearRect(0, 0, canvas.width, canvas.height);
+  ctx.setLineDash([4, 2]);
+  ctx.lineDashOffset = -offset;
+  ctx.strokeRect(10, 10, 100, 100);
+}
+
+function march() {
+  offset++;
+  if (offset > 16) {
+    offset = 0;
+  }
+  draw();
+  setTimeout(march, 20);
+}
+
+march();
+ +

{{EmbedLiveSample("Using_line_dashes", "120", "120", "https://mdn.mozillademos.org/files/9853/marching-ants.png")}}

+ +

Gradients

+ +

Igual que qualsevol altre programa normal de dibuix , podem emplenar i traçar formes usant, gradients lineals i radials. Es crea un objecte {{domxref("CanvasGradient")}} utilitzant un dels mètodes següents. A continuació, podem assignar aquest objecte a les propietats fillStyle o strokeStyle.

+ +
+
{{domxref("CanvasRenderingContext2D.createLinearGradient", "createLinearGradient(x1, y1, x2, y2)")}}
+
Crea un objecte de degradat lineal amb un punt inicial de (x1, y1) i un punt final de (x2, y2).
+
{{domxref("CanvasRenderingContext2D.createRadialGradient", "createRadialGradient(x1, y1, r1, x2, y2, r2)")}}
+
Crea un degradat radial. Els paràmetres representen dos cercles, un amb el seu centre en (x1, y1) i un radi de r1, i l'altre amb el seu centre en (x2, y2) amb un radi de r2.
+
+ +

Per exemple:

+ +
var lineargradient = ctx.createLinearGradient(0, 0, 150, 150);
+var radialgradient = ctx.createRadialGradient(75, 75, 0, 75, 75, 100);
+
+ +

Una vegada s'ha creat un objecte CanvasGradient se li pot assignar colors usant el mètode addColorStop().

+ +
+
{{domxref("CanvasGradient.addColorStop", "gradient.addColorStop(position, color)")}}
+
Crea una nova parada de color en l'objecte gradient. position és un nombre entre 0.0 i 1.0 i defineix la posició relativa del color en el degradat,  i l'argument color, ha de ser una cadena que representi un {{cssxref("<color>")}} CSS, indicant el color que el gradient ha d'aconseguir en aquest desplaçament en la transició.
+
+ +

Es pot afegir tantes parades de color, a un gardient, com es necessiti. A continuació, es mostra un gradient lineal molt simple de blanc a negre.

+ +
var lineargradient = ctx.createLinearGradient(0, 0, 150, 150);
+lineargradient.addColorStop(0, 'white');
+lineargradient.addColorStop(1, 'black');
+
+ +

Un exemple de createLinearGradient

+ +

En aquest exemple, es crearà dos gradientss diferents. Com es podrà veure aquí, tant les propietats strokeStyle com fillStyle poden acceptar un objecte canvasGradient com a entrada vàlida.

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  // Create gradients
+  var lingrad = ctx.createLinearGradient(0, 0, 0, 150);
+  lingrad.addColorStop(0, '#00ABEB');
+  lingrad.addColorStop(0.5, '#fff');
+  lingrad.addColorStop(0.5, '#26C000');
+  lingrad.addColorStop(1, '#fff');
+
+  var lingrad2 = ctx.createLinearGradient(0, 50, 0, 95);
+  lingrad2.addColorStop(0.5, '#000');
+  lingrad2.addColorStop(1, 'rgba(0, 0, 0, 0)');
+
+  // assign gradients to fill and stroke styles
+  ctx.fillStyle = lingrad;
+  ctx.strokeStyle = lingrad2;
+
+  // draw shapes
+  ctx.fillRect(10, 10, 130, 130);
+  ctx.strokeRect(50, 50, 50, 50);
+
+}
+
+ + + +

El primer és un gradient de fons. Com es veu, s'assignen dos colors a la mateixa posició. Això es fa per fer transicions de color molt nítides, en aquest cas del blanc al verd. No importa en quina ordre es defineixin les parades de color, però en aquest cas especial, ho fa de forma significativa. Si es mantenen les tasques en l'ordre en què es desitja que apareguin, això no serà un problema.

+ +

En el segon gradient, no s'assigna el color inicial (a la posició 0.0), ja que no és estrictament necessari, perquè automàticament assumirà el color de la següent parada de color. Per tant, l'assignació del color negre en la posició 0.5, automàticament fa que el gradient, des de l'inici fins a aquest punt, sigui negre.

+ +

{{EmbedLiveSample("A_createLinearGradient_example", "180", "180", "https://mdn.mozillademos.org/files/235/Canvas_lineargradient.png")}}

+ +

Un exemple de createRadialGradient

+ +

En aquest exemple, definim quatre gradients radials diferents. Com que tenim el control sobre els punts d'inici i de tancament del gradient, podem aconseguir efectes més complexos del que normalment tindríem en els gradients radials "clàssics" que veiem, per exemple, en Photoshop (és a dir, un gradient amb un únic punt central, on el gradient s'expandeix cap a l'exterior en forma circular).

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  // Create gradients
+  var radgrad = ctx.createRadialGradient(45, 45, 10, 52, 50, 30);
+  radgrad.addColorStop(0, '#A7D30C');
+  radgrad.addColorStop(0.9, '#019F62');
+  radgrad.addColorStop(1, 'rgba(1, 159, 98, 0)');
+
+  var radgrad2 = ctx.createRadialGradient(105, 105, 20, 112, 120, 50);
+  radgrad2.addColorStop(0, '#FF5F98');
+  radgrad2.addColorStop(0.75, '#FF0188');
+  radgrad2.addColorStop(1, 'rgba(255, 1, 136, 0)');
+
+  var radgrad3 = ctx.createRadialGradient(95, 15, 15, 102, 20, 40);
+  radgrad3.addColorStop(0, '#00C9FF');
+  radgrad3.addColorStop(0.8, '#00B5E2');
+  radgrad3.addColorStop(1, 'rgba(0, 201, 255, 0)');
+
+  var radgrad4 = ctx.createRadialGradient(0, 150, 50, 0, 140, 90);
+  radgrad4.addColorStop(0, '#F4F201');
+  radgrad4.addColorStop(0.8, '#E4C700');
+  radgrad4.addColorStop(1, 'rgba(228, 199, 0, 0)');
+
+  // draw shapes
+  ctx.fillStyle = radgrad4;
+  ctx.fillRect(0, 0, 150, 150);
+  ctx.fillStyle = radgrad3;
+  ctx.fillRect(0, 0, 150, 150);
+  ctx.fillStyle = radgrad2;
+  ctx.fillRect(0, 0, 150, 150);
+  ctx.fillStyle = radgrad;
+  ctx.fillRect(0, 0, 150, 150);
+}
+
+ + + +

En aquest cas, hem desplaçat lleugerament el punt d'inici des del punt final per aconseguir un efecte 3D esfèric. Lo millor es tractar d'evitar que els cercles interns i externs se superposin, ja que això genera efectes estranys que són difícils de predir.

+ +

L'última parada de color en cadascun dels quatre gradients, utilitza un color completament transparent. Si es desitja tenir una bona transició, d'aquesta a la parada de color anterior, tots dos colors han de ser iguals. Això no és molt obvi del codi, perquè utilitza dos mètodes de color CSS diferents com a demostració, però en el primer gradient #019F62 = rgba(1,159,98,1).

+ +

{{EmbedLiveSample("A_createRadialGradient_example", "180", "180", "https://mdn.mozillademos.org/files/244/Canvas_radialgradient.png")}}

+ +

Patrons

+ +

En un dels exemples de la pàgina anterior, hem utilitzat una sèrie de bucles per crear un patró d'imatges. Hi ha, però, un mètode molt més senzill: el mètode createPattern().

+ +
+
{{domxref("CanvasRenderingContext2D.createPattern", "createPattern(image, type)")}}
+
Crea i retorna un nou objecte de patró canvas. image es un {{domxref("CanvasImageSource")}} (és a dir, un {{domxref("HTMLImageElement")}}, altre llenç, un element {{HTMLElement("video")}} o similar. type és una cadena que indica com utilitzar la imatge.
+
+ +

Type, especifica com utilitzar la imatge per crear el patró, i ha de ser un dels següents valors de cadena:

+ +
+
repeat
+
Teixeix la imatge en ambdues direccions vertical i horitzontal.
+
repeat-x
+
Teixeix la imatge horitzontalment però no verticalment.
+
repeat-y
+
Teixeix la imatge verticalment però no horitzontalment.
+
no-repeat
+
No teixeix la imatge. S'utilitza només una vegada.
+
+ +

S'utilitzar aquest mètode per crear un objecte {{domxref("CanvasPattern")}} que és molt similar als mètodes de gradient que hem vist anteriorment. Una vegada que s'ha creat un patró, se li pot assignar les propietats fillStyle o strokeStyle. Per exemple:

+ +
var img = new Image();
+img.src = 'someimage.png';
+var ptrn = ctx.createPattern(img, 'repeat');
+
+ +
+

Nota: Igual que amb el mètode drawImage(), ens hem d'assegurar que la imatge que utilitzem s'hagi carregat abans de cridar a aquest mètode o que el patró es dibuixi incorrectament.

+
+ +

Un exemple de createPattern

+ +

En aquest últim exemple, crearem un patró per assignar a la propietat fillStyle. L'únic que cal esmentar, és l'ús del controlador onload de la imatge. Això és per assegurar-se de que la imatge es carregui abans que s'assigni el patró.

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  // create new image object to use as pattern
+  var img = new Image();
+  img.src = 'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png';
+  img.onload = function() {
+
+    // create pattern
+    var ptrn = ctx.createPattern(img, 'repeat');
+    ctx.fillStyle = ptrn;
+    ctx.fillRect(0, 0, 150, 150);
+
+  }
+}
+
+ + + +

{{EmbedLiveSample("A_createPattern_example", "180", "180", "https://mdn.mozillademos.org/files/222/Canvas_createpattern.png")}}

+ +

Ombres (Shadows)

+ +

L'ús d'ombres implica només quatre propietats:

+ +
+
{{domxref("CanvasRenderingContext2D.shadowOffsetX", "shadowOffsetX = float")}}
+
Indica la distància horitzontal que l'ombra ha d'estendre's des de l'objecte. Aquest valor no es veu afectat per la matriu de transformació. El valor predeterminat és 0.
+
{{domxref("CanvasRenderingContext2D.shadowOffsetY", "shadowOffsetY = float")}}
+
Indica la distància vertical que l'ombra ha d'estendre's des de l'objecte. Aquest valor no es veu afectat per la matriu de transformació. El valor predeterminat és 0.
+
{{domxref("CanvasRenderingContext2D.shadowBlur", "shadowBlur = float")}}
+
Indica la grandària de l'efecte de desenfocament; aquest valor no es correspon a un nombre de píxels i no es veu afectat per la matriu de transformació actual. El valor per defecte és 0.
+
{{domxref("CanvasRenderingContext2D.shadowColor", "shadowColor = color")}}
+
Un valor de color CSS estàndard, que indica el color de l'efecte d'ombra; per defecte, és negre completament transparent.
+
+ +

Les propietats shadowOffsetX i shadowOffsetY indiquen fins a on ha d'estendre's l'ombra des de l'objecte en les direccions X i Y; aquests valors no es veuen afectats per la matriu de transformació actual. Utilitzar valors negatius per fer que l'ombra s'estengui cap amunt o cap a l'esquerra, i valors positius perquè l'ombra s'estengui cap avall o cap a la dreta. Tots dos són 0 per defecte.

+ +

La propietat shadowBlur indica la grandària de l'efecte de desenfocament; aquest valor no es correspon a un nombre de píxels i no es veu afectat per la matriu de transformació actual. El valor per defecte és 0.

+ +

La propietat shadowColor és un valor de color CSS estàndard, que indica el color de l'efecte d'ombra; per defecte, és negre completament transparent.

+ +
+

Nota: Les ombres només es dibuixen per a operacions de composició de fonts.

+
+ +

Un exemple de text ombrejat

+ +

Aquest exemple dibuixa una cadena de text amb un efecte d'ombra.

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  ctx.shadowOffsetX = 2;
+  ctx.shadowOffsetY = 2;
+  ctx.shadowBlur = 2;
+  ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';
+
+  ctx.font = '20px Times New Roman';
+  ctx.fillStyle = 'Black';
+  ctx.fillText('Sample String', 5, 30);
+}
+
+ + + +

{{EmbedLiveSample("A_shadowed_text_example", "180", "100", "https://mdn.mozillademos.org/files/2505/shadowed-string.png")}}

+ +

Veurem la propietat font i el mètode fillText en el següent capítol sobre com dibuixar text.

+ +

Regles de farciment del llenç

+ +

Quan s'utilitza fill (o {{domxref("CanvasRenderingContext2D.clip", "clip")}} i {{domxref("CanvasRenderingContext2D.isPointInPath", "isPointinPath")}}) es pot proporcionar opcionalment un algorisme de regles de farciment per determinar si un punt està dins o fora d'una trajectòria i, per tant, si s'emplena o no. Això és útil quan una trajectòria es creua o es nia.
+
+ Dos valors són possibles:

+ + + +

En aquest exemple estem usant la regla evenodd.

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  ctx.beginPath();
+  ctx.arc(50, 50, 30, 0, Math.PI * 2, true);
+  ctx.arc(50, 50, 15, 0, Math.PI * 2, true);
+  ctx.fill('evenodd');
+}
+ + + +

{{EmbedLiveSample("Canvas_fill_rules", "110", "110", "https://mdn.mozillademos.org/files/9855/fill-rule.png")}}

+ +

{{PreviousNext("Web/API/Canvas_API/Tutorial/Drawing_shapes", "Web/API/Canvas_API/Tutorial/Drawing_text")}}

diff --git a/files/ca/web/api/canvas_api/tutorial/basic_animations/index.html b/files/ca/web/api/canvas_api/tutorial/basic_animations/index.html new file mode 100644 index 0000000000..e4a3751d1e --- /dev/null +++ b/files/ca/web/api/canvas_api/tutorial/basic_animations/index.html @@ -0,0 +1,335 @@ +--- +title: Animacions bàsiques +slug: Web/API/Canvas_API/Tutorial/Animacions_bàsiques +tags: + - Canvas + - Graphics + - HTML + - HTML5 + - Intermediate + - Tutorial +translation_of: Web/API/Canvas_API/Tutorial/Basic_animations +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Compositing", "Web/API/Canvas_API/Tutorial/Advanced_animations")}}
+ +
+

Atès que estem usant Javascript per controlar els elements {{HTMLElement("canvas")}}, també és molt fàcil fer animacions (interactives). En aquest capítol veurem com fer algunes animacions bàsiques.

+
+ +

Probablement, la major limitació és que, una vegada que es dibuixa una forma, aquesta es manté així. Si necessitem moure-la, hem de tornar a dibuixar-la i tot el que s'ha dibuixat abans. Es necessita molt temps per tornar a dibuixar quadres complexos i el rendiment depèn en gran manera de la velocitat de l'equip en el qual s'està executant.

+ +

Passos bàsics d'animació

+ +

Aquests són els passos que s'han de seguir per dibuixar un marc:

+ +
    +
  1. Esborrar el llenç
    + A menys que les formes que es dibuixin omplin el llenç complet (per exemple, una imatge de fons), és necessari esborrar qualsevol forma que s'hi hagi dibuixat prèviament. La manera més fàcil de fer-ho, és usant el mètode {{domxref("CanvasRenderingContext2D.clearRect", "clearRect()")}}.
  2. +
  3. Guardar l'estat del llenç
    + Si es canvia qualsevol configuració (com ara estils, transformacions, etc.) que afectin a l'estat del llenç i ens volem assegurar que l'estat original s'utilitza cada vegada que es dibuixa un marc, hem de guardar aquest estat original.
  4. +
  5. Dibuixar formes animades
    + El pas on es fa la representació del marc real.
  6. +
  7. Restaurar l'estat del llenç
    + Si s'ha guardat l'estat, ho hem de restaurar abans de dibuixar un nou marc.
  8. +
+ +

Controlar una animació

+ +

Les formes es dibuixen al llenç usant els mètodes de canvas directament o cridant a les funcions personalitzades. En circumstàncies normals, només veiem que aquests resultats apareixen en el llenç quan el script acaba d'executar-se. Per exemple, no és possible fer una animació des d'un bucle for.

+ +

Això significa que necessitem una forma d'executar les nostres funcions de dibuix durant un període de temps. Hi ha dues maneres de controlar una animació com aquesta.

+ +

Actualitzacions programades

+ +

Primer estan les funcions {{domxref("window.setInterval()")}}, {{domxref("window.setTimeout()")}} i {{domxref("window.requestAnimationFrame()")}}, que es poden utilitzar per cridar a una funció específica durant un període de temps determinat.

+ +
+
{{domxref("WindowTimers.setInterval", "setInterval(function, delay)")}}
+
Inicia repetidament l'execució de la funció especificada per la funció, cada mil·lisegons de retard.
+
{{domxref("WindowTimers.setTimeout", "setTimeout(function, delay)")}}
+
Executa la funció especificada per la function en mil·lisegons de delay.
+
{{domxref("Window.requestAnimationFrame()", "requestAnimationFrame(callback)")}}
+
Li diu al navegador que desitja realitzar una animació i sol·licita al navegador que cridi a una funció especifica per actualitzar una animació abans del proper repintat.
+
+ +

Si no es vol cap interacció amb l'usuari, es pot utilitzar la funció setInterval() que executa repetidament el codi proporcionat. Si volguéssim fer un joc, podríem usar esdeveniments de teclat o ratolí per controlar l'animació i usar setTimeout(). En establir {{domxref("EventListener")}}s, capturem qualsevol interacció de l'usuari i s'executan les nostres funcions d'animació

+ +
+

En els exemples següents, utilitzarem el mètode {{domxref("window.requestAnimationFrame()")}} per controlar l'animació. El mètode requestAnimationFrame proporciona una manera fluïda i eficient per a l'animació, cridant al marc d'animació quan el sistema estigui preparat per pintar el marc. El nombre de crides retornades és generalment 60 vegades per segon i pot reduir-se a una taxa més baixa quan s'executa en les pestanyes de fons. Per a més informació sobre el bucle d'animació, especialment per a jocs, veure l'article Anatomia d'un videojoc en la nostra Zona de desenvolupament de jocs.

+
+ +

Un sistema solar animat

+ +

Aquest exemple anima un petit model del nostre sistema solar.

+ +
var sun = new Image();
+var moon = new Image();
+var earth = new Image();
+function init() {
+  sun.src = 'https://mdn.mozillademos.org/files/1456/Canvas_sun.png';
+  moon.src = 'https://mdn.mozillademos.org/files/1443/Canvas_moon.png';
+  earth.src = 'https://mdn.mozillademos.org/files/1429/Canvas_earth.png';
+  window.requestAnimationFrame(draw);
+}
+
+function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  ctx.globalCompositeOperation = 'destination-over';
+  ctx.clearRect(0, 0, 300, 300); // clear canvas
+
+  ctx.fillStyle = 'rgba(0, 0, 0, 0.4)';
+  ctx.strokeStyle = 'rgba(0, 153, 255, 0.4)';
+  ctx.save();
+  ctx.translate(150, 150);
+
+  // Earth
+  var time = new Date();
+  ctx.rotate(((2 * Math.PI) / 60) * time.getSeconds() + ((2 * Math.PI) / 60000) * time.getMilliseconds());
+  ctx.translate(105, 0);
+  ctx.fillRect(0, -12, 50, 24); // Shadow
+  ctx.drawImage(earth, -12, -12);
+
+  // Moon
+  ctx.save();
+  ctx.rotate(((2 * Math.PI) / 6) * time.getSeconds() + ((2 * Math.PI) / 6000) * time.getMilliseconds());
+  ctx.translate(0, 28.5);
+  ctx.drawImage(moon, -3.5, -3.5);
+  ctx.restore();
+
+  ctx.restore();
+
+  ctx.beginPath();
+  ctx.arc(150, 150, 105, 0, Math.PI * 2, false); // Earth orbit
+  ctx.stroke();
+
+  ctx.drawImage(sun, 0, 0, 300, 300);
+
+  window.requestAnimationFrame(draw);
+}
+
+init();
+
+ + + +

{{EmbedLiveSample("An_animated_solar_system", "310", "310", "https://mdn.mozillademos.org/files/202/Canvas_animation1.png")}}

+ +

Un rellotge animat

+ +

Aquest exemple dibuixa un rellotge animat que mostra l'hora actual.

+ +
function clock() {
+  var now = new Date();
+  var ctx = document.getElementById('canvas').getContext('2d');
+  ctx.save();
+  ctx.clearRect(0, 0, 150, 150);
+  ctx.translate(75, 75);
+  ctx.scale(0.4, 0.4);
+  ctx.rotate(-Math.PI / 2);
+  ctx.strokeStyle = 'black';
+  ctx.fillStyle = 'white';
+  ctx.lineWidth = 8;
+  ctx.lineCap = 'round';
+
+  // Hour marks
+  ctx.save();
+  for (var i = 0; i < 12; i++) {
+    ctx.beginPath();
+    ctx.rotate(Math.PI / 6);
+    ctx.moveTo(100, 0);
+    ctx.lineTo(120, 0);
+    ctx.stroke();
+  }
+  ctx.restore();
+
+  // Minute marks
+  ctx.save();
+  ctx.lineWidth = 5;
+  for (i = 0; i < 60; i++) {
+    if (i % 5!= 0) {
+      ctx.beginPath();
+      ctx.moveTo(117, 0);
+      ctx.lineTo(120, 0);
+      ctx.stroke();
+    }
+    ctx.rotate(Math.PI / 30);
+  }
+  ctx.restore();
+
+  var sec = now.getSeconds();
+  var min = now.getMinutes();
+  var hr  = now.getHours();
+  hr = hr >= 12 ? hr - 12 : hr;
+
+  ctx.fillStyle = 'black';
+
+  // write Hours
+  ctx.save();
+  ctx.rotate(hr * (Math.PI / 6) + (Math.PI / 360) * min + (Math.PI / 21600) *sec);
+  ctx.lineWidth = 14;
+  ctx.beginPath();
+  ctx.moveTo(-20, 0);
+  ctx.lineTo(80, 0);
+  ctx.stroke();
+  ctx.restore();
+
+  // write Minutes
+  ctx.save();
+  ctx.rotate((Math.PI / 30) * min + (Math.PI / 1800) * sec);
+  ctx.lineWidth = 10;
+  ctx.beginPath();
+  ctx.moveTo(-28, 0);
+  ctx.lineTo(112, 0);
+  ctx.stroke();
+  ctx.restore();
+
+  // Write seconds
+  ctx.save();
+  ctx.rotate(sec * Math.PI / 30);
+  ctx.strokeStyle = '#D40000';
+  ctx.fillStyle = '#D40000';
+  ctx.lineWidth = 6;
+  ctx.beginPath();
+  ctx.moveTo(-30, 0);
+  ctx.lineTo(83, 0);
+  ctx.stroke();
+  ctx.beginPath();
+  ctx.arc(0, 0, 10, 0, Math.PI * 2, true);
+  ctx.fill();
+  ctx.beginPath();
+  ctx.arc(95, 0, 10, 0, Math.PI * 2, true);
+  ctx.stroke();
+  ctx.fillStyle = 'rgba(0, 0, 0, 0)';
+  ctx.arc(0, 0, 3, 0, Math.PI * 2, true);
+  ctx.fill();
+  ctx.restore();
+
+  ctx.beginPath();
+  ctx.lineWidth = 14;
+  ctx.strokeStyle = '#325FA2';
+  ctx.arc(0, 0, 142, 0, Math.PI * 2, true);
+  ctx.stroke();
+
+  ctx.restore();
+
+  window.requestAnimationFrame(clock);
+}
+
+window.requestAnimationFrame(clock);
+ + + +

{{EmbedLiveSample("An_animated_clock", "180", "180", "https://mdn.mozillademos.org/files/203/Canvas_animation2.png")}}

+ +

Un panorama en bucle

+ +

En aquest exemple, es desplaça una imatge panoràmica d'esquerra a dreta. Estem usant una imatge del Parc Nacional Yosemite, que hem pres de Wikipedia, però es pot usar qualsevol imatge que sigui més gran que el llenç.

+ +
var img = new Image();
+
+// User Variables - customize these to change the image being scrolled, its
+// direction, and the speed.
+
+img.src = 'https://mdn.mozillademos.org/files/4553/Capitan_Meadows,_Yosemite_National_Park.jpg';
+var CanvasXSize = 800;
+var CanvasYSize = 200;
+var speed = 30; // lower is faster
+var scale = 1.05;
+var y = -4.5; // vertical offset
+
+// Main program
+
+var dx = 0.75;
+var imgW;
+var imgH;
+var x = 0;
+var clearX;
+var clearY;
+var ctx;
+
+img.onload = function() {
+    imgW = img.width * scale;
+    imgH = img.height * scale;
+
+    if (imgW > CanvasXSize) {
+        // image larger than canvas
+        x = CanvasXSize - imgW;
+    }
+    if (imgW > CanvasXSize) {
+        // image width larger than canvas
+        clearX = imgW;
+    } else {
+        clearX = CanvasXSize;
+    }
+    if (imgH > CanvasYSize) {
+        // image height larger than canvas
+        clearY = imgH;
+    } else {
+        clearY = CanvasYSize;
+    }
+
+    // get canvas context
+    ctx = document.getElementById('canvas').getContext('2d');
+
+    // set refresh rate
+    return setInterval(draw, speed);
+}
+
+function draw() {
+    ctx.clearRect(0, 0, clearX, clearY); // clear the canvas
+
+    // if image is <= Canvas Size
+    if (imgW <= CanvasXSize) {
+        // reset, start from beginning
+        if (x > CanvasXSize) {
+            x = -imgW + x;
+        }
+        // draw additional image1
+        if (x > 0) {
+            ctx.drawImage(img, -imgW + x, y, imgW, imgH);
+        }
+        // draw additional image2
+        if (x - imgW > 0) {
+            ctx.drawImage(img, -imgW * 2 + x, y, imgW, imgH);
+        }
+    }
+
+    // image is > Canvas Size
+    else {
+        // reset, start from beginning
+        if (x > (CanvasXSize)) {
+            x = CanvasXSize - imgW;
+        }
+        // draw aditional image
+        if (x > (CanvasXSize-imgW)) {
+            ctx.drawImage(img, x - imgW + 1, y, imgW, imgH);
+        }
+    }
+    // draw image
+    ctx.drawImage(img, x, y,imgW, imgH);
+    // amount to move
+    x += dx;
+}
+
+ +

A continuació un {{HTMLElement("canvas")}} en què es desplaça la imatge. Hem de tenir en compte que l'amplada i l'alçada especificades aquí, han de coincidir amb els valors de les variables CanvasXZSize i CanvasYSize en el codi JavaScript.

+ +
<canvas id="canvas" width="800" height="200"></canvas>
+ +

{{EmbedLiveSample("A_looping_panorama", "830", "230")}}

+ +

Altres exemples

+ +
+
Una roda de raigs bàsica
+
Un bon exemple de com fer animacions usant els controls del teclat.
+
Animacions avançades
+
En el proper capítol veurem algunes tècniques avançades d'animació i física.
+
+ +

{{PreviousNext("Web/API/Canvas_API/Tutorial/Compositing", "Web/API/Canvas_API/Tutorial/Advanced_animations")}}

diff --git a/files/ca/web/api/canvas_api/tutorial/basic_usage/index.html b/files/ca/web/api/canvas_api/tutorial/basic_usage/index.html new file mode 100644 index 0000000000..fb15a62d81 --- /dev/null +++ b/files/ca/web/api/canvas_api/tutorial/basic_usage/index.html @@ -0,0 +1,158 @@ +--- +title: Ús bàsic de canvas +slug: Web/API/Canvas_API/Tutorial/Ús_bàsic +tags: + - Canvas + - Graphics + - HTML + - Intermediate + - Tutorial +translation_of: Web/API/Canvas_API/Tutorial/Basic_usage +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial", "Web/API/Canvas_API/Tutorial/Drawing_shapes")}}
+ +
+

Comencem aquest tutorial consultant l'element {{HTMLElement("canvas")}} {{Glossary("HTML")}}. Al final d'aquesta pàgina, sabreu com configurar un context 2D de canvas i haureu dibuixat un primer exemple en el vostre navegador.

+
+ +

L'element <canvas>

+ +
<canvas id="tutorial" width="150" height="150"></canvas>
+
+ +

A primera vista, {{HTMLElement("canvas")}} s'assembla l'element {{HTMLElement("img")}} amb l'única diferència clara, que no té els atributs src i alt. De fet, l'element <canvas> només té dos atributs, {{htmlattrxref("width", "canvas")}} i {{htmlattrxref("height", "canvas")}}. Aquests són opcionals i també es poden establir utilitzant les properties {{Glossary("DOM")}} . Quan no s'especifiquen els atributs width i height, inicialment canvas tindrà 300 píxels d'amplada i 150 píxels d'alçada. L'element es pot dimensionar arbitràriament per {{Glossary("CSS")}}, però durant la representació, la imatge s'escala per adaptar-se a la seva grandària de disseny: si el dimensionament CSS no respecta la relació inicial de canvas, apareixerà distorsionada

+ +
+

Nota: Si les vostres representacions semblen distorsionades, intenteu especificar els atributs width i height, explícitament, en els atributs <canvas> i no utilitzeu CSS.

+
+ +

L'atribut id no és específic de l'element <canvas>, però és un dels atributs HTML global que es pot aplicar a qualsevol element HTML (com class, per exemple). Sempre és una bona idea proporcionar un id, perquè això fa que sigui molt més fàcil identificar-lo en un script.

+ +

L'element <canvas> se li pot donar estil com qualsevol imatge normal ({{cssxref("margin")}}, {{cssxref("border")}}, {{cssxref("background")}}…). Aquestes regles, no obstant això, no afecten al dibuix real sobre el llenç. Veurem com això es fa en un capítol dedicat d'aquest tutorial. Quan no s'apliquen regles d'estil al llenç, inicialment, serà totalment transparent.

+ +
+

Contingut alternatiu

+ +

L'element <canvas> difereix d'una etiqueta {{HTMLElement("img")}} com per els elements {{HTMLElement("video")}}, {{HTMLElement("audio")}} o {{HTMLElement("picture")}}, és fàcil definir algun contingut alternatiu, que es mostri en navegadors antics que no ho suportin, com ara en versions d'Internet Explorer anteriors a la versió 9 o navegadors textuals. Sempre haureu de proporcionar contingut alternatiu perquè els navegadors ho mostrin.

+ +

Proporcionar contingut alternatiu és molt senzill: simplement inseriu el contingut alternatiu dins de l'element <canvas>. Els navegadors que no suporten <canvas> ignoraran el contenidor i mostraran el contingut alternatiu dins del mateix. Els navegadors que suporten <canvas> ignoraran el contingut dins del contenidor, i simplement mostraran el llenç, normalment.

+ +

Per exemple, podríem proporcionar una descripció de text del contingut del llenç o proporcionar una imatge estàtica del contingut presentat dinàmicament. Això pot semblar-se a això:

+ +
<canvas id="stockGraph" width="150" height="150">
+  current stock price: $3.15 + 0.15
+</canvas>
+
+<canvas id="clock" width="150" height="150">
+  <img src="images/clock.png" width="150" height="150" alt=""/>
+</canvas>
+
+ +

Dir-li a l'usuari que utilitzi un navegador diferent que suporti canvas no ajuda als usuaris que no poden llegir canvas en absolut, per exemple. Proporcionar un text alternatiu útil o un DOM secundari, ajuda a fer canvas més accessible.

+ +

Etiqueta </canvas> obligatoria

+ +

Com a conseqüència de la manera en què es proporciona una solució alternativa, a diferència de l'element {{HTMLElement("img")}}, l'element {{HTMLElement("canvas")}} requereix l'etiqueta de tancament (</canvas>). Si aquesta etiqueta no està present, la resta del document es consideraria contingut alternatiu i no es mostraria.

+ +

Si no es necessita un contingut alternatiu, un simple <canvas id="foo" ...></canvas> és totalment compatible amb tots els navegadors que suporten canvas.

+ +

El context de representació

+ +

L'element {{HTMLElement("canvas")}} crea una superfície de dibuix de grandària fixa que exposa un o més contextos de representació, que s'utilitzen per crear i manipular el contingut mostrat. En aquest tutorial, ens centrem en el context de representació 2D. Altres contextos poden proporcionar diferents tipus de representació; per exemple, WebGL utilitza un context 3D basat en OpenGL ÉS.Other contexts may provide different types of rendering; for example, WebGL uses a 3D context based on OpenGL ES.

+ +

El llenç està inicialment en blanc. Per mostrar alguna cosa, un script, primer necessita accedir al context de representació i dibuixar en ell. L'element {{HTMLElement("canvas")}} té un mètode anomenat {{domxref("HTMLCanvasElement.getContext", "getContext()")}}, utilitzat per obtenir el context de representació i les seves funcions de dibuix. getContext() pren un paràmetre, el tipus de context. Per als gràfics 2D, com els que es detallen en aquest tutorial, heu d'especificar "2d" per obtenir un {{domxref("CanvasRenderingContext2D")}}.

+ +
var canvas = document.getElementById('tutorial');
+var ctx = canvas.getContext('2d');
+
+ +

La primera línia del script recupera el node en el DOM, que representa l'element {{HTMLElement("canvas")}} cridant el mètode {{domxref("document.getElementById()")}}. Un cop tingueu el node d'element, podeu accedir al context del dibuix mitjançant el mètode getContext().

+ +
+

Comprovació del suport

+ +

El contingut alternatiu es mostra en navegadors que no admeten {{HTMLElement("canvas")}}. Les seqüències d'ordres, també poden comprovar la compatibilitat mitjançant programació, simplement provant la presència del mètode getContext(). El nostre fragment de codi de dalt es converteix en una cosa així:

+ +
var canvas = document.getElementById('tutorial');
+
+if (canvas.getContext) {
+  var ctx = canvas.getContext('2d');
+  // drawing code here
+} else {
+  // canvas-unsupported code here
+}
+
+
+
+ +

Una plantilla esquelet

+ +

Aquí teniu una plantilla minimalista, que usarem com a punt de partida per a exemples posteriors.

+ +
+

Nota: no és una bona pràctica incrustar un script dins d'HTML. Ho fem aquí per mantenir l'exemple concís.

+
+ +
<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <title>Canvas tutorial</title>
+    <script type="text/javascript">
+      function draw() {
+        var canvas = document.getElementById('tutorial');
+        if (canvas.getContext) {
+          var ctx = canvas.getContext('2d');
+        }
+      }
+    </script>
+    <style type="text/css">
+      canvas { border: 1px solid black; }
+    </style>
+  </head>
+  <body onload="draw();">
+    <canvas id="tutorial" width="150" height="150"></canvas>
+  </body>
+</html>
+
+ +

El script inclou una funció anomenada draw(), que s'executa una vegada que la pàgina acaba de carregar-se; això es fa escoltant  l'esdeveniment {{event("load")}} en el document. Aquesta funció, o una similar, també pot ser cridada usant {{domxref("WindowTimers.setTimeout", "window.setTimeout()")}}, {{domxref("WindowTimers.setInterval", "window.setInterval()")}}, o qualsevol altre controlador d'esdeveniments, sempre que la pàgina s'hagi carregat primer.

+ +

Així és com es veuria una plantilla en acció. Com es mostra aquí, inicialment està en blanc.

+ +

{{EmbedLiveSample("A_skeleton_template", 160, 160)}}

+ +

Un exemple senzill

+ +

Per començar, feu un cop d'ull a un exemple senzill que dibuixa dos rectangles que es creuen, un dels quals té una transparència alfa. Explorarem com funciona això amb més detall en exemples posteriors.

+ +
<!DOCTYPE html>
+<html>
+ <head>
+  <meta charset="utf-8"/>
+  <script type="application/javascript">
+    function draw() {
+      var canvas = document.getElementById('canvas');
+      if (canvas.getContext) {
+        var ctx = canvas.getContext('2d');
+
+        ctx.fillStyle = 'rgb(200, 0, 0)';
+        ctx.fillRect(10, 10, 50, 50);
+
+        ctx.fillStyle = 'rgba(0, 0, 200, 0.5)';
+        ctx.fillRect(30, 30, 50, 50);
+      }
+    }
+  </script>
+ </head>
+ <body onload="draw();">
+   <canvas id="canvas" width="150" height="150"></canvas>
+ </body>
+</html>
+
+ +

Aquest exemple es veu així:

+ +

{{EmbedLiveSample("A_simple_example", 160, 160, "https://mdn.mozillademos.org/files/228/canvas_ex1.png")}}

+ +

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

diff --git "a/files/ca/web/api/canvas_api/tutorial/composici\303\263/index.html" "b/files/ca/web/api/canvas_api/tutorial/composici\303\263/index.html" deleted file mode 100644 index e556e911d4..0000000000 --- "a/files/ca/web/api/canvas_api/tutorial/composici\303\263/index.html" +++ /dev/null @@ -1,113 +0,0 @@ ---- -title: Composició i retall -slug: Web/API/Canvas_API/Tutorial/Composició -tags: - - Canvas - - Graphics - - HTML - - HTML5 - - Intermediate - - Tutorial -translation_of: Web/API/Canvas_API/Tutorial/Compositing ---- -
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Transformations", "Web/API/Canvas_API/Tutorial/Basic_animations")}}
- -
-

En tots els nostres exemples anteriors, les formes sempre s'han dibuixat una damunt de l'altra. Això és més que adequat per a la majoria de les situacions, però limita l'ordre en què es construeixen formes compostes. No obstant això, podem canviar aquest comportament establint la propietat globalCompositeOperation. A més, la propietat clip permet ocultar parts de formes no desitjades.

-
- -

globalCompositeOperation

- -

No només podem dibuixar noves formes darrere de les formes existents, sinó que també, podem utilitzar-ho per emmascarar certes àrees, esborrar seccions del llenç (no limitades a rectangles, com ho fa el mètode {{domxref("CanvasRenderingContext2D.clearRect", "clearRect()")}}) i molt més.

- -
-
{{domxref("CanvasRenderingContext2D.globalCompositeOperation", "globalCompositeOperation = type")}}
-
Estableix el tipus d'operació de composició que s'aplicarà en dibuixar noves formes, on el tipus és una cadena que identifica quina de les dotze operacions de composició ha d'utilitzar-se.
-
- -

Veure exemples de composició per al codi dels següents exemples.

- -

{{EmbedLiveSample("Compositing_example", 750, 6750, "" ,"Web/API/Canvas_API/Tutorial/Compositing/Example")}}

- -

Trajectòries de retall

- -

Una trajectòria de retall és com una forma de llenç normal, però actua com una màscara per ocultar parts no desitjades de formes. Això es visualitza en la imatge de la dreta. La forma d'estel vermell és la nostre trajectòria de retall. Tot el que queda fora d'aquesta trajectòria no es dibuixarà en el llenç.

- -

Si comparem les trajectòries de retall  amb la propietat globalCompositeOperation, que hem vist anteriorment, veiem dos modes de composició que aconsegueixen més o menys el mateix efecte en source-in i source-atop. Les diferències més importants entre les dues, són que les trajectòries de retall mai es dibuixen realment al llenç i la trajectòria de retall mai es veu afectada per l'addició de noves formes. Això fa que les trajectòries de retall siguin ideals per dibuixar múltiples formes en un àrea restringida

- -

En el capítol sobre dibuixar formes, només s'ha esmentat els mètodes stroke() i fill(), però hi ha un tercer mètode que es pot utilitzar amb les trajectòries, anomenat clip().

- -
-
{{domxref("CanvasRenderingContext2D.clip", "clip()")}}
-
Converteix la trajectòria que s'està construint, en la trajectòria de retall actual.
-
- -

Utilitzar clip() en lloc de closePath() per tancar una trajectòria i convertir-la en una trajectòria de retall en lloc de traçar o emplenar la trajectòria.

- -

Per defecte, l'element {{HTMLElement("canvas")}}, té una trajectòria de retall de la mateixa grandària que el propi llenç. En altres paraules, no es produeix cap retall.

- -

Un exemple de clip

- -

En aquest exemple, utilitzarem un trajectòria de retall circular per restringir el dibuix d'un conjunt d'estels aleatòries a una regió en particular.

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-  ctx.fillRect(0, 0, 150, 150);
-  ctx.translate(75, 75);
-
-  // Crea una trajectòria de retall circular
-  ctx.beginPath();
-  ctx.arc(0, 0, 60, 0, Math.PI * 2, true);
-  ctx.clip();
-
-  // dibuixa el fons
-  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);
-
-  // dibuixa els estels
-  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();
-}
-
- - - -

En les primeres línies de codi, dibuixem un rectangle negre de la grandària del llenç com a fons, després traslladem l'origen al centre. A continuació, creem la trajectòria de retall circular, dibuixant un arc i cridem clip(). Les trajectòries de retall també formen part de l'estat de guardat del llenç. Si haguéssim volgut mantenir la trajectòria de retall original, podríem haver guardat l'estat del llenç abans de crear el nou.

- -

Tot el que es dibuixa després de crear la trajectòria de retall, només apareixerà dins d'aquesta trajectòria. Es pot veure això clarament, en el gradient lineal que es dibuixa a continuació. Després d'això, es dibuixa un conjunt de 50 estels posicionats aleatòriament i escalats, usant la funció personalitzada drawStar(). De nou, els estels, només apareixen dins de la trajectòria de retall definida.

- -

{{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")}}

diff --git a/files/ca/web/api/canvas_api/tutorial/compositing/index.html b/files/ca/web/api/canvas_api/tutorial/compositing/index.html new file mode 100644 index 0000000000..e556e911d4 --- /dev/null +++ b/files/ca/web/api/canvas_api/tutorial/compositing/index.html @@ -0,0 +1,113 @@ +--- +title: Composició i retall +slug: Web/API/Canvas_API/Tutorial/Composició +tags: + - Canvas + - Graphics + - HTML + - HTML5 + - Intermediate + - Tutorial +translation_of: Web/API/Canvas_API/Tutorial/Compositing +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Transformations", "Web/API/Canvas_API/Tutorial/Basic_animations")}}
+ +
+

En tots els nostres exemples anteriors, les formes sempre s'han dibuixat una damunt de l'altra. Això és més que adequat per a la majoria de les situacions, però limita l'ordre en què es construeixen formes compostes. No obstant això, podem canviar aquest comportament establint la propietat globalCompositeOperation. A més, la propietat clip permet ocultar parts de formes no desitjades.

+
+ +

globalCompositeOperation

+ +

No només podem dibuixar noves formes darrere de les formes existents, sinó que també, podem utilitzar-ho per emmascarar certes àrees, esborrar seccions del llenç (no limitades a rectangles, com ho fa el mètode {{domxref("CanvasRenderingContext2D.clearRect", "clearRect()")}}) i molt més.

+ +
+
{{domxref("CanvasRenderingContext2D.globalCompositeOperation", "globalCompositeOperation = type")}}
+
Estableix el tipus d'operació de composició que s'aplicarà en dibuixar noves formes, on el tipus és una cadena que identifica quina de les dotze operacions de composició ha d'utilitzar-se.
+
+ +

Veure exemples de composició per al codi dels següents exemples.

+ +

{{EmbedLiveSample("Compositing_example", 750, 6750, "" ,"Web/API/Canvas_API/Tutorial/Compositing/Example")}}

+ +

Trajectòries de retall

+ +

Una trajectòria de retall és com una forma de llenç normal, però actua com una màscara per ocultar parts no desitjades de formes. Això es visualitza en la imatge de la dreta. La forma d'estel vermell és la nostre trajectòria de retall. Tot el que queda fora d'aquesta trajectòria no es dibuixarà en el llenç.

+ +

Si comparem les trajectòries de retall  amb la propietat globalCompositeOperation, que hem vist anteriorment, veiem dos modes de composició que aconsegueixen més o menys el mateix efecte en source-in i source-atop. Les diferències més importants entre les dues, són que les trajectòries de retall mai es dibuixen realment al llenç i la trajectòria de retall mai es veu afectada per l'addició de noves formes. Això fa que les trajectòries de retall siguin ideals per dibuixar múltiples formes en un àrea restringida

+ +

En el capítol sobre dibuixar formes, només s'ha esmentat els mètodes stroke() i fill(), però hi ha un tercer mètode que es pot utilitzar amb les trajectòries, anomenat clip().

+ +
+
{{domxref("CanvasRenderingContext2D.clip", "clip()")}}
+
Converteix la trajectòria que s'està construint, en la trajectòria de retall actual.
+
+ +

Utilitzar clip() en lloc de closePath() per tancar una trajectòria i convertir-la en una trajectòria de retall en lloc de traçar o emplenar la trajectòria.

+ +

Per defecte, l'element {{HTMLElement("canvas")}}, té una trajectòria de retall de la mateixa grandària que el propi llenç. En altres paraules, no es produeix cap retall.

+ +

Un exemple de clip

+ +

En aquest exemple, utilitzarem un trajectòria de retall circular per restringir el dibuix d'un conjunt d'estels aleatòries a una regió en particular.

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  ctx.fillRect(0, 0, 150, 150);
+  ctx.translate(75, 75);
+
+  // Crea una trajectòria de retall circular
+  ctx.beginPath();
+  ctx.arc(0, 0, 60, 0, Math.PI * 2, true);
+  ctx.clip();
+
+  // dibuixa el fons
+  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);
+
+  // dibuixa els estels
+  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();
+}
+
+ + + +

En les primeres línies de codi, dibuixem un rectangle negre de la grandària del llenç com a fons, després traslladem l'origen al centre. A continuació, creem la trajectòria de retall circular, dibuixant un arc i cridem clip(). Les trajectòries de retall també formen part de l'estat de guardat del llenç. Si haguéssim volgut mantenir la trajectòria de retall original, podríem haver guardat l'estat del llenç abans de crear el nou.

+ +

Tot el que es dibuixa després de crear la trajectòria de retall, només apareixerà dins d'aquesta trajectòria. Es pot veure això clarament, en el gradient lineal que es dibuixa a continuació. Després d'això, es dibuixa un conjunt de 50 estels posicionats aleatòriament i escalats, usant la funció personalitzada drawStar(). De nou, els estels, només apareixen dins de la trajectòria de retall definida.

+ +

{{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")}}

diff --git a/files/ca/web/api/canvas_api/tutorial/dibuixar_text/index.html b/files/ca/web/api/canvas_api/tutorial/dibuixar_text/index.html deleted file mode 100644 index 37b730176a..0000000000 --- a/files/ca/web/api/canvas_api/tutorial/dibuixar_text/index.html +++ /dev/null @@ -1,165 +0,0 @@ ---- -title: Dibuixar text -slug: Web/API/Canvas_API/Tutorial/Dibuixar_text -tags: - - Canvas - - Graphics - - Intermediate - - Tutorial -translation_of: Web/API/Canvas_API/Tutorial/Drawing_text ---- -
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Applying_styles_and_colors", "Web/API/Canvas_API/Tutorial/Using_images")}}
- -
-

Després d'haver vist com aplicar estils i colors en el capítol anterior, ara veurem com dibuixar text sobre canvas.

-
- -

Dibuixar text

- -

El context de representació de canvas proporciona dos mètodes per representar el text:

- -
-
{{domxref("CanvasRenderingContext2D.fillText", "fillText(text, x, y [, maxWidth])")}}
-
Omple un text donat en la posició donada (x, y). Opcionalment amb ample màxim per dibuixar.
-
{{domxref("CanvasRenderingContext2D.strokeText", "strokeText(text, x, y [, maxWidth])")}}
-
Traça un text donat en la posició donada (x, y). Opcionalment amb ample màxim per dibuixar.
-
- -

Un exemple de fillText

- -

El text s'omple usant l'actual fillStyle.

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-  ctx.font = '48px serif';
-  ctx.fillText('Hello world', 10, 50);
-}
- - - -

{{EmbedLiveSample("A_fillText_example", 310, 110)}}

- -

Un exemple de strokeText

- -

El text s'omple usant l'actual strokeStyle.

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-  ctx.font = '48px serif';
-  ctx.strokeText('Hello world', 10, 50);
-}
- - - -

{{EmbedLiveSample("A_strokeText_example", 310, 110)}}

- -

Estil de text

- -

En els exemples anteriors ja hem fet ús de la propietat font per fer el text una mica més gran que la grandària predeterminada. Hi ha algunes propietats més que permeten ajustar la forma en què el text es mostra en el llenç:

- -
-
{{domxref("CanvasRenderingContext2D.font", "font = value")}}
-
L'estil de text actual que s'utilitza en dibuixar text. Aquesta cadena utilitza la mateixa sintaxi que la propietat CSS {{cssxref("font")}}. La font predeterminada és 10px sans-serif.
-
{{domxref("CanvasRenderingContext2D.textAlign", "textAlign = value")}}
-
Configuració de l'alineació del text. Valors possibles: start, end, left, right o center. El valor predeterminat és start.
-
{{domxref("CanvasRenderingContext2D.textBaseline", "textBaseline = value")}}
-
Configuració d'alineació de la línia de base. Valors possibles: top, hanging, middle, alphabetic, ideographic, bottom. El valor predeterminat és alphabetic.
-
{{domxref("CanvasRenderingContext2D.direction", "direction = value")}}
-
Direccionalitat. Valors possibles: ltr, rtl, inherit. El valor predeterminat és inherit.
-
- -

Aquestes propietats poden ser familiars, si heu treballat abans amb CSS.

- -

El següent diagrama del WHATWG mostra les diverses línies de base compatibles amb la propietat textBaseline.La part superior del quadrat em està aproximadament en la part superior dels glifos en una font, la línia de base penjant és on alguns glifos com आ estan ancorats, el mitjà està a mig camí entre la part superior del quadrat em i la part inferior del quadrat em,la línia de base alfabètica és on ancoren caràcters com Á, ÿ,
-f i Ω, la línia de base ideográfica és on glifos com 私 i 達 estan ancorats, i la part inferior del quadrat em està aproximadament en la part inferior dels glifos en una font. La part superior i inferior del quadre delimitador pot estar lluny d'aquestes línies de base, a causa que els glifos s'estenen molt més allà del quadrat em.

- -

Un exemple de textBaseline

- -

Editeu el codi següent i vegeu els canvis actualitzats en directe en el llenç:

- -
ctx.font = '48px serif';
-ctx.textBaseline = 'hanging';
-ctx.strokeText('Hello world', 0, 100);
-
- - - -

{{ EmbedLiveSample('Playable_code', 700, 360) }}

- -

Mesures avançades de text

- -

En el cas de necessitar obtenir més detalls sobre el text, el següent mètode permet mesurar-ho.

- -
-
{{domxref("CanvasRenderingContext2D.measureText", "measureText()")}}
-
Retorna un objecte {{domxref("TextMetrics")}} que conté l'amplada, en píxels, que serà el text especificat quan es dibuixi en l'estil de text actual.
-
- -

El següent fragment de codi mostra com es pot mesurar un text i obtenir la seva amplada

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-  var text = ctx.measureText('foo'); // TextMetrics object
-  text.width; // 16;
-}
-
- -

Notes específiques de Gecko

- -

En Gecko (el motor de representació de Firefox, Firefox OS i altres aplicacions basades en Mozilla), es van implementar algunes APIs prefixades en versions anteriors per dibuixar text en un llenç. Ara estan desaprovades i eliminades, ja no es garanteix el seu funcionament.

- -

{{PreviousNext("Web/API/Canvas_API/Tutorial/Applying_styles_and_colors", "Web/API/Canvas_API/Tutorial/Using_images")}}

- -
- - -
 
- -
 
-
diff --git a/files/ca/web/api/canvas_api/tutorial/drawing_text/index.html b/files/ca/web/api/canvas_api/tutorial/drawing_text/index.html new file mode 100644 index 0000000000..37b730176a --- /dev/null +++ b/files/ca/web/api/canvas_api/tutorial/drawing_text/index.html @@ -0,0 +1,165 @@ +--- +title: Dibuixar text +slug: Web/API/Canvas_API/Tutorial/Dibuixar_text +tags: + - Canvas + - Graphics + - Intermediate + - Tutorial +translation_of: Web/API/Canvas_API/Tutorial/Drawing_text +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Applying_styles_and_colors", "Web/API/Canvas_API/Tutorial/Using_images")}}
+ +
+

Després d'haver vist com aplicar estils i colors en el capítol anterior, ara veurem com dibuixar text sobre canvas.

+
+ +

Dibuixar text

+ +

El context de representació de canvas proporciona dos mètodes per representar el text:

+ +
+
{{domxref("CanvasRenderingContext2D.fillText", "fillText(text, x, y [, maxWidth])")}}
+
Omple un text donat en la posició donada (x, y). Opcionalment amb ample màxim per dibuixar.
+
{{domxref("CanvasRenderingContext2D.strokeText", "strokeText(text, x, y [, maxWidth])")}}
+
Traça un text donat en la posició donada (x, y). Opcionalment amb ample màxim per dibuixar.
+
+ +

Un exemple de fillText

+ +

El text s'omple usant l'actual fillStyle.

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  ctx.font = '48px serif';
+  ctx.fillText('Hello world', 10, 50);
+}
+ + + +

{{EmbedLiveSample("A_fillText_example", 310, 110)}}

+ +

Un exemple de strokeText

+ +

El text s'omple usant l'actual strokeStyle.

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  ctx.font = '48px serif';
+  ctx.strokeText('Hello world', 10, 50);
+}
+ + + +

{{EmbedLiveSample("A_strokeText_example", 310, 110)}}

+ +

Estil de text

+ +

En els exemples anteriors ja hem fet ús de la propietat font per fer el text una mica més gran que la grandària predeterminada. Hi ha algunes propietats més que permeten ajustar la forma en què el text es mostra en el llenç:

+ +
+
{{domxref("CanvasRenderingContext2D.font", "font = value")}}
+
L'estil de text actual que s'utilitza en dibuixar text. Aquesta cadena utilitza la mateixa sintaxi que la propietat CSS {{cssxref("font")}}. La font predeterminada és 10px sans-serif.
+
{{domxref("CanvasRenderingContext2D.textAlign", "textAlign = value")}}
+
Configuració de l'alineació del text. Valors possibles: start, end, left, right o center. El valor predeterminat és start.
+
{{domxref("CanvasRenderingContext2D.textBaseline", "textBaseline = value")}}
+
Configuració d'alineació de la línia de base. Valors possibles: top, hanging, middle, alphabetic, ideographic, bottom. El valor predeterminat és alphabetic.
+
{{domxref("CanvasRenderingContext2D.direction", "direction = value")}}
+
Direccionalitat. Valors possibles: ltr, rtl, inherit. El valor predeterminat és inherit.
+
+ +

Aquestes propietats poden ser familiars, si heu treballat abans amb CSS.

+ +

El següent diagrama del WHATWG mostra les diverses línies de base compatibles amb la propietat textBaseline.La part superior del quadrat em està aproximadament en la part superior dels glifos en una font, la línia de base penjant és on alguns glifos com आ estan ancorats, el mitjà està a mig camí entre la part superior del quadrat em i la part inferior del quadrat em,la línia de base alfabètica és on ancoren caràcters com Á, ÿ,
+f i Ω, la línia de base ideográfica és on glifos com 私 i 達 estan ancorats, i la part inferior del quadrat em està aproximadament en la part inferior dels glifos en una font. La part superior i inferior del quadre delimitador pot estar lluny d'aquestes línies de base, a causa que els glifos s'estenen molt més allà del quadrat em.

+ +

Un exemple de textBaseline

+ +

Editeu el codi següent i vegeu els canvis actualitzats en directe en el llenç:

+ +
ctx.font = '48px serif';
+ctx.textBaseline = 'hanging';
+ctx.strokeText('Hello world', 0, 100);
+
+ + + +

{{ EmbedLiveSample('Playable_code', 700, 360) }}

+ +

Mesures avançades de text

+ +

En el cas de necessitar obtenir més detalls sobre el text, el següent mètode permet mesurar-ho.

+ +
+
{{domxref("CanvasRenderingContext2D.measureText", "measureText()")}}
+
Retorna un objecte {{domxref("TextMetrics")}} que conté l'amplada, en píxels, que serà el text especificat quan es dibuixi en l'estil de text actual.
+
+ +

El següent fragment de codi mostra com es pot mesurar un text i obtenir la seva amplada

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  var text = ctx.measureText('foo'); // TextMetrics object
+  text.width; // 16;
+}
+
+ +

Notes específiques de Gecko

+ +

En Gecko (el motor de representació de Firefox, Firefox OS i altres aplicacions basades en Mozilla), es van implementar algunes APIs prefixades en versions anteriors per dibuixar text en un llenç. Ara estan desaprovades i eliminades, ja no es garanteix el seu funcionament.

+ +

{{PreviousNext("Web/API/Canvas_API/Tutorial/Applying_styles_and_colors", "Web/API/Canvas_API/Tutorial/Using_images")}}

+ +
+ + +
 
+ +
 
+
diff --git "a/files/ca/web/api/canvas_api/tutorial/manipular_p\303\255xels_amb_canvas/index.html" "b/files/ca/web/api/canvas_api/tutorial/manipular_p\303\255xels_amb_canvas/index.html" deleted file mode 100644 index d792e62ef0..0000000000 --- "a/files/ca/web/api/canvas_api/tutorial/manipular_p\303\255xels_amb_canvas/index.html" +++ /dev/null @@ -1,307 +0,0 @@ ---- -title: Manipular píxels amb canvas -slug: Web/API/Canvas_API/Tutorial/Manipular_píxels_amb_canvas -tags: - - Canvas - - Graphics - - Intermediate - - Tutorial -translation_of: Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas ---- -
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Advanced_animations", "Web/API/Canvas_API/Tutorial/Hit_regions_and_accessibility")}}
- -
-

Fins ara no hem mirat els píxels reals del nostre llenç. Amb l'objecte ImageData podem llegir i escriure directament una matriu de dades per manipular dades de píxels. També veurem com es pot controlar el suavitzat de la imatge (anti-aliasing) i com guardar imatges del vostre llenç.

-
- -

L'objecte ImageData

- -

L'objecte {{domxref("ImageData")}} representa les dades de píxels subjacents d'un àrea d'un objecte canvas. Conté els següents atributs de només lectura:

- -
-
width
-
L'amplada de la imatge en píxels.
-
height
-
L'alçada de la imatge en píxels.
-
data
-
Un {{jsxref("Uint8ClampedArray")}} representa una matriu unidimensional que conté les dades en l'ordre RGBA, amb valors enters entre 0 i 255 (inclosos).
-
- -

La propietat data retorna un {{jsxref("Uint8ClampedArray")}} al que es pot accedir per veure les dades de píxel en brut; cada píxel està representat per quatre valors d'un byte (vermell, verd, blau i alfa, en aquest ordre; és a dir, format "RGBA"). Cada component de color està representat per un nombre enter entre 0 i 255. A cada component se li assigna un índex consecutiu dins de la matriu, el component vermell del píxel esquerre superior és l'índex 0 dins de la matriu. Els píxels es segueixen d'esquerra a dreta, a després cap avall, a través de la matriu.

- -

El {{jsxref("Uint8ClampedArray")}} conté height × width × 4 bytes de dades, amb valors d'índex que van des de 0 fins a (height×width×4)-1.

- -

Per exemple, per llegir el valor del component blau del píxel a la columna 200, fila 50 de la imatge, fariem el següent:

- -
blueComponent = imageData.data[((50 * (imageData.width * 4)) + (200 * 4)) + 2];
- -

Si se li dóna un conjunt de coordenades (X i Y), es pot acabar fent alguna cosa com això:

- -
var xCoord = 50;
-var yCoord = 100;
-var canvasWidth = 1024;
-
-function getColorIndicesForCoord(x, y, width) {
-  var red = y * (width * 4) + x * 4;
-  return [red, red + 1, red + 2, red + 3];
-}
-
-var colorIndices = getColorIndicesForCoord(xCoord, yCoord, canvasWidth);
-
-var redIndex = colorIndices[0];
-var greenIndex = colorIndices[1];
-var blueIndex = colorIndices[2];
-var alphaIndex = colorIndices[3];
-
-var redForCoord = imageData.data[redIndex];
-var greenForCoord = imageData.data[greenIndex];
-var blueForCoord = imageData.data[blueIndex];
-var alphaForCoord = imageData.data[alphaIndex];
-
- -

O, si ES6 is apropiat:

- -
const xCoord = 50;
-const yCoord = 100;
-const canvasWidth = 1024;
-
-const getColorIndicesForCoord = (x, y, width) => {
-  const red = y * (width * 4) + x * 4;
-  return [red, red + 1, red + 2, red + 3];
-};
-
-const colorIndices = getColorIndicesForCoord(xCoord, yCoord, canvasWidth);
-
-const [redIndex, greenIndex, blueIndex, alphaIndex] = colorIndices;
-
- -

També es pot accedir a la mida de la matriu de píxels en bytes llegint l'atribut Uint8ClampedArray.length:

- -
var numBytes = imageData.data.length;
-
- -

Crear un objecte ImageData

- -

Per crear un nou objecte ImageData en blanc, hem d'utilitzar el mètode {{domxref("CanvasRenderingContext2D.createImageData", "createImageData()")}}. Hi ha dues versions del mètode createImageData():

- -
var myImageData = ctx.createImageData(width, height);
- -

Crea un nou objecte ImageData amb les dimensions especificades. Tots els píxels estan predefinits en negre transparent.

- -

També podem crear un nou objecte ImageData amb les mateixes dimensions que l'objecte especificat amb anotherImageData. Els píxels del nou objecte, estan tots predefinits en negre transparent. Això no copia les dades de la imatge!

- -
var myImageData = ctx.createImageData(anotherImageData);
- -

Obtenir les dades de píxels per a un context

- -

Per obtenir un objecte ImageData que contingui una còpia de les dades de píxel per a un context de llenç, podem utilitzar el mètodegetImageData():

- -
var myImageData = ctx.getImageData(left, top, width, height);
- -

Aquest mètode retorna un objecte ImageData que representa les dades de píxel per a l'àrea del llenç, les cantonades del qual estan representades pels punts (left,top), (left+width, top), (left, top+height) i (left+width, top+height). Les coordenades s'especifiquen en unitats d'espai en coordenades canvas.

- -
-

Nota: Qualsevol píxel fora del llenç es retorna com a negre transparent en l'objecte ImageData resultant.

-
- -

Aquest mètode també es demostra a l'article Manipulant vídeo usant canvas.

- -

Un selector de colors

- -

En aquest exemple estem usant el mètode getImageData() per mostrar el color sota el cursor del ratolí. Per a això, necessitem la posició actual del ratolí amb layerX i layerY, llavors busquem les dades de píxels en aquesta posició en la matriu de píxels que getImageData() ens proporciona. Finalment, utilitzem les dades de la matriu per establir un color de fons i un text en el <div> per mostrar el color.

- - - -
var img = new Image();
-img.crossOrigin = 'anonymous';
-img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
-var canvas = document.getElementById('canvas');
-var ctx = canvas.getContext('2d');
-img.onload = function() {
-  ctx.drawImage(img, 0, 0);
-  img.style.display = 'none';
-};
-var color = document.getElementById('color');
-function pick(event) {
-  var x = event.layerX;
-  var y = event.layerY;
-  var pixel = ctx.getImageData(x, y, 1, 1);
-  var data = pixel.data;
-  var rgba = 'rgba(' + data[0] + ', ' + data[1] +
-             ', ' + data[2] + ', ' + (data[3] / 255) + ')';
-  color.style.background =  rgba;
-  color.textContent = rgba;
-}
-canvas.addEventListener('mousemove', pick);
-
- -

{{ EmbedLiveSample('A_color_picker', 610, 240) }}

- -

Pintar dades de píxels en un context

- -

Utilitzem el mètode putImageData() per pintar dades de píxels en un context:

- -
ctx.putImageData(myImageData, dx, dy);
-
- -

Els paràmetres dx i dy indiquen les coordenades del dispositiu, dins del context en el que es pinta la cantonada superior esquerra de les dades de píxels que es vol dibuixar.

- -

Per exemple, per pintar tota la imatge representada per myImageData en la cantonada superior esquerra del context, simplement fem el següent:

- -
ctx.putImageData(myImageData, 0, 0);
-
- -

Escalat de grisos i inversió de colors

- -

En aquest exemple, iterem sobre tots els píxels per canviar els seus valors, després posem la matriu de píxels modificada, de nou, al llenç, utilitzant putImageData(). La funció invert, simplement, resta cada color del valor màxim 255. La funció grayscale, simplement, utilitza la mitjana de vermell, verd i blau. També es pot utilitzar una mitjana ponderada, donada per la fórmula x = 0.299r + 0.587g + 0.114b, per exemple. Vegeu Escala de grisos (Grayscale) a Wikipedia per obtenir més informació.

- - - -
var img = new Image();
-img.crossOrigin = 'anonymous';
-img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
-img.onload = function() {
-  draw(this);
-};
-
-function draw(img) {
-  var canvas = document.getElementById('canvas');
-  var ctx = canvas.getContext('2d');
-  ctx.drawImage(img, 0, 0);
-  img.style.display = 'none';
-  var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
-  var data = imageData.data;
-
-  var invert = function() {
-    for (var i = 0; i < data.length; i += 4) {
-      data[i]     = 255 - data[i];     // red
-      data[i + 1] = 255 - data[i + 1]; // green
-      data[i + 2] = 255 - data[i + 2]; // blue
-    }
-    ctx.putImageData(imageData, 0, 0);
-  };
-
-  var grayscale = function() {
-    for (var i = 0; i < data.length; i += 4) {
-      var avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
-      data[i]     = avg; // red
-      data[i + 1] = avg; // green
-      data[i + 2] = avg; // blue
-    }
-    ctx.putImageData(imageData, 0, 0);
-  };
-
-  var invertbtn = document.getElementById('invertbtn');
-  invertbtn.addEventListener('click', invert);
-  var grayscalebtn = document.getElementById('grayscalebtn');
-  grayscalebtn.addEventListener('click', grayscale);
-}
-
- -

{{ EmbedLiveSample('Grayscaling_and_inverting_colors', 330, 270) }}

- -

Ampliació i suavitzat

- -

Amb l'ajuda del mètode {{domxref("CanvasRenderingContext2D.drawImage", "drawImage()")}} un segon llenç i la propietat {{domxref("CanvasRenderingContext2D.imageSmoothingEnabled", "imageSmoothingEnabled")}}, podem ampliar la nostra imatge i veure els detalls.

- -

Obtenim la posició del ratolí, retallem una imatge de 5 píxels a l'esquerra i a dalt a 5 píxels a la dreta i a baix. A continuació, la copiem a un altre llenç i canviem la grandària de la imatge a la grandària que volguem. En el llenç de zoom, canviem la grandària de un retall de 10×10 píxels del llenç original a 200×200.

- -
zoomctx.drawImage(canvas,
-                  Math.abs(x - 5), Math.abs(y - 5),
-                  10, 10, 0, 0, 200, 200);
- -

Atès que el suavitzat (anti-aliasing) està habilitat per defecte, és possible que vulguem deshabilitar el suavitzat per veure els píxels clars. Alternant la casella de verificació es pot veure l'efecte de la propietat imageSmoothingEnabled (necessita prefixos per a diferents navegadors).

- - - - - -
var img = new Image();
-img.crossOrigin = 'anonymous';
-img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
-img.onload = function() {
-  draw(this);
-};
-
-function draw(img) {
-  var canvas = document.getElementById('canvas');
-  var ctx = canvas.getContext('2d');
-  ctx.drawImage(img, 0, 0);
-  img.style.display = 'none';
-  var zoomctx = document.getElementById('zoom').getContext('2d');
-
-  var smoothbtn = document.getElementById('smoothbtn');
-  var toggleSmoothing = function(event) {
-    zoomctx.imageSmoothingEnabled = this.checked;
-    zoomctx.mozImageSmoothingEnabled = this.checked;
-    zoomctx.webkitImageSmoothingEnabled = this.checked;
-    zoomctx.msImageSmoothingEnabled = this.checked;
-  };
-  smoothbtn.addEventListener('change', toggleSmoothing);
-
-  var zoom = function(event) {
-    var x = event.layerX;
-    var y = event.layerY;
-    zoomctx.drawImage(canvas,
-                      Math.abs(x - 5),
-                      Math.abs(y - 5),
-                      10, 10,
-                      0, 0,
-                      200, 200);
-  };
-
-  canvas.addEventListener('mousemove', zoom);
-}
- -

{{ EmbedLiveSample('Zoom_example', 620, 490) }}

- -

Guardar imatges

- -

El {{domxref("HTMLCanvasElement")}} proporciona un mètode toDataURL(), que és útil quan es guarden imatges. Retorna un URI de dades que conté una representació de la imatge en el format especificat pel paràmetre type (per defecte en PNG). La imatge retornada té una resolució de 96 dpi.

- -
-
{{domxref("HTMLCanvasElement.toDataURL", "canvas.toDataURL('image/png')")}}
-
Configuració per defecte. Crea una imatge PNG.
-
{{domxref("HTMLCanvasElement.toDataURL", "canvas.toDataURL('image/jpeg', quality)")}}
-
Crea una imatge JPG. Opcionalment, pot proporcionar una qualitat en el rang de 0 a 1, sent una d'elles la millor qualitat i amb 0 gairebé no recognoscible, però, petita en grandària d'arxiu.
-
- -

Una vegada que s'hagi generat un URI de dades des del llenç, es podrà utilitzar com a font de qualsevol {{HTMLElement("image")}} o posar-ho en un hipervíncle amb un atribut de descàrrega per guardar-ho en el disc, per exemple.

- -

També es pot crear un {{domxref("Blob")}} des del llenç.

- -
-
{{domxref("HTMLCanvasElement.toBlob", "canvas.toBlob(callback, type, encoderOptions)")}}
-
Crea un objecte Blob, representant la imatge continguda en el llenç.
-
- -

Vegeu també

- - - -

{{PreviousNext("Web/API/Canvas_API/Tutorial/Advanced_animations", "Web/API/Canvas_API/Tutorial/Hit_regions_and_accessibility")}}

diff --git a/files/ca/web/api/canvas_api/tutorial/pixel_manipulation_with_canvas/index.html b/files/ca/web/api/canvas_api/tutorial/pixel_manipulation_with_canvas/index.html new file mode 100644 index 0000000000..d792e62ef0 --- /dev/null +++ b/files/ca/web/api/canvas_api/tutorial/pixel_manipulation_with_canvas/index.html @@ -0,0 +1,307 @@ +--- +title: Manipular píxels amb canvas +slug: Web/API/Canvas_API/Tutorial/Manipular_píxels_amb_canvas +tags: + - Canvas + - Graphics + - Intermediate + - Tutorial +translation_of: Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Advanced_animations", "Web/API/Canvas_API/Tutorial/Hit_regions_and_accessibility")}}
+ +
+

Fins ara no hem mirat els píxels reals del nostre llenç. Amb l'objecte ImageData podem llegir i escriure directament una matriu de dades per manipular dades de píxels. També veurem com es pot controlar el suavitzat de la imatge (anti-aliasing) i com guardar imatges del vostre llenç.

+
+ +

L'objecte ImageData

+ +

L'objecte {{domxref("ImageData")}} representa les dades de píxels subjacents d'un àrea d'un objecte canvas. Conté els següents atributs de només lectura:

+ +
+
width
+
L'amplada de la imatge en píxels.
+
height
+
L'alçada de la imatge en píxels.
+
data
+
Un {{jsxref("Uint8ClampedArray")}} representa una matriu unidimensional que conté les dades en l'ordre RGBA, amb valors enters entre 0 i 255 (inclosos).
+
+ +

La propietat data retorna un {{jsxref("Uint8ClampedArray")}} al que es pot accedir per veure les dades de píxel en brut; cada píxel està representat per quatre valors d'un byte (vermell, verd, blau i alfa, en aquest ordre; és a dir, format "RGBA"). Cada component de color està representat per un nombre enter entre 0 i 255. A cada component se li assigna un índex consecutiu dins de la matriu, el component vermell del píxel esquerre superior és l'índex 0 dins de la matriu. Els píxels es segueixen d'esquerra a dreta, a després cap avall, a través de la matriu.

+ +

El {{jsxref("Uint8ClampedArray")}} conté height × width × 4 bytes de dades, amb valors d'índex que van des de 0 fins a (height×width×4)-1.

+ +

Per exemple, per llegir el valor del component blau del píxel a la columna 200, fila 50 de la imatge, fariem el següent:

+ +
blueComponent = imageData.data[((50 * (imageData.width * 4)) + (200 * 4)) + 2];
+ +

Si se li dóna un conjunt de coordenades (X i Y), es pot acabar fent alguna cosa com això:

+ +
var xCoord = 50;
+var yCoord = 100;
+var canvasWidth = 1024;
+
+function getColorIndicesForCoord(x, y, width) {
+  var red = y * (width * 4) + x * 4;
+  return [red, red + 1, red + 2, red + 3];
+}
+
+var colorIndices = getColorIndicesForCoord(xCoord, yCoord, canvasWidth);
+
+var redIndex = colorIndices[0];
+var greenIndex = colorIndices[1];
+var blueIndex = colorIndices[2];
+var alphaIndex = colorIndices[3];
+
+var redForCoord = imageData.data[redIndex];
+var greenForCoord = imageData.data[greenIndex];
+var blueForCoord = imageData.data[blueIndex];
+var alphaForCoord = imageData.data[alphaIndex];
+
+ +

O, si ES6 is apropiat:

+ +
const xCoord = 50;
+const yCoord = 100;
+const canvasWidth = 1024;
+
+const getColorIndicesForCoord = (x, y, width) => {
+  const red = y * (width * 4) + x * 4;
+  return [red, red + 1, red + 2, red + 3];
+};
+
+const colorIndices = getColorIndicesForCoord(xCoord, yCoord, canvasWidth);
+
+const [redIndex, greenIndex, blueIndex, alphaIndex] = colorIndices;
+
+ +

També es pot accedir a la mida de la matriu de píxels en bytes llegint l'atribut Uint8ClampedArray.length:

+ +
var numBytes = imageData.data.length;
+
+ +

Crear un objecte ImageData

+ +

Per crear un nou objecte ImageData en blanc, hem d'utilitzar el mètode {{domxref("CanvasRenderingContext2D.createImageData", "createImageData()")}}. Hi ha dues versions del mètode createImageData():

+ +
var myImageData = ctx.createImageData(width, height);
+ +

Crea un nou objecte ImageData amb les dimensions especificades. Tots els píxels estan predefinits en negre transparent.

+ +

També podem crear un nou objecte ImageData amb les mateixes dimensions que l'objecte especificat amb anotherImageData. Els píxels del nou objecte, estan tots predefinits en negre transparent. Això no copia les dades de la imatge!

+ +
var myImageData = ctx.createImageData(anotherImageData);
+ +

Obtenir les dades de píxels per a un context

+ +

Per obtenir un objecte ImageData que contingui una còpia de les dades de píxel per a un context de llenç, podem utilitzar el mètodegetImageData():

+ +
var myImageData = ctx.getImageData(left, top, width, height);
+ +

Aquest mètode retorna un objecte ImageData que representa les dades de píxel per a l'àrea del llenç, les cantonades del qual estan representades pels punts (left,top), (left+width, top), (left, top+height) i (left+width, top+height). Les coordenades s'especifiquen en unitats d'espai en coordenades canvas.

+ +
+

Nota: Qualsevol píxel fora del llenç es retorna com a negre transparent en l'objecte ImageData resultant.

+
+ +

Aquest mètode també es demostra a l'article Manipulant vídeo usant canvas.

+ +

Un selector de colors

+ +

En aquest exemple estem usant el mètode getImageData() per mostrar el color sota el cursor del ratolí. Per a això, necessitem la posició actual del ratolí amb layerX i layerY, llavors busquem les dades de píxels en aquesta posició en la matriu de píxels que getImageData() ens proporciona. Finalment, utilitzem les dades de la matriu per establir un color de fons i un text en el <div> per mostrar el color.

+ + + +
var img = new Image();
+img.crossOrigin = 'anonymous';
+img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
+var canvas = document.getElementById('canvas');
+var ctx = canvas.getContext('2d');
+img.onload = function() {
+  ctx.drawImage(img, 0, 0);
+  img.style.display = 'none';
+};
+var color = document.getElementById('color');
+function pick(event) {
+  var x = event.layerX;
+  var y = event.layerY;
+  var pixel = ctx.getImageData(x, y, 1, 1);
+  var data = pixel.data;
+  var rgba = 'rgba(' + data[0] + ', ' + data[1] +
+             ', ' + data[2] + ', ' + (data[3] / 255) + ')';
+  color.style.background =  rgba;
+  color.textContent = rgba;
+}
+canvas.addEventListener('mousemove', pick);
+
+ +

{{ EmbedLiveSample('A_color_picker', 610, 240) }}

+ +

Pintar dades de píxels en un context

+ +

Utilitzem el mètode putImageData() per pintar dades de píxels en un context:

+ +
ctx.putImageData(myImageData, dx, dy);
+
+ +

Els paràmetres dx i dy indiquen les coordenades del dispositiu, dins del context en el que es pinta la cantonada superior esquerra de les dades de píxels que es vol dibuixar.

+ +

Per exemple, per pintar tota la imatge representada per myImageData en la cantonada superior esquerra del context, simplement fem el següent:

+ +
ctx.putImageData(myImageData, 0, 0);
+
+ +

Escalat de grisos i inversió de colors

+ +

En aquest exemple, iterem sobre tots els píxels per canviar els seus valors, després posem la matriu de píxels modificada, de nou, al llenç, utilitzant putImageData(). La funció invert, simplement, resta cada color del valor màxim 255. La funció grayscale, simplement, utilitza la mitjana de vermell, verd i blau. També es pot utilitzar una mitjana ponderada, donada per la fórmula x = 0.299r + 0.587g + 0.114b, per exemple. Vegeu Escala de grisos (Grayscale) a Wikipedia per obtenir més informació.

+ + + +
var img = new Image();
+img.crossOrigin = 'anonymous';
+img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
+img.onload = function() {
+  draw(this);
+};
+
+function draw(img) {
+  var canvas = document.getElementById('canvas');
+  var ctx = canvas.getContext('2d');
+  ctx.drawImage(img, 0, 0);
+  img.style.display = 'none';
+  var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
+  var data = imageData.data;
+
+  var invert = function() {
+    for (var i = 0; i < data.length; i += 4) {
+      data[i]     = 255 - data[i];     // red
+      data[i + 1] = 255 - data[i + 1]; // green
+      data[i + 2] = 255 - data[i + 2]; // blue
+    }
+    ctx.putImageData(imageData, 0, 0);
+  };
+
+  var grayscale = function() {
+    for (var i = 0; i < data.length; i += 4) {
+      var avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
+      data[i]     = avg; // red
+      data[i + 1] = avg; // green
+      data[i + 2] = avg; // blue
+    }
+    ctx.putImageData(imageData, 0, 0);
+  };
+
+  var invertbtn = document.getElementById('invertbtn');
+  invertbtn.addEventListener('click', invert);
+  var grayscalebtn = document.getElementById('grayscalebtn');
+  grayscalebtn.addEventListener('click', grayscale);
+}
+
+ +

{{ EmbedLiveSample('Grayscaling_and_inverting_colors', 330, 270) }}

+ +

Ampliació i suavitzat

+ +

Amb l'ajuda del mètode {{domxref("CanvasRenderingContext2D.drawImage", "drawImage()")}} un segon llenç i la propietat {{domxref("CanvasRenderingContext2D.imageSmoothingEnabled", "imageSmoothingEnabled")}}, podem ampliar la nostra imatge i veure els detalls.

+ +

Obtenim la posició del ratolí, retallem una imatge de 5 píxels a l'esquerra i a dalt a 5 píxels a la dreta i a baix. A continuació, la copiem a un altre llenç i canviem la grandària de la imatge a la grandària que volguem. En el llenç de zoom, canviem la grandària de un retall de 10×10 píxels del llenç original a 200×200.

+ +
zoomctx.drawImage(canvas,
+                  Math.abs(x - 5), Math.abs(y - 5),
+                  10, 10, 0, 0, 200, 200);
+ +

Atès que el suavitzat (anti-aliasing) està habilitat per defecte, és possible que vulguem deshabilitar el suavitzat per veure els píxels clars. Alternant la casella de verificació es pot veure l'efecte de la propietat imageSmoothingEnabled (necessita prefixos per a diferents navegadors).

+ + + + + +
var img = new Image();
+img.crossOrigin = 'anonymous';
+img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
+img.onload = function() {
+  draw(this);
+};
+
+function draw(img) {
+  var canvas = document.getElementById('canvas');
+  var ctx = canvas.getContext('2d');
+  ctx.drawImage(img, 0, 0);
+  img.style.display = 'none';
+  var zoomctx = document.getElementById('zoom').getContext('2d');
+
+  var smoothbtn = document.getElementById('smoothbtn');
+  var toggleSmoothing = function(event) {
+    zoomctx.imageSmoothingEnabled = this.checked;
+    zoomctx.mozImageSmoothingEnabled = this.checked;
+    zoomctx.webkitImageSmoothingEnabled = this.checked;
+    zoomctx.msImageSmoothingEnabled = this.checked;
+  };
+  smoothbtn.addEventListener('change', toggleSmoothing);
+
+  var zoom = function(event) {
+    var x = event.layerX;
+    var y = event.layerY;
+    zoomctx.drawImage(canvas,
+                      Math.abs(x - 5),
+                      Math.abs(y - 5),
+                      10, 10,
+                      0, 0,
+                      200, 200);
+  };
+
+  canvas.addEventListener('mousemove', zoom);
+}
+ +

{{ EmbedLiveSample('Zoom_example', 620, 490) }}

+ +

Guardar imatges

+ +

El {{domxref("HTMLCanvasElement")}} proporciona un mètode toDataURL(), que és útil quan es guarden imatges. Retorna un URI de dades que conté una representació de la imatge en el format especificat pel paràmetre type (per defecte en PNG). La imatge retornada té una resolució de 96 dpi.

+ +
+
{{domxref("HTMLCanvasElement.toDataURL", "canvas.toDataURL('image/png')")}}
+
Configuració per defecte. Crea una imatge PNG.
+
{{domxref("HTMLCanvasElement.toDataURL", "canvas.toDataURL('image/jpeg', quality)")}}
+
Crea una imatge JPG. Opcionalment, pot proporcionar una qualitat en el rang de 0 a 1, sent una d'elles la millor qualitat i amb 0 gairebé no recognoscible, però, petita en grandària d'arxiu.
+
+ +

Una vegada que s'hagi generat un URI de dades des del llenç, es podrà utilitzar com a font de qualsevol {{HTMLElement("image")}} o posar-ho en un hipervíncle amb un atribut de descàrrega per guardar-ho en el disc, per exemple.

+ +

També es pot crear un {{domxref("Blob")}} des del llenç.

+ +
+
{{domxref("HTMLCanvasElement.toBlob", "canvas.toBlob(callback, type, encoderOptions)")}}
+
Crea un objecte Blob, representant la imatge continguda en el llenç.
+
+ +

Vegeu també

+ + + +

{{PreviousNext("Web/API/Canvas_API/Tutorial/Advanced_animations", "Web/API/Canvas_API/Tutorial/Hit_regions_and_accessibility")}}

diff --git a/files/ca/web/api/canvas_api/tutorial/transformacions/index.html b/files/ca/web/api/canvas_api/tutorial/transformacions/index.html deleted file mode 100644 index 2958d40498..0000000000 --- a/files/ca/web/api/canvas_api/tutorial/transformacions/index.html +++ /dev/null @@ -1,290 +0,0 @@ ---- -title: Transformacions -slug: Web/API/Canvas_API/Tutorial/Transformacions -tags: - - Canvas - - Graphics - - Guide - - HTML - - HTML5 - - Intermediate - - Web -translation_of: Web/API/Canvas_API/Tutorial/Transformations ---- -
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Using_images", "Web/API/Canvas_API/Tutorial/Compositing")}}
- -
Anteriorment en aquest tutorial hem après sobre la graella de canvas i l'espai de coordenades. Fins ara, només usàvem la graella per defecte i canviàvem la grandària del llenç per a les nostres necessitats. Amb les transformacions, hi ha formes més poderoses de traslladar l'origen a una posició diferent, girar la graella i fins i tot escalar-la.
- -

Guardar i restaurar l'estat

- -

Abans de veure els mètodes de transformació, vegem altres dos mètodes que són indispensables una vegada que comencem a generar dibuixos cada vegada més complexos.

- -
-
{{domxref("CanvasRenderingContext2D.save", "save()")}}
-
Guarda tot l'estat del llenç.
-
{{domxref("CanvasRenderingContext2D.restore", "restore()")}}
-
Restaura l'estat del llenç guardat més recent.
-
- -

Els estats del llenç s'emmagatzemen en una pila. Cada vegada que es crida al mètode save() l'estat del dibuix actual es mou a la pila. L'estat d'un dibuix consisteix de

- - - -

Es pot cridar al mètode save() tantes vegades com es vulgui. Cada vegada que es crida al mètode restore() l'últim estat desat s'elimina de la pila i es restauren tots les configuracions guardades.

- -

Un exemple de save i restore de l'estat del llenç

- -

Aquest exemple intenta il·lustrar com funciona la pila d'estats del dibuix en dibuixar un conjunt de rectangles consecutius.

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-
-  ctx.fillRect(0, 0, 150, 150);   // Dibuixa un rectangle amb la configuració per defecte
-  ctx.save();                  // Guarda el estat predeterminat
-
-  ctx.fillStyle = '#09F';      // Es fan canvis a la configuració
-  ctx.fillRect(15, 15, 120, 120); // Es dibuixa un rectangle amb la nova configuració
-
-  ctx.save();                  // Es guarda el estat actual
-  ctx.fillStyle = '#FFF';      // Es fan canvis a la configuració
-  ctx.globalAlpha = 0.5;
-  ctx.fillRect(30, 30, 90, 90);   // Es dibuixa un rectangle amb la nova configuració
-
-  ctx.restore();               // Es restaura el estat anterior
-  ctx.fillRect(45, 45, 60, 60);   // Es dibuixa un rectangle amb la configuració restaurada
-
-  ctx.restore();               // Es restaura el estat original
-  ctx.fillRect(60, 60, 30, 30);   // Es dibuixa un rectangle amb la configuració restaurada
- - - -

El primer pas és dibuixar un gran rectangle amb la configuració predeterminada.  A continuació guardem aquest estat i fem canvis en el color de farcit. Després dibuixem el segon rectangle blau i més petit i guardem l'estat. De nou canviem algunes configuracions de dibuix i dibuixem el tercer rectangle blanc semitransparent.

- -

Fins ara, això és bastant similar al que hem fet en les seccions anteriors. No obstant això, una vegada que cridem a la primera instrucció restore() l'estat del dibuix superior s'elimina de la pila i es restaura la configuració. Si no haguéssim guardat l'estat usant save(), hauríem de canviar el color de farcit i la transparència manualment, per tornar a l'estat anterior. Això seria fàcil per a dues propietats, però si tenim més que això, el nostre codi es faria molt llarg, molt ràpid.

- -

Quan es crida a la segona instrucció restore(), es restaura l'estat original (el que hem configurat abans de la primera crida save) i l'últim rectangle es dibuixa de nou en negre.

- -

{{EmbedLiveSample("A_save_and_restore_canvas_state_example", "180", "180", "https://mdn.mozillademos.org/files/249/Canvas_savestate.png")}}

- -

Traslladar

- -

El primer dels mètodes de transformació que veurem és translate(). Aquest mètode s'utilitza per moure el llenç i el seu origen a un punt diferent de la graella.

- -
-
{{domxref("CanvasRenderingContext2D.translate", "translate(x, y)")}}
-
Mou el llenç i el seu origen en la graella. x indica la distància horitzontal a moure, i y indica quanta distància s'ha de moure la graella verticalment.
-
- -

És una bona idea guardar l'estat del llenç abans de fer qualsevol transformació. En la majoria dels casos, és més fàcil cridar al mètode restore, que haver de fer una traslació inversa per tornar a l'estat original. També, si estem trasladant dins d'un bucle i no guardem i restaurem l'estat del llenç, pot ser que acabem perdent part del dibuix, ja que es va dibuixar fora de la vora del llenç.

- -

Un exemple de translate

- -

Aquest exemple demostra alguns dels beneficis de traslladar l'origen del llenç. Sense el mètode translate(), tots els rectangles es dibuixarien en la mateixa posició (0,0). El mètode translate(), també ens dóna la llibertat de col·locar el rectangle en qualsevol lloc del llenç, sense haver d'ajustar manualment les coordenades en la funció fillRect(). Això fa que sigui una mica més fàcil d'entendre i usar.

- -

En la funció draw(), cridem a la funció fillRect() nou vegades, usant dos  bucles for. En cada bucle, el llenç es trasllada, es dibuixa el rectangle i el llenç torna al seu estat original. Observem com la crida a fillRect() usa les mateixes coordenades cada vegada, confiant en translate() per ajustar la posició del dibuix.

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-  for (var i = 0; i < 3; i++) {
-    for (var j = 0; j < 3; j++) {
-      ctx.save();
-      ctx.fillStyle = 'rgb(' + (51 * i) + ', ' + (255 - 51 * i) + ', 255)';
-      ctx.translate(10 + j * 50, 10 + i * 50);
-      ctx.fillRect(0, 0, 25, 25);
-      ctx.restore();
-    }
-  }
-}
-
- - - -

{{EmbedLiveSample("A_translate_example", "160", "160", "https://mdn.mozillademos.org/files/9857/translate.png")}}

- -

Girar

- -

El segon mètode de transformació és rotate(). Se usa per girar el llenç al voltant de l'origen actual.

- -
-
{{domxref("CanvasRenderingContext2D.rotate", "rotate(angle)")}}
-
Gira el llenç en sentit horari, al voltant de l'origen actual pel nombre d'angle de radiants.
-
- -

El punt central de gir és sempre l'origen del llenç. Per canviar el punt central, necessitarem moure el llenç usant el mètode translate().

- -

Un exemple de rotate

- -

En aquest exemple, usarem el mètode rotate() para girar primer un rectangle des de l'origen del llenç, i després des del centre del rectangle mateix amb l'ajuda de translate().

- -
-

Recordatori: Els angles estan en radiants, no en graus. Per fer la conversació, estem usant: radians = (Math.PI/180)*degrees.

-
- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-
-  // rectangles esquerra, giren a partir d'origen del llenç
-  ctx.save();
-  // rect blau
-  ctx.fillStyle = '#0095DD';
-  ctx.fillRect(30, 30, 100, 100);
-  ctx.rotate((Math.PI / 180) * 25);
-  // grey rect
-  ctx.fillStyle = '#4D4E53';
-  ctx.fillRect(30, 30, 100, 100);
-  ctx.restore();
-
-  // rectangles drets, giren des del centre del rectangle
-  // dibuixa rect blau
-  ctx.fillStyle = '#0095DD';
-  ctx.fillRect(150, 30, 100, 100);
-
-  ctx.translate(200, 80); // trasllada al rectangle central
-                          // x = x + 0.5 * width
-                          // y = y + 0.5 * height
-  ctx.rotate((Math.PI / 180) * 25); // gira
-  ctx.translate(-200, -80); // traslladar de nou
-
-  // dibuixa rect gris
-  ctx.fillStyle = '#4D4E53';
-  ctx.fillRect(150, 30, 100, 100);
-}
-
- -

Per girar el rectangle al voltant del seu propi centre, traslladem el llenç al centre del rectangle, després girem el llenç i tornem a traslladar el llenç a 0,0, i a continuació dibuixem el rectangle.

- - - -

{{EmbedLiveSample("A_rotate_example", "310", "210", "https://mdn.mozillademos.org/files/9859/rotate.png")}}

- -

Escalar

- -

El següent mètode de transformació és l'escalat. Ho usem per augmentar o disminuir les unitats en la graella del llenç. Això es pot utilitzar per dibuixar formes i mapes de bits reduïts o ampliats.

- -
-
{{domxref("CanvasRenderingContext2D.scale", "scale(x, y)")}}
-
Escala les unitats del llenç, per x horitzontalment i per y verticalment. Tots dos paràmetres són nombres reals. Els valors inferiors a 1.0 redueixen la grandària de la unitat i els valors superiors a 1.0 augmenten la grandària de la unitat. Els valors a 1.0 deixen les unitats de la mateixa grandària.
-
- -

Usant nombres negatius es pot fer la replica d'eixos (per exemple, usant translate(0,canvas.height); scale(1,-1); tindrem el conegut sistema de coordenades cartesianes, amb l'origen en la cantonada inferior esquerra).

- -

Per defecte, una unitat en el llenç és exactament un píxel. Si apliquem, per exemple, un factor d'escala de 0.5, la unitat resultant es convertirà en 0.5 píxels i per tant les formes es dibuixaran a meitat de la seva grandària. De manera similar, si s'ajusta el factor d'escala a 2.0, la grandària de la unitat augmentarà i una unitat ara es converteix en dos píxels. Això dona com a resultat que les formes es dibuixin dues vegades més grans.

- -

Un exemple de scale

- -

En aquest últim exemple, dibuixarem formes amb diferents factors d'escala.

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-
-  // dibuixar un rectangle senzill, però escalar-lo.
-  ctx.save();
-  ctx.scale(10, 3);
-  ctx.fillRect(1, 10, 10, 10);
-  ctx.restore();
-
-  // mirror horizontally
-  ctx.scale(-1, 1);
-  ctx.font = '48px serif';
-  ctx.fillText('MDN', -135, 120);
-}
-
-
- - - -

{{EmbedLiveSample("A_scale_example", "160", "160", "https://mdn.mozillademos.org/files/9861/scale.png")}}

- -

Transformar

- -

Finalment, els següents mètodes de transformació permeten modificar directament la matriu de transformació.

- -
-
{{domxref("CanvasRenderingContext2D.transform", "transform(a, b, c, d, e, f)")}}
-
Multiplica la matriu de transformació actual amb la matriu descrita pels seus arguments. La matriu de transformació és descrita per: [acebdf001]\left[ \begin{array}{ccc} a & c & e \\ b & d & f \\ 0 & 0 & 1 \end{array} \right]
-
- -
-
Si qualsevol dels arguments és Infinity, la matriu de transformació ha de ser marcada com a infinita en lloc que el mètode llanci una excepció.
-
- -

Els paràmetres d'aquesta funció són:

- -
-
a (m11)
-
Escalat horitzontal.
-
b (m12)
-
Desviació Horizontal.
-
c (m21)
-
Desviació Vertical.
-
d (m22)
-
Escalat Vertical.
-
e (dx)
-
Moviment Horizontal.
-
f (dy)
-
Moviment Vertical.
-
{{domxref("CanvasRenderingContext2D.setTransform", "setTransform(a, b, c, d, e, f)")}}
-
Reinicia la transformació actual a la matriu d'identitat i, a continuació, invoca el mètode transform() amb els mateixos arguments. Això, bàsicament, desfà la transformació actual, i després estableix la transformació especificada, tot en un sol pas.
-
{{domxref("CanvasRenderingContext2D.resetTransform", "resetTransform()")}}
-
Reinicia la transformació actual a la matriu d'identitat. Això és el mateix que cridar: ctx.setTransform(1, 0, 0, 1, 0, 0);
-
- -

Exemple de transform i setTransform

- -
function draw() {
-  var ctx = document.getElementById('canvas').getContext('2d');
-
-  var sin = Math.sin(Math.PI / 6);
-  var cos = Math.cos(Math.PI / 6);
-  ctx.translate(100, 100);
-  var c = 0;
-  for (var i = 0; i <= 12; i++) {
-    c = Math.floor(255 / 12 * i);
-    ctx.fillStyle = 'rgb(' + c + ', ' + c + ', ' + c + ')';
-    ctx.fillRect(0, 0, 100, 10);
-    ctx.transform(cos, sin, -sin, cos, 0, 0);
-  }
-
-  ctx.setTransform(-1, 0, 0, 1, 100, 100);
-  ctx.fillStyle = 'rgba(255, 128, 255, 0.5)';
-  ctx.fillRect(0, 50, 100, 100);
-}
-
- - - -

{{EmbedLiveSample("Example_for_transform_and_setTransform", "230", "280", "https://mdn.mozillademos.org/files/255/Canvas_transform.png")}}

- -

{{PreviousNext("Web/API/Canvas_API/Tutorial/Using_images", "Web/API/Canvas_API/Tutorial/Compositing")}}

- -
- - -
 
- -
 
-
diff --git a/files/ca/web/api/canvas_api/tutorial/transformations/index.html b/files/ca/web/api/canvas_api/tutorial/transformations/index.html new file mode 100644 index 0000000000..2958d40498 --- /dev/null +++ b/files/ca/web/api/canvas_api/tutorial/transformations/index.html @@ -0,0 +1,290 @@ +--- +title: Transformacions +slug: Web/API/Canvas_API/Tutorial/Transformacions +tags: + - Canvas + - Graphics + - Guide + - HTML + - HTML5 + - Intermediate + - Web +translation_of: Web/API/Canvas_API/Tutorial/Transformations +--- +
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Using_images", "Web/API/Canvas_API/Tutorial/Compositing")}}
+ +
Anteriorment en aquest tutorial hem après sobre la graella de canvas i l'espai de coordenades. Fins ara, només usàvem la graella per defecte i canviàvem la grandària del llenç per a les nostres necessitats. Amb les transformacions, hi ha formes més poderoses de traslladar l'origen a una posició diferent, girar la graella i fins i tot escalar-la.
+ +

Guardar i restaurar l'estat

+ +

Abans de veure els mètodes de transformació, vegem altres dos mètodes que són indispensables una vegada que comencem a generar dibuixos cada vegada més complexos.

+ +
+
{{domxref("CanvasRenderingContext2D.save", "save()")}}
+
Guarda tot l'estat del llenç.
+
{{domxref("CanvasRenderingContext2D.restore", "restore()")}}
+
Restaura l'estat del llenç guardat més recent.
+
+ +

Els estats del llenç s'emmagatzemen en una pila. Cada vegada que es crida al mètode save() l'estat del dibuix actual es mou a la pila. L'estat d'un dibuix consisteix de

+ + + +

Es pot cridar al mètode save() tantes vegades com es vulgui. Cada vegada que es crida al mètode restore() l'últim estat desat s'elimina de la pila i es restauren tots les configuracions guardades.

+ +

Un exemple de save i restore de l'estat del llenç

+ +

Aquest exemple intenta il·lustrar com funciona la pila d'estats del dibuix en dibuixar un conjunt de rectangles consecutius.

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  ctx.fillRect(0, 0, 150, 150);   // Dibuixa un rectangle amb la configuració per defecte
+  ctx.save();                  // Guarda el estat predeterminat
+
+  ctx.fillStyle = '#09F';      // Es fan canvis a la configuració
+  ctx.fillRect(15, 15, 120, 120); // Es dibuixa un rectangle amb la nova configuració
+
+  ctx.save();                  // Es guarda el estat actual
+  ctx.fillStyle = '#FFF';      // Es fan canvis a la configuració
+  ctx.globalAlpha = 0.5;
+  ctx.fillRect(30, 30, 90, 90);   // Es dibuixa un rectangle amb la nova configuració
+
+  ctx.restore();               // Es restaura el estat anterior
+  ctx.fillRect(45, 45, 60, 60);   // Es dibuixa un rectangle amb la configuració restaurada
+
+  ctx.restore();               // Es restaura el estat original
+  ctx.fillRect(60, 60, 30, 30);   // Es dibuixa un rectangle amb la configuració restaurada
+ + + +

El primer pas és dibuixar un gran rectangle amb la configuració predeterminada.  A continuació guardem aquest estat i fem canvis en el color de farcit. Després dibuixem el segon rectangle blau i més petit i guardem l'estat. De nou canviem algunes configuracions de dibuix i dibuixem el tercer rectangle blanc semitransparent.

+ +

Fins ara, això és bastant similar al que hem fet en les seccions anteriors. No obstant això, una vegada que cridem a la primera instrucció restore() l'estat del dibuix superior s'elimina de la pila i es restaura la configuració. Si no haguéssim guardat l'estat usant save(), hauríem de canviar el color de farcit i la transparència manualment, per tornar a l'estat anterior. Això seria fàcil per a dues propietats, però si tenim més que això, el nostre codi es faria molt llarg, molt ràpid.

+ +

Quan es crida a la segona instrucció restore(), es restaura l'estat original (el que hem configurat abans de la primera crida save) i l'últim rectangle es dibuixa de nou en negre.

+ +

{{EmbedLiveSample("A_save_and_restore_canvas_state_example", "180", "180", "https://mdn.mozillademos.org/files/249/Canvas_savestate.png")}}

+ +

Traslladar

+ +

El primer dels mètodes de transformació que veurem és translate(). Aquest mètode s'utilitza per moure el llenç i el seu origen a un punt diferent de la graella.

+ +
+
{{domxref("CanvasRenderingContext2D.translate", "translate(x, y)")}}
+
Mou el llenç i el seu origen en la graella. x indica la distància horitzontal a moure, i y indica quanta distància s'ha de moure la graella verticalment.
+
+ +

És una bona idea guardar l'estat del llenç abans de fer qualsevol transformació. En la majoria dels casos, és més fàcil cridar al mètode restore, que haver de fer una traslació inversa per tornar a l'estat original. També, si estem trasladant dins d'un bucle i no guardem i restaurem l'estat del llenç, pot ser que acabem perdent part del dibuix, ja que es va dibuixar fora de la vora del llenç.

+ +

Un exemple de translate

+ +

Aquest exemple demostra alguns dels beneficis de traslladar l'origen del llenç. Sense el mètode translate(), tots els rectangles es dibuixarien en la mateixa posició (0,0). El mètode translate(), també ens dóna la llibertat de col·locar el rectangle en qualsevol lloc del llenç, sense haver d'ajustar manualment les coordenades en la funció fillRect(). Això fa que sigui una mica més fàcil d'entendre i usar.

+ +

En la funció draw(), cridem a la funció fillRect() nou vegades, usant dos  bucles for. En cada bucle, el llenç es trasllada, es dibuixa el rectangle i el llenç torna al seu estat original. Observem com la crida a fillRect() usa les mateixes coordenades cada vegada, confiant en translate() per ajustar la posició del dibuix.

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+  for (var i = 0; i < 3; i++) {
+    for (var j = 0; j < 3; j++) {
+      ctx.save();
+      ctx.fillStyle = 'rgb(' + (51 * i) + ', ' + (255 - 51 * i) + ', 255)';
+      ctx.translate(10 + j * 50, 10 + i * 50);
+      ctx.fillRect(0, 0, 25, 25);
+      ctx.restore();
+    }
+  }
+}
+
+ + + +

{{EmbedLiveSample("A_translate_example", "160", "160", "https://mdn.mozillademos.org/files/9857/translate.png")}}

+ +

Girar

+ +

El segon mètode de transformació és rotate(). Se usa per girar el llenç al voltant de l'origen actual.

+ +
+
{{domxref("CanvasRenderingContext2D.rotate", "rotate(angle)")}}
+
Gira el llenç en sentit horari, al voltant de l'origen actual pel nombre d'angle de radiants.
+
+ +

El punt central de gir és sempre l'origen del llenç. Per canviar el punt central, necessitarem moure el llenç usant el mètode translate().

+ +

Un exemple de rotate

+ +

En aquest exemple, usarem el mètode rotate() para girar primer un rectangle des de l'origen del llenç, i després des del centre del rectangle mateix amb l'ajuda de translate().

+ +
+

Recordatori: Els angles estan en radiants, no en graus. Per fer la conversació, estem usant: radians = (Math.PI/180)*degrees.

+
+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  // rectangles esquerra, giren a partir d'origen del llenç
+  ctx.save();
+  // rect blau
+  ctx.fillStyle = '#0095DD';
+  ctx.fillRect(30, 30, 100, 100);
+  ctx.rotate((Math.PI / 180) * 25);
+  // grey rect
+  ctx.fillStyle = '#4D4E53';
+  ctx.fillRect(30, 30, 100, 100);
+  ctx.restore();
+
+  // rectangles drets, giren des del centre del rectangle
+  // dibuixa rect blau
+  ctx.fillStyle = '#0095DD';
+  ctx.fillRect(150, 30, 100, 100);
+
+  ctx.translate(200, 80); // trasllada al rectangle central
+                          // x = x + 0.5 * width
+                          // y = y + 0.5 * height
+  ctx.rotate((Math.PI / 180) * 25); // gira
+  ctx.translate(-200, -80); // traslladar de nou
+
+  // dibuixa rect gris
+  ctx.fillStyle = '#4D4E53';
+  ctx.fillRect(150, 30, 100, 100);
+}
+
+ +

Per girar el rectangle al voltant del seu propi centre, traslladem el llenç al centre del rectangle, després girem el llenç i tornem a traslladar el llenç a 0,0, i a continuació dibuixem el rectangle.

+ + + +

{{EmbedLiveSample("A_rotate_example", "310", "210", "https://mdn.mozillademos.org/files/9859/rotate.png")}}

+ +

Escalar

+ +

El següent mètode de transformació és l'escalat. Ho usem per augmentar o disminuir les unitats en la graella del llenç. Això es pot utilitzar per dibuixar formes i mapes de bits reduïts o ampliats.

+ +
+
{{domxref("CanvasRenderingContext2D.scale", "scale(x, y)")}}
+
Escala les unitats del llenç, per x horitzontalment i per y verticalment. Tots dos paràmetres són nombres reals. Els valors inferiors a 1.0 redueixen la grandària de la unitat i els valors superiors a 1.0 augmenten la grandària de la unitat. Els valors a 1.0 deixen les unitats de la mateixa grandària.
+
+ +

Usant nombres negatius es pot fer la replica d'eixos (per exemple, usant translate(0,canvas.height); scale(1,-1); tindrem el conegut sistema de coordenades cartesianes, amb l'origen en la cantonada inferior esquerra).

+ +

Per defecte, una unitat en el llenç és exactament un píxel. Si apliquem, per exemple, un factor d'escala de 0.5, la unitat resultant es convertirà en 0.5 píxels i per tant les formes es dibuixaran a meitat de la seva grandària. De manera similar, si s'ajusta el factor d'escala a 2.0, la grandària de la unitat augmentarà i una unitat ara es converteix en dos píxels. Això dona com a resultat que les formes es dibuixin dues vegades més grans.

+ +

Un exemple de scale

+ +

En aquest últim exemple, dibuixarem formes amb diferents factors d'escala.

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  // dibuixar un rectangle senzill, però escalar-lo.
+  ctx.save();
+  ctx.scale(10, 3);
+  ctx.fillRect(1, 10, 10, 10);
+  ctx.restore();
+
+  // mirror horizontally
+  ctx.scale(-1, 1);
+  ctx.font = '48px serif';
+  ctx.fillText('MDN', -135, 120);
+}
+
+
+ + + +

{{EmbedLiveSample("A_scale_example", "160", "160", "https://mdn.mozillademos.org/files/9861/scale.png")}}

+ +

Transformar

+ +

Finalment, els següents mètodes de transformació permeten modificar directament la matriu de transformació.

+ +
+
{{domxref("CanvasRenderingContext2D.transform", "transform(a, b, c, d, e, f)")}}
+
Multiplica la matriu de transformació actual amb la matriu descrita pels seus arguments. La matriu de transformació és descrita per: [acebdf001]\left[ \begin{array}{ccc} a & c & e \\ b & d & f \\ 0 & 0 & 1 \end{array} \right]
+
+ +
+
Si qualsevol dels arguments és Infinity, la matriu de transformació ha de ser marcada com a infinita en lloc que el mètode llanci una excepció.
+
+ +

Els paràmetres d'aquesta funció són:

+ +
+
a (m11)
+
Escalat horitzontal.
+
b (m12)
+
Desviació Horizontal.
+
c (m21)
+
Desviació Vertical.
+
d (m22)
+
Escalat Vertical.
+
e (dx)
+
Moviment Horizontal.
+
f (dy)
+
Moviment Vertical.
+
{{domxref("CanvasRenderingContext2D.setTransform", "setTransform(a, b, c, d, e, f)")}}
+
Reinicia la transformació actual a la matriu d'identitat i, a continuació, invoca el mètode transform() amb els mateixos arguments. Això, bàsicament, desfà la transformació actual, i després estableix la transformació especificada, tot en un sol pas.
+
{{domxref("CanvasRenderingContext2D.resetTransform", "resetTransform()")}}
+
Reinicia la transformació actual a la matriu d'identitat. Això és el mateix que cridar: ctx.setTransform(1, 0, 0, 1, 0, 0);
+
+ +

Exemple de transform i setTransform

+ +
function draw() {
+  var ctx = document.getElementById('canvas').getContext('2d');
+
+  var sin = Math.sin(Math.PI / 6);
+  var cos = Math.cos(Math.PI / 6);
+  ctx.translate(100, 100);
+  var c = 0;
+  for (var i = 0; i <= 12; i++) {
+    c = Math.floor(255 / 12 * i);
+    ctx.fillStyle = 'rgb(' + c + ', ' + c + ', ' + c + ')';
+    ctx.fillRect(0, 0, 100, 10);
+    ctx.transform(cos, sin, -sin, cos, 0, 0);
+  }
+
+  ctx.setTransform(-1, 0, 0, 1, 100, 100);
+  ctx.fillStyle = 'rgba(255, 128, 255, 0.5)';
+  ctx.fillRect(0, 50, 100, 100);
+}
+
+ + + +

{{EmbedLiveSample("Example_for_transform_and_setTransform", "230", "280", "https://mdn.mozillademos.org/files/255/Canvas_transform.png")}}

+ +

{{PreviousNext("Web/API/Canvas_API/Tutorial/Using_images", "Web/API/Canvas_API/Tutorial/Compositing")}}

+ +
+ + +
 
+ +
 
+
diff --git "a/files/ca/web/api/canvas_api/tutorial/\303\272s_b\303\240sic/index.html" "b/files/ca/web/api/canvas_api/tutorial/\303\272s_b\303\240sic/index.html" deleted file mode 100644 index fb15a62d81..0000000000 --- "a/files/ca/web/api/canvas_api/tutorial/\303\272s_b\303\240sic/index.html" +++ /dev/null @@ -1,158 +0,0 @@ ---- -title: Ús bàsic de canvas -slug: Web/API/Canvas_API/Tutorial/Ús_bàsic -tags: - - Canvas - - Graphics - - HTML - - Intermediate - - Tutorial -translation_of: Web/API/Canvas_API/Tutorial/Basic_usage ---- -
{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial", "Web/API/Canvas_API/Tutorial/Drawing_shapes")}}
- -
-

Comencem aquest tutorial consultant l'element {{HTMLElement("canvas")}} {{Glossary("HTML")}}. Al final d'aquesta pàgina, sabreu com configurar un context 2D de canvas i haureu dibuixat un primer exemple en el vostre navegador.

-
- -

L'element <canvas>

- -
<canvas id="tutorial" width="150" height="150"></canvas>
-
- -

A primera vista, {{HTMLElement("canvas")}} s'assembla l'element {{HTMLElement("img")}} amb l'única diferència clara, que no té els atributs src i alt. De fet, l'element <canvas> només té dos atributs, {{htmlattrxref("width", "canvas")}} i {{htmlattrxref("height", "canvas")}}. Aquests són opcionals i també es poden establir utilitzant les properties {{Glossary("DOM")}} . Quan no s'especifiquen els atributs width i height, inicialment canvas tindrà 300 píxels d'amplada i 150 píxels d'alçada. L'element es pot dimensionar arbitràriament per {{Glossary("CSS")}}, però durant la representació, la imatge s'escala per adaptar-se a la seva grandària de disseny: si el dimensionament CSS no respecta la relació inicial de canvas, apareixerà distorsionada

- -
-

Nota: Si les vostres representacions semblen distorsionades, intenteu especificar els atributs width i height, explícitament, en els atributs <canvas> i no utilitzeu CSS.

-
- -

L'atribut id no és específic de l'element <canvas>, però és un dels atributs HTML global que es pot aplicar a qualsevol element HTML (com class, per exemple). Sempre és una bona idea proporcionar un id, perquè això fa que sigui molt més fàcil identificar-lo en un script.

- -

L'element <canvas> se li pot donar estil com qualsevol imatge normal ({{cssxref("margin")}}, {{cssxref("border")}}, {{cssxref("background")}}…). Aquestes regles, no obstant això, no afecten al dibuix real sobre el llenç. Veurem com això es fa en un capítol dedicat d'aquest tutorial. Quan no s'apliquen regles d'estil al llenç, inicialment, serà totalment transparent.

- -
-

Contingut alternatiu

- -

L'element <canvas> difereix d'una etiqueta {{HTMLElement("img")}} com per els elements {{HTMLElement("video")}}, {{HTMLElement("audio")}} o {{HTMLElement("picture")}}, és fàcil definir algun contingut alternatiu, que es mostri en navegadors antics que no ho suportin, com ara en versions d'Internet Explorer anteriors a la versió 9 o navegadors textuals. Sempre haureu de proporcionar contingut alternatiu perquè els navegadors ho mostrin.

- -

Proporcionar contingut alternatiu és molt senzill: simplement inseriu el contingut alternatiu dins de l'element <canvas>. Els navegadors que no suporten <canvas> ignoraran el contenidor i mostraran el contingut alternatiu dins del mateix. Els navegadors que suporten <canvas> ignoraran el contingut dins del contenidor, i simplement mostraran el llenç, normalment.

- -

Per exemple, podríem proporcionar una descripció de text del contingut del llenç o proporcionar una imatge estàtica del contingut presentat dinàmicament. Això pot semblar-se a això:

- -
<canvas id="stockGraph" width="150" height="150">
-  current stock price: $3.15 + 0.15
-</canvas>
-
-<canvas id="clock" width="150" height="150">
-  <img src="images/clock.png" width="150" height="150" alt=""/>
-</canvas>
-
- -

Dir-li a l'usuari que utilitzi un navegador diferent que suporti canvas no ajuda als usuaris que no poden llegir canvas en absolut, per exemple. Proporcionar un text alternatiu útil o un DOM secundari, ajuda a fer canvas més accessible.

- -

Etiqueta </canvas> obligatoria

- -

Com a conseqüència de la manera en què es proporciona una solució alternativa, a diferència de l'element {{HTMLElement("img")}}, l'element {{HTMLElement("canvas")}} requereix l'etiqueta de tancament (</canvas>). Si aquesta etiqueta no està present, la resta del document es consideraria contingut alternatiu i no es mostraria.

- -

Si no es necessita un contingut alternatiu, un simple <canvas id="foo" ...></canvas> és totalment compatible amb tots els navegadors que suporten canvas.

- -

El context de representació

- -

L'element {{HTMLElement("canvas")}} crea una superfície de dibuix de grandària fixa que exposa un o més contextos de representació, que s'utilitzen per crear i manipular el contingut mostrat. En aquest tutorial, ens centrem en el context de representació 2D. Altres contextos poden proporcionar diferents tipus de representació; per exemple, WebGL utilitza un context 3D basat en OpenGL ÉS.Other contexts may provide different types of rendering; for example, WebGL uses a 3D context based on OpenGL ES.

- -

El llenç està inicialment en blanc. Per mostrar alguna cosa, un script, primer necessita accedir al context de representació i dibuixar en ell. L'element {{HTMLElement("canvas")}} té un mètode anomenat {{domxref("HTMLCanvasElement.getContext", "getContext()")}}, utilitzat per obtenir el context de representació i les seves funcions de dibuix. getContext() pren un paràmetre, el tipus de context. Per als gràfics 2D, com els que es detallen en aquest tutorial, heu d'especificar "2d" per obtenir un {{domxref("CanvasRenderingContext2D")}}.

- -
var canvas = document.getElementById('tutorial');
-var ctx = canvas.getContext('2d');
-
- -

La primera línia del script recupera el node en el DOM, que representa l'element {{HTMLElement("canvas")}} cridant el mètode {{domxref("document.getElementById()")}}. Un cop tingueu el node d'element, podeu accedir al context del dibuix mitjançant el mètode getContext().

- -
-

Comprovació del suport

- -

El contingut alternatiu es mostra en navegadors que no admeten {{HTMLElement("canvas")}}. Les seqüències d'ordres, també poden comprovar la compatibilitat mitjançant programació, simplement provant la presència del mètode getContext(). El nostre fragment de codi de dalt es converteix en una cosa així:

- -
var canvas = document.getElementById('tutorial');
-
-if (canvas.getContext) {
-  var ctx = canvas.getContext('2d');
-  // drawing code here
-} else {
-  // canvas-unsupported code here
-}
-
-
-
- -

Una plantilla esquelet

- -

Aquí teniu una plantilla minimalista, que usarem com a punt de partida per a exemples posteriors.

- -
-

Nota: no és una bona pràctica incrustar un script dins d'HTML. Ho fem aquí per mantenir l'exemple concís.

-
- -
<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8"/>
-    <title>Canvas tutorial</title>
-    <script type="text/javascript">
-      function draw() {
-        var canvas = document.getElementById('tutorial');
-        if (canvas.getContext) {
-          var ctx = canvas.getContext('2d');
-        }
-      }
-    </script>
-    <style type="text/css">
-      canvas { border: 1px solid black; }
-    </style>
-  </head>
-  <body onload="draw();">
-    <canvas id="tutorial" width="150" height="150"></canvas>
-  </body>
-</html>
-
- -

El script inclou una funció anomenada draw(), que s'executa una vegada que la pàgina acaba de carregar-se; això es fa escoltant  l'esdeveniment {{event("load")}} en el document. Aquesta funció, o una similar, també pot ser cridada usant {{domxref("WindowTimers.setTimeout", "window.setTimeout()")}}, {{domxref("WindowTimers.setInterval", "window.setInterval()")}}, o qualsevol altre controlador d'esdeveniments, sempre que la pàgina s'hagi carregat primer.

- -

Així és com es veuria una plantilla en acció. Com es mostra aquí, inicialment està en blanc.

- -

{{EmbedLiveSample("A_skeleton_template", 160, 160)}}

- -

Un exemple senzill

- -

Per començar, feu un cop d'ull a un exemple senzill que dibuixa dos rectangles que es creuen, un dels quals té una transparència alfa. Explorarem com funciona això amb més detall en exemples posteriors.

- -
<!DOCTYPE html>
-<html>
- <head>
-  <meta charset="utf-8"/>
-  <script type="application/javascript">
-    function draw() {
-      var canvas = document.getElementById('canvas');
-      if (canvas.getContext) {
-        var ctx = canvas.getContext('2d');
-
-        ctx.fillStyle = 'rgb(200, 0, 0)';
-        ctx.fillRect(10, 10, 50, 50);
-
-        ctx.fillStyle = 'rgba(0, 0, 200, 0.5)';
-        ctx.fillRect(30, 30, 50, 50);
-      }
-    }
-  </script>
- </head>
- <body onload="draw();">
-   <canvas id="canvas" width="150" height="150"></canvas>
- </body>
-</html>
-
- -

Aquest exemple es veu així:

- -

{{EmbedLiveSample("A_simple_example", 160, 160, "https://mdn.mozillademos.org/files/228/canvas_ex1.png")}}

- -

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

-- cgit v1.2.3-54-g00ecf