miércoles, 28 de agosto de 2013

Transformaciones en el canvas

Este post tiene una continuación en la entrada: Guardar y restaurar el contexto del canvas.
Las transformaciones básicas en el  canvas son 3: traslación, rotación y escalado.
La forma en que funcionan es poco intuitiva puesto que lo que hacen no es trasladar, rotar y escalar elementos en el canvas sino que actúan sobre el origen y los ejes de coordenadas del canvas, modificando su posición, orientación y escala, de forma que los elementos dibujados antes de una transformación permanecen inalterados y los que se dibujen después de aplicar la transformación son afectados por ella.
Las transformaciones se aplican sobre el contexto del canvas.

Traslación

context.translate(x,y)
Traslada el origen de cordenadas del canvas desde la esquina superior izquierda al punto x,y.

Rotación

context.rotate(radianes)
Rota los ejes de coordenadas en torno al origen, un angulo especificado en radianes, en sentido horario. Para pasar de grados a radianes:
angulo_en_radianes = angulo_en_grados * (Math.PI/180)

Escalado

context.scale(factorX, factorY)
Mutiplica las coordenadas en el eje X e Y por el factorX y el factorY.


Ejemplo

<!DOCTYPE html>
<html>
<head>
</head>
<body>
 <canvas id="my_canvas" width="300px" height="200px"
 style="border:1px solid #000000;"></canvas> 
 <script type="text/javascript">
  var canvas = document.getElementById('my_canvas');
  var ctx = canvas.getContext('2d');
      
  var x = 10;
  var y = 10;
  var w = 50;
  var h = 50;
  var factorX = 0.5;
  var factorY = 0.5;
  
  // escalado
  ctx.scale(factorX, factorY);
  
  ctx.fillStyle = "#ff0000"; // rojo
  ctx.fillRect(x, y, w, h);
  
  // traslación
  ctx.translate(100, 50);
  
  ctx.fillStyle = "#00ff00"; // verde
  ctx.fillRect(x, y, w, h);
  
  // rotación
  ctx.rotate(30 * Math.PI/180);
  
  // dibujamos el nuevo eje x
  ctx.beginPath();
  ctx.moveTo(0,0);
  ctx.lineTo(50,0);
  ctx.stroke();
  
  // y el nuevo eje Y
  ctx.beginPath();
  ctx.moveTo(0,0);
  ctx.lineTo(0,50);
  ctx.stroke();
  
  ctx.fillStyle = "#0000ff"; // azul
  ctx.fillRect(x, y, w, h);
 
 </script> 
</body>
</html>
En el ejemplo se puede probar a cambiar la escala, cambiando factorX y factorY. El ejemplo tiene factorX = 0.5 y factorY = 0.5 (mitad de escala). El tamaño normal se consigue con factorX = 1, factorY = 1 y el doble de tamaño se consigue con factorX = 2, factorY = 2.


Este post tiene una continuación en la entrada: Guardar y restaurar el contexto del canvas 

lunes, 5 de agosto de 2013

Dibujar imágenes en el canvas con drawImage

Podemos dibujar en el canvas el contenido de un archivo de imagen. Los 2 formatos de imagen más habituales en la actualidad son:
  • jpg: formato comprimido con pérdida de calidad y sin transparencia.
  • png: formato comprimido sin pérdida de calidad y con posibilidad de transparencia.
Tal vez en un futuro ambos queden relegados por un nuevo formato libre: webp, pero de momento no hay indicios de tal cosa.
En general usaremos el formato jpg por ser de tamaño más reducido, a no ser que no queramos que la imagen pierda calidad o queramos usar una imagen con transparencia, en cuyo caso usaremos el formato png.

Para dibujar una imagen en el canvas usaremos la función drawImage del contexto del canvas (context.drawImage()), que tiene varias posibilidades:
  • context.drawImage(img, x, y): dibuja la imagen entera y sin escalar en el canvas, poniendo su esquina superior izquierda en el punto x,y del canvas.
  • context.drawImage(img, x, y, ancho, alto): posiciona la imagen en el punto x,y del canvas y la reescala para que tenga la anchura y altura especificadas.
  • context.drawImage(img, ox, oy, oancho, oalto, x, y, ancho, alto): coge un trozo de la imagen a partir del punto ox,oy, de anchura oancho y altura oalto y lo coloca en el canvas en el punto x, y, reescalándolo para que tenga la anchura ancho y altura alto.

Ejemplo

usaremos la siguiente imagen, que se puede guardar con click derecho del ratón sobre ella y "Guardar imagen". La guardaremos como planeta.jpg.


En el mismo directorio en que tengamos la imagen creamos un archivo html con el siguiente contenido.
<!DOCTYPE html>
<html>
<head>
</head>
<body>
    <canvas id="my_canvas" width="300px" height="200px"
           style="border:1px solid #000000;"></canvas> 
    <script type="text/javascript">
 var canvas = document.getElementById('my_canvas');
 var ctx = canvas.getContext('2d');
 var imagen = new Image();
 imagen.onload = pinta;
 imagen.src = 'planeta.jpg';

 function pinta(){     
            // pintamos la imagen en la esquina superior izquierda del
            // canvas, con el tamaño original.
     ctx.drawImage(imagen, 0, 0);
     // pintamos la imagen en en el punto 110, 0, reescalada.
     ctx.drawImage(imagen, 110, 0, 1.5*imagen.width, 
            0.5*imagen.height);
     // pintamos un trozo de imagen, el cuadrante inferior
            // derecho, en el punto 0, 110, sin reescalar.
     ctx.drawImage(imagen, 50, 50, 50, 50, 0, 110, 50, 50);
     // reescalado (doble altura)
     ctx.drawImage(imagen, 50, 50, 50, 50, 110, 110, 50, 2*50);
 }
 </script> 
</body>
</html>
Como nota interesante del ejemplo, ver que el objeto de tipo Image tiene un par de campos width y height desde los que podemos recuperar la anchura y altura de la imagen.