Mostrando entradas con la etiqueta Capítulo 7. API Canvas. Mostrar todas las entradas
Mostrando entradas con la etiqueta Capítulo 7. API Canvas. Mostrar todas las entradas

domingo, 24 de abril de 2016

Procesando video en el lienzo - HTML, CSS y JAVASCRIPT



Al igual que para animaciones, no hay ningún método especial para mostrar video en el elemento <canvas>. La única manera de hacerlo es tomando cada cuadro del video desde el elemento <video> y dibujarlo como una imagen en el lienzo usando drawImage(). Así que básicamente, el procesamiento de video en el lienzo es hecho con la combinación de técnicas ya estudiadas.
Construyamos una nueva plantilla y los códigos para ver de qué estamos hablando.

Código 7-28. Plantilla para reproducir video en el lienzo.

<!DOCTYPE html>
<html lang="es">
<head>
<title>Video en el Lienzo</title>
<style>
.cajas{
display: inline-block;
margin: 10px;
padding: 5px;
border: 1px solid #999999;
}
</style>
<script src="canvasvideo.js"></script>
</head>
<body>
<section class="cajas">
<video id="medio" width="483" height="272">
<source src="http://www.minkbooks.com/content/trailer2.mp4">
<source src="http://www.minkbooks.com/content/trailer2.ogg">
</video>
</section>
<section class="cajas">
<canvas id="lienzo" width="483" height="272">
Su navegador no soporta el elemento canvas
</canvas>
</section>
</body>
</html>

La plantilla en el código 7-28 incluye dos componentes específicos: el elemento <video> y el elemento <canvas>. Con la combinación de ambos vamos a procesar y mostrar video en el lienzo.
La plantilla también incluye estilos CSS embebidos para las cajas y un archivo Javascript llamado canvasvideo.js para el siguiente código:


Código 7-29. Video color convertido en blanco y negro.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
video=document.getElementById('medio');
video.addEventListener('click', presionar, false);
}
function presionar(){
if(!video.paused && !video.ended){
video.pause();
window.clearInterval(bucle);
}else{
video.play();
bucle=setInterval(procesarCuadros, 33);
}
}
function procesarCuadros(){
lienzo.drawImage(video,0,0);
var info=lienzo.getImageData(0,0,483,272);
var pos;
var gris;
for(x=0;x<=483;x++){
for(y=0;y<=272;y++){
pos=(info.width*4*y)+(x*4);
gris=parseInt(info.data[pos]*0.2989 +
info.data[pos+1]*0.5870 + info.data[pos+2]*0.1140);
info.data[pos]=gris;
info.data[pos+1]=gris;
info.data[pos+2]=gris;
}
}
lienzo.putImageData(info,0,0);
}
window.addEventListener("load", iniciar, false);

Hágalo usted mismo: Cree un nuevo archivo HTML con el código 7-28 y un archivo Javascript llamado canvasvideo.js con el código 7-29.
Para comenzar a reproducir el video, haga clic en la caja izquierda en la pantalla.
IMPORTANTE: Este ejemplo usa los métodos getImageData() y putImageData() para procesar datos de imagen. Como explicamos anteriormente, estos métodos extraen información del lienzo. Debido a restricciones de seguridad, la extracción de información desde el lienzo es desactivada luego de que el elemento recibe contenido desde un origen que no es el origen del documento que lo creó (el documento pertenece a un dominio y el video a otro). Por lo tanto, para probar este ejemplo, deberá descargar el video desde nuestro sitio web (o usar el suyo propio) y luego subir cada uno de los archivos a su servidor. 

Estudiemos por un momento el código 7-29. Como dijimos previamente, para procesar video en el lienzo, simplemente debemos recurrir a códigos y técnicas ya vistas. En este código estamos usando la función presionar() tomada del Capítulo 5 para comenzar y detener la reproducción del video haciendo clic sobre el mismo. También creamos una función llamada procesarCuadros() que está usando el mismo código 7-25 de este capítulo, excepto que esta vez en lugar de invertir la imagen estamos usando una fórmula para transformar todos los colores de cada cuadro del video en el correspondiente gris. Esto convertirá nuestro video color en un video blanco y negro. La función presionar() cumple con dos propósitos: comenzar o detener la reproducción del video e iniciar un intervalo que ejecutará la función procesarCuadros() cada 33 milisegundos. Esta función toma un cuadro del elemento <video> y lo dibuja en el lienzo con la instrucción drawImage(video,0,0). 
Luego los datos son extraídos del lienzo con el método getImageData() y cada pixel de ese cuadro es procesado por medio de dos bucles for (como lo hicimos en un ejemplo anterior). 
El proceso utilizado para convertir cada uno de los colores que integran cada pixel en su correspondiente gris es uno de los más populares y fáciles de encontrar en Internet. La fórmula es la siguiente: rojo × 0.2989 + verde × 0.5870 + azul × 0.1140. 
Luego de que la fórmula es calculada, el resultado debe ser asignado a cada color del pixel (rojo, verde y azul), como lo hicimos en el ejemplo usando la variable gris. 
El proceso termina cuando dibujamos nuevamente el cuadro modificado en el lienzo usando el método putImageData().
IMPORTANTE: Este ejemplo es con propósitos didácticos. Procesar video en
tiempo real del modo en que lo hicimos no es una práctica recomendada.
Dependiendo de la configuración de su ordenador y el navegador que use para correr la aplicación, probablemente note algunas demoras en el proceso. Para crear aplicaciones Javascript útiles, siempre debe considerar su rendimiento.


Referencia rápida

La API Canvas es probablemente la más compleja y extensa de todas las APIs incluidas dentro de la especificación HTML5. Provee varios métodos y propiedades para crear aplicaciones gráficas sobre el elemento <canvas>.

Métodos

Estos métodos son específicos de la API Canvas:
  • getContext(contexto) Este método crea el contexto para el lienzo. Puede tomar dos valores: 2d y 3d para gráficos en 2 y 3 dimensiones.
  • fillRect(x, y, ancho, alto) Este método dibujará un rectángulo sólido directamente en el lienzo en la posición indicada por x,y y el tamaño ancho,alto.
  • strokeRect(x, y, ancho, alto) Este método dibujará un rectángulo vacío (solo el contorno) directamente en el lienzo en la posición indicada por x,y y el tamaño ancho,alto.
  • clearRect(x, y, ancho, alto) Este método borra un área en el lienzo usando una figura rectangular declarada por los valores de sus atributos.
  • createLinearGradient(x1, y1, x2, y2) Este método crea un gradiente lineal para asignarlo a una figura como si fuese un color usando la propiedad fillStyle. Sus atributos solo especifican las posiciones de comienzo y final del gradiente (relativas al lienzo). Para declarar los colores involucrados en el gradiente, este método debe ser usado en combinación con addColorStop().
  • createRadialGradient(x1, y1, r1, x2, y2, r2) Este método crea un gradiente radial para asignarlo a una figura como si fuese un color usando la propiedad fillStyle. El gradiente es construido por medio de dos círculos. Los atributos solo especifican la posición y radio de los círculos (relativos al lienzo). Para declarar los colores involucrados en el gradiente, este método debe ser usado en combinación con addColorStop().
  • addColorStop(posición, color) Este método es usado para declarar los colores para el gradiente. El atributo posición es un valor entre 0.0 y 1.0, usado para determinar dónde el color comenzará la degradación.
  • beginPath() Este método es requerido para comenzar un nuevo trazado.
  • closePath() Este método puede ser usado al final de un trazado para cerrarlo. Generará una línea recta desde la última posición del lápiz hasta el punto donde el trazado comenzó. No es necesario usar este método cuando el trazado debe permanecer abierto o es dibujado en el lienzo usando fill().
  • stroke() Este método es usado para dibujar un trazado como una figura vacía (solo el contorno).
  • fill() Este método es usado para dibujar un trazado como una figura sólida.
  • clip() Este método es usado para crear una máscara a partir de un trazado. Todo lo que sea enviado al lienzo luego de que este método es declarado será dibujado sólo si cae dentro de la máscara.
  • moveTo(x, y) Este método mueve el lápiz virtual a una nueva posición para continuar el trazado desde ese punto.
  • lineTo(x, y) Este método agrega líneas rectas al trazado desde la posición actual del lápiz hasta el punto indicado por los atributos x e y.
  • rect(x, y, ancho, alto) Este método agrega un rectángulo al trazado en la posición x,y y con un tamaño determinado por ancho,alto.
  • arc(x, y, radio, ángulo inicio, ángulo final, dirección) Este método agrega un arco al trazado. El centro del arco es determinado por x e y, los ángulos son definidos en radianes, y la dirección es un valor booleano para determinar si el arco será dibujado en el mismo sentido o el opuesto a las agujas del reloj. Para convertir grados en radianes, use la fórmula: Math.PI/180×grados.
  • quadraticCurveTo(cpx, cpy, x, y) Este método agrega una curva Bézier cuadrática al trazado. Comienza desde la posición actual del lápiz y termina en el punto x,y. Los atributos cpx y cpy especifican la posición del punto de control que dará forma a la curva.
  • bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) Este método agrega una curva Bézier cúbica al trazado. Comienza desde la posición actual del lápiz y termina en el punto x,y. Los atributos cp1x, cp1y, cp2x, y cp2y especifican la posición de los dos puntos de control que darán forma a la curva.
  • strokeText(texto, x, y, máximo) Este método dibuja un texto vacío (solo el contorno) directamente en el lienzo. El atributo máximo es opcional y determina el máximo tamaño del texto en pixeles.
  • fillText(texto, x, y, máximo) Este método dibuja un texto sólido directamente en el lienzo. El atributo máximo es opcional y determina el máximo tamaño del texto en pixeles. 
  • measureText(texto) Este método calcula el tamaño del área que un texto ocupará en el lienzo usando los estilos vigentes. La propiedad width es usada para retornar el valor.
  • translate(x, y) Este método mueve el origen del lienzo al punto x,y. La posición inicial del origen (0,0) es la esquina superior izquierda del área generada por el elemento <canvas>.
  • rotate(angle) Este método es usado para rotar el lienzo alrededor del origen. El ángulo debe ser declarado en radianes. Para convertir grados en radianes, use la fórmula: Math.PI/180×grados.
  • scale(x, y) Este método cambia la escala del lienzo. Los valores por defecto son (1.0, 1.0). Los valores provistos pueden ser negativos.
  • transform(m1, m2, m3, m4, dx, dy) Este método modifica la matriz de transformación del lienzo. La nueva matriz es calculada sobre la anterior.
  • setTransform(m1, m2, m3, m4, dx, dy) Este método modifica la matriz de transformación del lienzo. Reinicia los valores anteriores y declara los nuevos.
  • save() Este método graba el estado del lienzo, incluyendo la matriz de transformación, propiedades de estilo y la máscara.
  • restore() Este método restaura el último estado del lienzo grabado, incluyendo la matriz de transformación, propiedades de estilo y la máscara.
  • drawImage() Esta método dibujará una imagen en el lienzo. Existen tres sintaxis posibles.  La sintaxis drawImage(imagen,x,y) dibuja la imagen en la posición x,y. 
  • La sintaxis drawImage(imagen,x,y,ancho,alto) dibuja la imagen en la posición x,y con un nuevo tamaño declarado por ancho,alto. Y la sintaxis drawImage(imagen, x1, y1, ancho1, alto1, x2, y2, ancho2, alto2) toma una porción de la imagen original determinada por x1,y1,ancho1,alto1 y la dibuja en el lienzo en la posición x2,y2 y el nuevo tamaño ancho2,alto2. 
  • getImageData(x, y, ancho, alto) Este método toma una porción del lienzo y la graba como datos en un objeto. Los valores del objeto son accesibles a través de las propiedades width, height y data. Las primeras dos propiedades retornan el tamaño de la porción de la imagen tomada, y data retorna la información como un array con valores representando los colores de cada pixel. Este valor puede ser accedido usando la fórmula (ancho×4×y)+(x×4).
  • putImageData(datosImagen, x, y) Este método dibuja en el lienzo la imagen representada por la información en datosImagen.
  • createImageData(ancho, alto) Este método crea una nueva imagen en formato de datos. Todos los pixeles son inicializados en color negro transparente. Puede tomar datos de imagen como atributo en lugar de ancho y alto. En este caso la nueva imagen tendrá el tamaño determinado por los datos provistos.
  • createPattern(imagen, tipo) Este método crea un patrón desde una imagen que luego podrá ser asignado a una figura usando la propiedad fillStyle. Los valores posibles para el atributo tipo son repeat, repeat-x, repeat-y y no-repeat.


Propiedades

La siguiente lista de propiedades es específica para la API Canvas:
  • strokeStyle Esta propiedad declara el color para las líneas de las figuras. Puede recibir cualquier valor CSS, incluidas funciones como rgb() y rgba().
  • fillStyle Esta propiedad declara el color para el interior de figuras sólidas. Puede recibir cualquier valor CSS, incluidas funciones como rgb() y rgba(). Es también usada para asignar gradientes y patrones a figuras (estos estilos son primero asignados a una variable y luego esa variable es declarada como el valor de esta propiedad).
  • globalAlpha Esta propiedad es usada para determinar el nivel de transparencia de las figuras. Recibe valores entre 0.0 (completamente opaco) y 1.0 (completamente transparente).
  • lineWidth Esta propiedad especifica el grosor de la línea. Por defecto el valor es 1.0.
  • lineCap - Esta propiedad determina la forma de la terminación de las líneas. Se pueden utilizar tres valores: butt (terminación normal), round (termina la línea con un semicírculo) y square (termina la línea con un cuadrado).
  • lineJoin Esta propiedad determina la forma de la conexión entre líneas. Se pueden utilizar tres valores: round (la unión es redondeada), bevel (la unión es cortada) y miter (la unión es extendida hasta que ambas líneas alcanzan un punto en común).
  • miterLimit Esta propiedad determina cuánto se extenderán las líneas cuando la propiedad lineJoin es declarada como miter.
  • font Esta propiedad es similar a la propiedad font de CSS y utiliza la misma sintaxis para declarar los estilos del texto. 
  • textAlign Esta propiedad determina cómo el texto será alineado. Los posibles valores son start, end, left, right y center.
  • textBaseline Esta propiedad determina el alineamiento vertical para el texto. Los posibles valores son: top, hanging, middle, alphabetic, ideographic y bottom.
  • shadowColor Esta propiedad establece el color para la sombra. Utiliza valores CSS.
  • shadowOffsetX Esta propiedad declara la distancia horizontal entre la sombra y el objeto.
  • shadowOffsetY Esta propiedad declara la distancia vertical entre la sombra y el objeto.
  • shadowBlur Esta propiedad recibe un valor numérico para generar un efecto de difuminación para la sombra.
  • globalCompositeOperation Esta propiedad determina cómo las nuevas figuras serán dibujadas en el lienzo considerando las figuras ya existentes. Puede recibir varios valores: source-over, source-in, source-out, source-atop, lighter, xor,destination-over, destination-in, destination-out, destination-atop,darker y copy. El valor por defecto es source-over, lo que significa que las nuevas formas son dibujadas sobre las anteriores.


Espero haber ayudado en algo. Hasta la próxima oportunidad!











  

domingo, 6 de marzo de 2016

Animaciones en el lienzo - JAVASCRIPT



Las animaciones son creadas por código Javascript convencional. No existen métodos para ayudarnos a animar figuras en el lienzo, y tampoco existe un procedimiento predeterminado para hacerlo. Básicamente, debemos borrar el área del lienzo que queremos animar, dibujar las figuras y repetir el proceso una y otra vez. Una vez que las figuras son dibujadas no se pueden mover. Solo borrando el área y dibujando las figuras nuevamente podemos construir una animación. Por esta razón, en juegos o aplicaciones que requieren grandes cantidades de objetos a ser animados, es mejor usar imágenes en lugar de figuras construidas con trazados complejos (por ejemplo, juegos normalmente utilizan imágenes PNG, que además son útiles por su capacidad de transparencia).
Existen múltiples técnicas para lograr animaciones en el mundo de la programación. 
Algunas son simples y otras tan complejas como las aplicaciones para las que fueron creadas. Vamos a ver un ejemplo simple utilizando el método clearRect() para limpiar el lienzo y dibujar nuevamente, generando una animación con solo una función, pero siempre recuerde que si su intención es crear elaborados efectos probablemente deberá adquirir un libro de programación avanzada en Javascript antes de siquiera intentarlo. 

Código 7-27. Nuestra primera animación.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
window.addEventListener('mousemove', animacion, false);
}
function animacion(e){
lienzo.clearRect(0,0,300,500);
var xraton=e.clientX;
var yraton=e.clientY;
var xcentro=220;
var ycentro=150;
var angulo=Math.atan2(xraton-xcentro,yraton-ycentro);
var x=xcentro+Math.round(Math.sin(angulo)*10);
var y=ycentro+Math.round(Math.cos(angulo)*10);
lienzo.beginPath();
lienzo.arc(xcentro,ycentro,20,0,Math.PI*2, false);
lienzo.moveTo(xcentro+70,150);
lienzo.arc(xcentro+50,150,20,0,Math.PI*2, false);
lienzo.stroke();
lienzo.beginPath();
lienzo.moveTo(x+10,y);
lienzo.arc(x,y,10,0,Math.PI*2, false);
lienzo.moveTo(x+60,y);
lienzo.arc(x+50,y,10,0,Math.PI*2, false);
lienzo.fill();
}
window.addEventListener("load", iniciar, false);

El Código 7-27 mostrará dos ojos en pantalla que miran al puntero del ratón todo el tiempo. Para mover los ojos, debemos actualizar su posición cada vez que el ratón es movido. Por este motivo agregamos una escucha para el evento mousemove en la función iniciar(). Cada vez que el puntero del ratón cambia de posición, el evento es disparado y la función animacion() es llamada.
La función animacion() comienza limpiando el lienzo con la instrucción clearRect(0,0,300,500). Luego, la posición del puntero del ratón es capturada (usando las viejas propiedades clientX y clientY) y la posición del primer ojo es grabada en las variables xcentro e ycentro.
Luego de que estas variables son inicializadas, es tiempo de comenzar con las matemáticas. Usando los valores de la posición del ratón y el centro del ojo izquierdo, calculamos el ángulo de la línea invisible que va desde un punto al otro usando el método predefinido atan2. Este ángulo es usado en el siguiente paso para calcular el punto exacto del centro del iris del ojo izquierdo con la fórmula xcentro + Math.round(Math.sin(angulo) × 10). El número 10 en la fórmula representa la distancia desde el centro del ojo al centro del iris (porque el iris no está en el centro del ojo, está siempre sobre el borde).
Con todos estos valores podemos finalmente comenzar a dibujar nuestros ojos en el lienzo. El primer trazado es para los dos círculos representando los ojos. El primer método arc() para el primer ojo es posicionado en los valores xcentro y ycentro, y el círculo para el segundo ojo es generado 50 pixeles hacia la derecha usando la instrucción arc(xcentro+50, 150, 20, 0, Math.PI*2, false). 
La parte animada del gráfico es creada a continuación con el segundo trazado. Este trazado usa las variables x e y con la posición calculada previamente a partir del ángulo. 
Ambos iris son dibujados como un círculo negro sólido usando fill(). 

El proceso será repetido y los valores recalculados cada vez que el evento mousemove es disparado.
Hágalo usted mismo: Copie el Código 7-27 en el archivo Javascript canvas.js y abra el archivo HTML con la plantilla del Código 7-1 en su navegador. 


Espero haber ayudado en algo. Hasta la próxima oportunidad!











  

domingo, 28 de febrero de 2016

Procesando imágenes con API CANVAS



API Canvas no sería nada sin la capacidad de procesar imágenes. Pero incluso cuando las imágenes son un elemento tan importante para una aplicación gráfica, solo un método nativo fue provisto para trabajar con ellas.

drawImage()

El método drawImage() es el único a cargo de dibujar una imagen en el lienzo. Sin embargo, este método puede recibir un número de valores que producen diferentes resultados. Estudiemos estas posibilidades:

drawImage(imágen, x, y) :Esta sintaxis es para dibujar una imagen en el lienzo en la posición declarada por x e y. El primer valor es una referencia a la imagen que será dibujada.
drawImage(imágen, x, y, ancho, alto) :Esta sintaxis nos permite escalar la imagen antes de dibujarla en el lienzo, cambiando su tamaño con los valores de los atributos ancho y alto. 
drawImage(imágen, x1, y1, ancho1, alto1, x2, y2, ancho2, alto2) :Esta es la sintaxis más compleja. Hay dos valores para cada parámetro. El propósito es cortar partes de la imagen y luego dibujarlas en el lienzo con un tamaño y una posición específica. Los valores x1 e y1 declaran la esquina superior izquierda de la parte de la imagen que será cortada. Los valores ancho1 y alto1 indican el tamaño de esta pieza. El resto de los valores (x2, y2, ancho2 y alto2) declaran el lugar donde la pieza será dibujada en el lienzo y su nuevo tamaño (el cual puede ser igual o diferente al original).

En cada caso, el primer atributo puede ser una referencia a una imagen en el mismo documento generada por métodos como getElementById(), o creando un nuevo objeto imagen usando métodos regulares de Javascript. No es posible usar una URL o cargar un archivo desde una fuente externa directamente con este método.

Código 7-22. Trabajando con imágenes.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
var imagen=new Image();
imagen.src="http://www.minkbooks.com/content/snow.jpg";
imagen.addEventListener("load", function(){
lienzo.drawImage(imagen,20,20)
}, false);
}
window.addEventListener("load", iniciar, false);

Comencemos con un simple ejemplo. El código 7-22 lo único que hace es cargar la imagen y dibujarla en el lienzo. Debido a que el lienzo solo puede dibujar imágenes que ya están completamente cargadas, necesitamos controlar esta situación escuchando al evento load. Agregamos una escucha para este evento y declaramos una función anónima para responder al mismo. El método drawImage() dentro de esta función dibujará la imagen cuando fue completamente cargada. 
Conceptos básicos: En el Código 7-22, dentro del método addEventListener(), usamos una función anónima en lugar de una referencia a una función normal. En casos como éste, cuando la función es pequeña, esta técnica vuelve al código más simple y fácil de entender.  

Código 7-23. Ajustando la imagen al tamaño del lienzo.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
var imagen=new Image();
imagen.src="http://www.minkbooks.com/content/snow.jpg";
imagen.addEventListener("load", function(){
lienzo.drawImage(imagen,0,0,elemento.width,elemento.height)
}, false);
}
window.addEventListener("load", iniciar, false);

En el Código 7-23, agregamos dos valores al método drawImage() utilizado previamente para cambiar el tamaño de la imagen. Las propiedades width y height retornan las medidas del lienzo, por lo que la imagen será estirada por este código hasta cubrir el lienzo por completo.

Código 7-24. Extrayendo, cambiando el tamaño y dibujando.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
var imagen=new Image();
imagen.src="http://www.minkbooks.com/content/snow.jpg";
imagen.addEventListener("load", function(){
lienzo.drawImage(imagen,135,30,50,50,0,0,200,200)
}, false);
}
window.addEventListener("load", iniciar, false);

En el Código 7-24 el código presenta la sintaxis más compleja del método drawImage(). 
Nueve valores fueron provistos para obtener una parte de la imagen original, cambiar su tamaño y luego dibujarla en el lienzo. Tomamos un cuadrado de la imagen original desde la posición 135,50, con un tamaño de 50,50 pixeles. Este bloque es redimensionado a 200,200 pixeles y finalmente dibujado en el lienzo en la posición 0,0.


Datos de imágenes

Cuando dijimos previamente que drawImage() era el único método disponible para dibujar imágenes en el lienzo, mentimos. Existen unos poderosos métodos para procesar imágenes en esta API que además pueden dibujarlas en el lienzo. Debido a que estos métodos no trabajan con imágenes sino con datos, nuestra declaración previa sigue siendo legítima. ¿Pero por qué desearíamos procesar datos en lugar de imágenes? 
Toda imagen puede ser representada por una sucesión de números enteros representando valores rgba (cuatro valores para cada pixel). Un grupo de valores con esta información resultará en un array unidimensional que puede ser usado luego para generar una imagen. La API Canvas ofrece tres métodos para manipular datos y procesar imágenes de este modo:

getImageData(x, y, ancho, alto) :Este método toma un rectángulo del lienzo del tamaño declarado por sus atributos y lo convierte en datos. Retorna un objeto que puede ser luego accedido por sus propiedades width, height y data.
putImageData(datosImagen, x, y) :Este método convierte a los datos en datosImagen en una imagen y dibuja la imagen en el lienzo en la posición especificada por x e y. Este es el opuesto a getImageData().
createImageData(ancho, alto) :Este método crea datos para representar una imagen vacía. Todos sus pixeles serán de color negro transparente. Puede también recibir datos como atributo (en lugar de los atributos ancho y alto) y utilizar las dimensiones tomadas de los datos provistos para crear la imagen. 

La posición de cada valor en el array es calculada con la fórmula (ancho×4×y)+(x×4). Éste será el primer valor del pixel (rojo); para el resto tenemos que agregar 1 al resultado (por ejemplo, (ancho×4×y)+(x×4)+1 para verde, (ancho×4×y)+(x×4)+2 para azul, y (ancho×4×y)+(x×4)+3 para el valor alpha (transparencia). Veamos esto en práctica:
IMPORTANTE: Debido a restricciones de seguridad, no se puede extraer información del elemento <canvas> luego de que una imagen tomada desde una fuente externa fue dibujada en el lienzo. Solo cuando el documento y la imagen corresponden a la misma fuente (URL) el método getImageData() trabajará adecuadamente. Por este motivo, para probar este ejemplo tendrá que descargar la imagen desde nuestro servidor en www.minkbooks.com/content/snow.jpg (o usar una imagen propia), y luego subir esta imagen, el archivo HTML y el archivo con el código Javascript a su propio servidor. Si simplemente trata de ejecutar el siguiente ejemplo en su ordenador sin seguir los pasos previos, no funcionará.

Código 7-25. Generando un negativo de la imagen.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
var imagen=new Image();
imagen.src="snow.jpg";
imagen.addEventListener("load", modificarimagen, false);
}

function modificarimagen(e){
imagen=e.target;
lienzo.drawImage(imagen,0,0);
var info=lienzo.getImageData(0,0,175,262);
var pos;
for(x=0;x<=175;x++){
for(y=0;y<=262;y++){
pos=(info.width*4*y)+(x*4);
info.data[pos]=255-info.data[pos];
info.data[pos+1]=255-info.data[pos+1];
info.data[pos+2]=255-info.data[pos+2];
}
}
lienzo.putImageData(info,0,0);
}
window.addEventListener("load", iniciar, false);

Esta vez tuvimos que crear una nueva función (en lugar de utilizar una función anónima) para procesar la imagen luego de que es cargada. Primero, la función modificarimagen() genera una referencia a la imagen aprovechando la propiedad target usada en publicaciones anteriores. En el siguiente paso, usando esta referencia y el método drawImage(), la imagen es dibujada en el lienzo en la posición 0,0. No hay nada inusual en esta parte del código, pero eso es algo que pronto va a cambiar. 
IMPORTANTE: Los archivos para este ejemplo deben ser subidos a su propio servidor para trabajar correctamente (incluyendo la imagen snow.jpg que puede descargar desde www.minkbooks.com/content/snow.jpg). 
La imagen utilizada en nuestro ejemplo tiene un tamaño de 350 pixeles de ancho por 262 pixeles de alto, por lo que usando el método getImageData() con los valores 0,0 para la esquina superior izquierda y 175,262 para el valor horizontal y vertical, estamos extrayendo solo la mitad izquierda de la imagen original. Estos datos son grabados dentro de la variable info.
Una vez que esta información fue recolectada, es momento de manipular cada pixel para obtener el resultado que queremos (en nuestro ejemplo esto será un negativo de este trozo de la imagen).
Debido a que cada color es declarado por un valor entre 0 y 255, el valor negativo es obtenido restando el valor real a 255 con la fórmula color=255-color. Para hacerlo con cada pixel de la imagen, debemos crear dos bucles for (uno para las columnas y otro para las filas) para obtener cada color original y calcular el valor del negativo correspondiente.
El bucle for para los valores x va desde 0 a 175 (el ancho de la parte de la imagen que extrajimos del lienzo) y el for para los valores y va desde 0 a 262 (el tamaño vertical de la imagen y también el tamaño vertical del trozo de imagen que estamos procesando).

Luego de que cada pixel es procesado, la variable info con los datos de la imagen es enviada al lienzo como una imagen usando el método putImageData(). La imagen es ubicada en la misma posición que la original, reemplazando la mitad izquierda de la imagen original por el negativo que acabamos de crear. 
El método getImageData() retorna un objeto que puede ser procesado a través de sus propiedades (width, height y data) o puede ser usado íntegro por el método putImageData().
Existe otra manera de extraer datos del lienzo que retorna el contenido en una cadena de texto codificada en base64. Esta cadena puede ser usada luego como fuente para otro lienzo, como fuente de un elemento HTML (por ejemplo, <img>), o incluso ser enviado al servidor o grabado en un archivo. El siguiente es el método incluido con este fin: 

toDataURL(tipo) :El elemento <canvas> tiene dos propiedades, width y height, y dos métodos: getContext() y toDataURL(). Este último método retorna datos en el formato data:url conteniendo una representación del contenido del lienzo en formato PNG (o el formato de imagen especificado en el atributo tipo). 

Más adelante en esta serie de publicaciones veremos algunos ejemplos de cómo usar toDataURL() y cómo puede ayudarnos a integrar esta API con otras. 
Conceptos básicos: Los datos del tipo data:url son datos que son presentados en forma de cadena de texto y pueden ser incluidos en nuestros documentos como si se tratara de datos tomados de fuentes externas (por ejemplo, la fuente para imágenes insertadas con la etiqueta <img>). 

Patrones

Los patrones son simples adiciones que pueden mejorar nuestros trazados. Con esta herramienta podemos agregar textura a nuestras figuras utilizando una imagen. El procedimiento es similar a la creación de gradientes; los patrones son creados por el método createPattern() y luego aplicados al trazado como si fuesen un color. 
createPattern(imágen, tipo) El atributo imágen es una referencia a la imagen que vamos a usar como patrón, y tipo configura el patrón por medio de cuatro valores: repeat, repeat-x, repeat-y y no-repeat.

Código 7-26. Agregando un patrón para nuestro trazado.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
var imagen=new Image();
imagen.src="http://www.minkbooks.com/content/bricks.jpg";
imagen.addEventListener("load", modificarimagen, false);
}
function modificarimagen(e){
imagen=e.target;
var patron=lienzo.createPattern(imagen,'repeat');
lienzo.fillStyle=patron;
lienzo.fillRect(0,0,500,300);
}
window.addEventListener("load", iniciar, false);

Hágalo usted mismo: Experimente con los diferentes valores disponibles para createPattern() y también utilizando otras figuras.



Espero haber ayudado en algo. Hasta la próxima oportunidad!

DESCARGAR PUBLICACIÓN










  

domingo, 24 de enero de 2016

Dibujar gráficos en HTML - 3 de 3



  • Sombras
Por supuesto, sombras son también una parte importante de Canvas API. Podemos generar sombras para cada trazado e incluso textos. La API provee cuatro propiedades para hacerlo:
  • shadowColor :Esta propiedad declara el color de la sombra usando sintaxis CSS.
  • shadowOffsetX :Esta propiedad recibe un número para determinar qué tan lejos la sombra estará ubicada del objeto (dirección horizontal).
  • shadowOffsetY :Esta propiedad recibe un número para determinar qué tan lejos la sombra estará ubicada del objeto (dirección vertical).
  • shadowBlur :Esta propiedad produce un efecto de difuminación para la sombra.


Código 7-17. Aplicando sombras.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
lienzo.shadowColor="rgba(0,0,0,0.5)";
lienzo.shadowOffsetX=4;
lienzo.shadowOffsetY=4;
lienzo.shadowBlur=5;
lienzo.font="bold 50px verdana, sans-serif";
lienzo.fillText("Mi mensaje ", 100,100);
}
window.addEventListener("load", iniciar, false);

La sombra creada en el Código 7-17 usa la función rgba() para obtener un color negro semitransparente. Es desplazada 4 pixeles del objeto y tiene un valor de difuminación de 5.
Hágalo usted mismo: Aplique sombras a otra figura en lugar de texto. Por ejemplo, pruebe generar sombras para figuras vacías y sólidas, usando rectángulos o círculos.

  • Transformaciones

LA API Canvas ofrece operaciones complejas que es posible aplicar sobre el lienzo para afectar los gráficos que luego son dibujados en él. Estas operaciones son realizadas utilizando cinco métodos de transformación diferentes, cada uno para un propósito específico. 
  • translate(x, y) :Este método de transformación es usado para mover el origen del lienzo. Cada lienzo comienza en el punto 0,0 localizado en la esquina superior izquierda, y los valores se incrementan en cualquier dirección dentro del lienzo. Valores negativos caen fuera del lienzo. A veces es bueno poder usar valores negativos para crear figuras complejas. El método translate() nos permite mover el punto 0,0 a una posición específica para usar el origen como referencia para nuestros dibujos o para aplicar otras transformaciones.
  • rotate(ángulo) :Este método de transformación rotará el lienzo alrededor del origen tantos ángulos como sean especificados.
  • scale(x, y) :Este método de transformación incrementa o disminuye las unidades de la grilla para reducir o ampliar todo lo que esté dibujado en el lienzo. La escala puede ser cambiada independientemente para el valor horizontal o vertical usando los atributos x e y. Los valores pueden ser negativos, produciendo un efecto de espejo. Por defecto los valores son iguales a 1.0.
  • transform(m1, m2, m3, m4, dx, dy) :El lienzo contiene una matriz de valores que especifican sus propiedades. El método transform() aplica una nueva matriz sobre la actual para modificar el lienzo.
  • setTransform(m1, m2, m3, m4, dx, dy) :Este método reinicializa la actual matriz de transformación y establece una nueva desde los valores provistos en sus atributos.


Código 7-18. Moviendo, rotando y escalando.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
lienzo.font="bold 20px verdana, sans-serif";
lienzo.fillText("PRUEBA",50,20);
lienzo.translate(50,70);
lienzo.rotate(Math.PI/180*45);
lienzo.fillText("PRUEBA",0,0);
lienzo.rotate(-Math.PI/180*45);
lienzo.translate(0,100);
lienzo.scale(2,2);
lienzo.fillText("PRUEBA",0,0);
}
window.addEventListener("load", iniciar, false);

No hay mejor forma de entender cómo funcionan las transformaciones que usarlas en nuestro código. En el Código 7-18, aplicamos los métodos translate(), rotate() y scale() al mismo texto. Primero dibujamos un texto en el lienzo con la configuración por defecto. El texto aparecerá en la posición 50,20 con un tamaño de 20 pixeles. Luego de esto, usando translate(), el origen del lienzo es movido a la posición 50,70 y el lienzo completo es rotado 45 grados con el método rotate(). Otro texto es dibujado en el nuevo origen, con una inclinación de 45 grados. Las transformaciones aplicadas se vuelven los valores por defecto, por lo tanto antes de aplicar el siguiente método scale() rotamos el lienzo 45 grados negativos para ubicarlo en su posición original. Realizamos una transformación más moviendo el origen otros 100 pixeles hacia abajo. Finalmente, la escala del lienzo es duplicada y un nuevo texto es dibujado al doble del tamaño de los anteriores.
Cada transformación es acumulativa. Si realizamos dos transformaciones usando scale(), por ejemplo, el segundo método realizará el escalado considerando el estado actual del lienzo. Una orden scale(2,2) luego de otra scale(2,2) cuadruplicará la escala del lienzo. Y para los métodos de transformación de la matriz, esta no es una excepción. Es por esto que contamos con dos métodos para realizar esta clase de transformaciones: transform() y setTransform().

Código 7-19. Transformaciones acumulativas sobre la matriz.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
lienzo.transform(3,0,0,1,0,0);
lienzo.font="bold 20px verdana, sans-serif";
lienzo.fillText("PRUEBA",20,20);
lienzo.transform(1,0,0,10,0,0);
lienzo.font="bold 20px verdana, sans-serif";
lienzo.fillText("PRUEBA",100,20);
}
window.addEventListener("load", iniciar, false);

Al igual que en el código anterior, en el Código 7-19 aplicamos varios métodos de transformación sobre el mismo texto para comparar efectos. Los valores por defecto de la matriz del lienzo son 1,0,0,1,0,0. Cambiando el primer valor a 3, en la primera transformación de nuestro ejemplo arriba, estiramos el lienzo horizontalmente. El texto dibujado luego de esta transformación será más ancho que en condiciones por defecto.
Con la siguiente transformación, el lienzo fue estirado verticalmente cambiando el cuarto valor a 10 y preservando los anteriores.
Un detalle importante a recordar es que las transformaciones son aplicadas sobre la matriz declarada en previas transformaciones, por lo que el segundo texto mostrado por el código del Código 7-19 será igual de ancho que el anterior (es estirado horizontal y verticalmente). Para reinicializar la matriz y declarar nuevos valores de transformación, podemos usar el método setTransform()
Hágalo usted mismo: Reemplace el último método transform() en el ejemplo por setTransform() y compruebe los resultados. Usando solo un texto, cambie cada valor en el método transform() para conocer la clase de transformación realizada en el lienzo por cada uno de ellos.

  • Restaurando el estado

La acumulación de transformaciones hace realmente difícil volver a anteriores estados. En el código del Código 7-18, por ejemplo, tuvimos que recordar el valor de rotación usado previamente para poder realizar una nueva rotación y volver el lienzo al estado original. 
Considerando situaciones como ésta, Canvas API provee dos métodos para grabar y recuperar el estado del lienzo. 
  • save() :Este método graba el estado del lienzo, incluyendo transformaciones ya aplicadas, valores de propiedades de estilo y la actual máscara (el área creada por el método clip(), si existe).
  • restore() :Este método recupera el último estado grabado.


Código 7-20. Grabando el estado del lienzo.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
lienzo.save();
lienzo.translate(50,70);
lienzo.font="bold 20px verdana, sans-serif";
lienzo.fillText("PRUEBA1",0,30);
lienzo.restore();
lienzo.fillText("PRUEBA2",0,30);
}
window.addEventListener("load", iniciar, false);

Si ejecuta el código del Código 7-20 en su navegador, verá el texto “PRUEBA1” en grandes letras al centro del lienzo, y el texto “PRUEBA2” en letras pequeñas, cercano al origen. Lo que hicimos fue grabar el estado por defecto del lienzo y luego establecer una nueva posición para el origen y estilos para el texto. El primer texto es dibujado con esta configuración, pero antes de dibujar el segundo texto el estado original es restaurado, por lo que este texto es mostrado con los estilos por defecto, no con los declarados para el primero.
No importa cuántas transformaciones hayamos realizado, luego de llamar al método restore() la configuración del lienzo será retornada exactamente a su estado anterior (el último grabado).

  • globalCompositeOperation

Cuando hablamos de trazados dijimos que existe una propiedad para determinar cómo una figura es posicionada y combinada con figuras dibujadas previamente en el lienzo. La propiedad es globalCompositeOperation y su valor por defecto es source-over, lo que significa que la nueva figura será dibujada sobre las que ya existen en el lienzo. La propiedad ofrece 11 valores más:
  • source-in :Solo la parte de la nueva figura que se sobrepone a las figuras previas es dibujada. El resto de la figura, e incluso el resto de las figuras previas, se vuelven transparentes.
  • source-out :Solo la parte de la nueva figura que no se sobrepone a las figuras previas es dibujada. El resto de la figura, e incluso el resto de las figuras previas, se vuelven transparentes.
  • source-atop :Solo la parte de la nueva figura que se superpone con las figuras previas es dibujada. Las figuras previas son preservadas, pero el resto de la nueva figura se vuelve transparente.
  • lighter :Ambas figuras son dibujadas (nueva y vieja), pero el color de las partes que se superponen es obtenido adicionando los valores de los colores de cada figura.
  • xor :Ambas figuras son dibujadas (nueva y vieja), pero las partes que se superponen se vuelven transparentes.
  • destination-over :Este es el opuesto del valor por defecto. Las nuevas figuras son dibujadas detrás de las viejas que ya se encuentran en el lienzo.
  • destination-in :Las partes de las figuras existentes en el lienzo que se superponen con la nueva figura son preservadas. El resto, incluyendo la nueva figura, se vuelven transparentes.
  • destination-out :Las partes de las figuras existentes en el lienzo que no se superponen con la nueva figura son preservadas. El resto, incluyendo la nueva figura, se vuelven transparentes.
  • destination-atop :Las figuras existentes y la nueva son preservadas solo en la parte en la que se superponen.

  • darker :Ambas figuras son dibujadas, pero el color de las partes que se superponen es determinado substrayendo los valores de los colores de cada figura.
  • copy :Solo la nueva figura es dibujada. Las ya existentes se vuelven transparentes.


Código 7-21. Probando la propiedad globalCompositeOperation.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
lienzo.fillStyle="#990000";
lienzo.fillRect(100,100,300,100);
lienzo.globalCompositeOperation="destination-atop";
lienzo.fillStyle="#AAAAFF";
lienzo.font="bold 80px verdana, sans-serif";
lienzo.textAlign="center";
lienzo.textBaseline="middle";
lienzo.fillText("PRUEBA",250,110);
}
window.addEventListener("load", iniciar, false);

Solo representaciones visuales de cada posible valor para la propiedad globalCompositeOperation le ayudarán a comprender cómo funcionan. Con este propósito, preparamos el código del Código 7-21. Cuando este código es ejecutado, un rectángulo rojo es dibujado en el medio del lienzo, pero gracias al valor destination-atop solo la parte del rectángulo que se superpone con el texto es dibujada.
Hágalo usted mismo: Reemplace el valor destination-atop con cualquiera de los demás valores posibles para esta propiedad y compruebe el resultado en su navegador. Pruebe el código en distintos navegadores.

Espero haber ayudado en algo. Hasta la próxima oportunidad!










  

viernes, 16 de octubre de 2015

Dibujar gráficos en HTML - 2 de 3



El método closePath() simplemente agrega una línea recta al trazado, desde el último al primer punto, cerrando la figura.
Usando el método stroke() al final de nuestro trazado dibujamos un triángulo vacío en el lienzo. Para lograr una figura sólida, este método debe ser reemplazado por fill():

Código 7-9. Triángulo sólido.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
lienzo.beginPath();
lienzo.moveTo(100,100);
lienzo.lineTo(200,200);
lienzo.lineTo(100,200);
lienzo.fill();
}
window.addEventListener("load", iniciar, false);

Ahora la figura en la pantalla será un triángulo sólido. El método fill() cierra el trazado automáticamente, por lo que ya no tenemos que usar closePath() para lograrlo.
Uno de los métodos mencionados anteriormente para dibujar un trazado en el lienzo fue clip(). Este método en realidad no dibuja nada, lo que hace es crear una máscara con la forma del trazado para seleccionar qué será dibujado y qué no. Todo lo que caiga fuera de la máscara no se dibujará en el lienzo. Veamos un ejemplo:

Código 7-10. Usando el triángulo anterior como una máscara.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
lienzo.beginPath();<
lienzo.moveTo(100,100);
lienzo.lineTo(200,200);
lienzo.lineTo(100,200);
lienzo.clip();
lienzo.beginPath();
for(f=0; f<300; f=f+10){
lienzo.moveTo(0,f);
lienzo.lineTo(500,f);
}
lienzo.stroke();
}
window.addEventListener("load", iniciar, false);

Para mostrar exactamente cómo funciona el método clip(), en el Código 7-10 utilizamos un bucle for para crear líneas horizontales cada 10 pixeles. Estas líneas van desde el lado izquierdo al lado derecho del lienzo, pero solo las partes de las líneas que caen dentro de la máscara (el triángulo) serán dibujadas. 
Ahora que ya sabemos cómo dibujar trazados, es tiempo de ver el resto de las alternativas con las que contamos para crearlos. Hasta el momento hemos estudiado cómo generar líneas rectas y formas rectangulares. Para figuras circulares, la API provee tres métodos: arc(), quadraticCurveTo() y bezierCurveTo(). El primero es relativamente sencillo y puede generar círculos parciales o completos, como mostramos en el siguiente ejemplo:

Código 7-11. Círculos con arc().

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
lienzo.beginPath();
lienzo.arc(100,100,50,0,Math.PI*2, false);
lienzo.stroke();
}
window.addEventListener("load", iniciar, false);

Lo primero que seguramente notará en el método arc() en nuestro ejemplo es el uso del valor PI. Este método usa radianes en lugar de grados para los valores del ángulo. En radianes, el valor PI representa 180 grados, por lo que la formula PI*2 multiplica PI por 2 obteniendo un ángulo de 360 grados.
El Código 7-11 genera un arco con centro en el punto 100,100 y un radio de 50 pixeles, comenzando a 0 grados y terminando a Math.PI*2 grados, lo que representa un círculo completo. El uso de la propiedad PI del objeto Math nos permite obtener el valor preciso de PI. 
Si necesitamos calcular el valor en radianes de cualquier ángulo en grados usamos la fórmula: Math.PI / 180 × grados, como en el próximo ejemplo:

Código 7-12. Un arco de 45 grados.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
lienzo.beginPath();
var radianes=Math.PI/180*45;
lienzo.arc(100,100,50,0,radianes, false);
lienzo.stroke();
}
window.addEventListener("load", iniciar, false);

Con el Código 7-12 obtenemos un arco que cubre 45 grados de un círculo. Intente cambiar el valor de la dirección a true (verdadero). En este caso, el arco será generado desde 0 grados a 315, creando un círculo abierto.
Una cosa importante a considerar es que si continuamos construyendo el trazado luego del arco, el actual punto de comienzo será el final del arco. Si no deseamos que esto pase tendremos que usar el método moveTo() para cambiar la posición del lápiz, como hicimos anteriormente. Sin embargo, si la próxima figura es otro arco (por ejemplo, un círculo completo) siempre recuerde que el método moveTo() mueve el lápiz virtual hacia el punto en el cual el círculo comenzará a ser dibujado, no el centro del círculo. Digamos que el centro del círculo que queremos dibujar se encuentra en el punto 300,150 y su radio es de 50. El método moveTo() debería mover el lápiz a la posición 350,150 para comenzar a dibujar el círculo.
Además de arc(), existen dos métodos más para dibujar curvas, en este caso curvas complejas. El método quadraticCurveTo() genera una curva Bézier cuadrática, y el método bezierCurveTo() es para curvas Bézier cúbicas. La diferencia entre estos dos métodos es que el primero cuenta con un solo punto de control y el segundo con dos, creando de este modo diferentes tipos de curvas.

Código  7-13. Curvas complejas.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
lienzo.beginPath();
lienzo.moveTo(50,50);
lienzo.quadraticCurveTo(100,125, 50,200);
lienzo.moveTo(250,50);
lienzo.bezierCurveTo(200,125, 300,125, 250,200);
lienzo.stroke();
}
window.addEventListener("load", iniciar, false);


Para la curva cuadrática movimos el lápiz virtual a la posición 50,50 y finalizamos la curva en el punto 50,200. El punto de control para esta curva fue ubicado en la posición 100,125.
La curva generada por el método bezierCurveTo() es un poco más compleja. Hay dos puntos de control para esta curva, el primero en la posición 200,125 y el segundo en la posición 300,125.
Los valores en la Figura 7-2 indican los puntos de control para las curvas. Moviendo estos puntos cambiamos la forma de la curva.

Figura 7-2. Representación de curvas Bézier y sus puntos de control.


Hágalo usted mismo: Puede agregar tantas curvas como necesite para construir su figura. Intente cambiar los valores de los puntos de control en el Código 7-13 para ver cómo afectan a las curvas. Construya figuras más complejas combinando curvas y líneas para entender cómo la construcción del trazado es realizada.

  • Estilos de línea

Hasta esta parte del capítulo hemos usado siempre los mismos estilos de líneas. El ancho, la terminación y otros aspectos de la línea pueden ser modificados para obtener exactamente el tipo de línea que necesitamos para nuestros dibujos. 
Existen cuatro propiedades específicas para este propósito: 
    • lineWidth :Esta propiedad determina el grosor de la línea. Por defecto el valor es 1.0 unidades.
    • lineCap :Esta propiedad determina la forma de la terminación de la línea. Puede recibir uno de estos tres valores: butt, round y square.
    • lineJoin :Esta propiedad determina la forma de la conexión entre dos líneas. Los valores posibles son: round, bevel y miter.
    • miterLimit :Trabajando en conjunto con lineJoin, esta propiedad determina cuánto la conexión de dos líneas será extendida cuando la propiedad lineJoin es declarada con el valor miter.

Las propiedades afectarán el trazado completo. Cada vez que tenemos que cambiar las características de las líneas debemos crear un nuevo trazado.

Código 7-14. Propiedades para probar diferentes estilos de línea.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
lienzo.beginPath();
lienzo.arc(200,150,50,0,Math.PI*2, false);
lienzo.stroke();
lienzo.lineWidth=10;
lienzo.lineCap="round";
lienzo.beginPath();
lienzo.moveTo(230,150);
lienzo.arc(200,150,30,0,Math.PI, false);
lienzo.stroke();
lienzo.lineWidth=5;
lienzo.lineJoin="miter";
lienzo.beginPath();
lienzo.moveTo(195,135);
lienzo.lineTo(215,155);
lienzo.lineTo(195,155);
lienzo.stroke();
}
window.addEventListener("load", iniciar, false);

Comenzamos el dibujo en el Código 7-14 creando un trazado para un círculo completo con propiedades por defecto. Luego, usando lineWith, cambiamos el ancho de la línea a 10 y definimos la propiedad lineCap como round. Esto hará que el siguiente trazado sea más grueso y con terminaciones redondeadas. Para crear un trazado con estas características, primero movimos el lápiz a la posición 230,150 y luego generamos un semicírculo. Los extremos redondeados nos ayudarán a simular una boca sonriente.
Finalmente, agregamos un trazado creado con dos líneas para lograr una forma similar a una nariz. Las líneas para este trazado fueron configuradas con un ancho de 5 y serán unidas de acuerdo a la propiedad lineJoin y su valor miter. Esta propiedad hará a la nariz lucir puntiaguda, expandiendo las puntas de las líneas en la unión hasta que ambas alcancen un punto en común.
Hágalo usted mismo: Experimente con las líneas para la nariz modificando la propiedad miterLimit (por ejemplo, con la instrucción miterLimit=2). Cambie el valor de la propiedad lineJoin a round o bevel. También puede modificar la forma de la boca probando diferentes valores para la propiedad lineCap.

  • Texto

Escribir texto en el lienzo es tan simple como definir unas pocas propiedades y llamar al método apropiado. Tres propiedades son ofrecidas para configurar texto:
    • font :Esta propiedad tiene una sintaxis similar a la propiedad font de CSS, y acepta los mismos valores.
    • textAlign :Esta propiedad alinea el texto. Existen varios valores posibles: start (comienzo), end (final), left (izquierda), right (derecha) y center (centro).
    • textBaseline :Esta propiedad es para alineamiento vertical. Establece diferentes posiciones para el texto (incluyendo texto Unicode). Los posibles valores son: top, hanging, middle, alphabetic, ideographic y bottom.
Dos métodos están disponibles para dibujar texto en el lienzo:
    • strokeText(texto, x, y) :Del mismo modo que el método stroke() para el trazado, este método dibujará el texto especificado en la posición x,y como una figura vacía (solo los contornos). Puede también incluir un cuarto valor para declarar el tamaño máximo. Si el texto es más extenso que este último valor, será encogido para caber dentro del espacio establecido.
    • fillText(texto, x, y) :Este método es similar al método anterior excepto que esta vez el texto dibujado será sólido (igual que la función para el trazado).


Código 7-15. Dibujando texto.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
lienzo.font="bold 24px verdana, sans-serif";
lienzo.textAlign="start";
lienzo.fillText("Mi mensaje", 100,100);
}
window.addEventListener("load", iniciar, false);

Como podemos ver en el Código 7-15, la propiedad font puede tomar varios valores a la vez, usando exactamente la misma sintaxis que CSS. La propiedad textAling hace que el texto sea dibujado desde la posición 100,100 (si el valor de esta propiedad fuera end, por ejemplo, el texto terminaría en la posición 100,100). Finalmente, el método fillText dibuja un texto sólido en el lienzo.
Además de los previamente mencionados, la API provee otro método importante para trabajar con texto:
    • measureText() :Este método retorna información sobre el tamaño de un texto específico.

Puede ser útil para combinar texto con otras formas en el lienzo y calcular posiciones o incluso colisiones en animaciones.

Código 7-16. Midiendo texto.

function iniciar(){
var elemento=document.getElementById('lienzo');
lienzo=elemento.getContext('2d');
lienzo.font="bold 24px verdana, sans-serif";
lienzo.textAlign="start";
lienzo.textBaseline="bottom";
lienzo.fillText("Mi mensaje", 100,124);
var tamano=lienzo.measureText("Mi mensaje");
lienzo.strokeRect(100,100,tamano.width,24);
}
window.addEventListener("load", iniciar, false);

En este ejemplo comenzamos con el mismo Código 7-15, pero agregamos un alineamiento vertical. La propiedad textBaseline fue establecida como bottom (inferior), lo que significa que la base o parte inferior del texto estará ubicada en la posición 124. Esto nos ayudará a conocer la posición vertical exacta del texto en el lienzo. 
Usando el método measureText() y la propiedad width (ancho) obtenemos el tamaño horizontal del texto. Con esta medida estamos listos para dibujar un rectángulo que rodeará al texto.
Hágalo usted mismo: Utilizando el Código 7-16, pruebe diferentes valores para las propiedades textAlign y textBaseline. Use el rectángulo como referencia para comprobar cómo estas propiedades trabajan. Escriba un texto diferente para ver cómo el rectángulo se adapta automáticamente a su tamaño. 

Espero haber ayudado en algo. Hasta la próxima oportunidad!








       
free counters

Páginas vistas en total según Google