This translation is incomplete. Please help translate this article from English.

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.

fillStyle = color
Estableix l'estil utilitzat per emplenar formes.
strokeStyle = color
Estableix l'estil per als contorns de les formes.

color és una cadena que representa un <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 <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:

ScreenshotLive sample

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í:

ScreenshotLive sample

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.

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();
  }
}

ScreenshotLive sample

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);
    }
  }
}

ScreenshotLive sample

Estils de línia

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

lineWidth = value
Estableix l'amplària de les línies dibuixades en el futur.
lineCap = type
Estableix l'aparença dels extrems de les línies.
lineJoin = type
Estableix l'aparença de les "cantonades" on s'uneixen les línies.
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ó.
getLineDash()
Retorna la matriu de patró de guió de la línia actual que conté un nombre parell de nombres no negatius.
setLineDash(segments)
Estableix el patró de guió de línia actual.
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();
  }
}

ScreenshotLive sample

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();
  }
}

ScreenshotLive sample

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();
  }
}

ScreenshotLive sample

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 <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:

  • miterLimit = max miterLength / lineWidth = 1 / sin ( min θ / 2 )
  • El límit de miter predeterminat de 10.0 llevarà tots els miters per a angles aguts per sota d'uns 11 graus.
  • Un límit de miter igual a √2 ≈ 1.4142136 (arrodonit cap amunt) separarà els miters de tots els angles aguts, mantenint les unions de miter solament per als angles obtusos o rectes.
  • Un límit de miter igual a 1.0 és vàlid, però desactivarà tots els miters.
  • Els valors inferiors a 1.0 no són vàlids per al límit de miter.

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;
}

ScreenshotLive sample

Ú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();

ScreenshotLive sample

Gradients

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

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).
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().

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 <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.

ScreenshotLive sample

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).

ScreenshotLive sample

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().

createPattern(image, type)
Crea i retorna un nou objecte de patró canvas. image es un CanvasImageSource (és a dir, un HTMLImageElement, altre llenç, un element <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 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);

  }
}

ScreenshotLive sample

Ombres (Shadows)

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

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.
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.
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.
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);
}

ScreenshotLive sample

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 clip i 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');
}

ScreenshotLive sample

Document Tags and Contributors

 Contributors to this page: Legioinvicta
 Last updated by: Legioinvicta,