Hoy iniciaremos con la recomendación de la W3C sobre CANVAS, para continuar con los post referentes a tecnologías para graficar en html, la última versión del documento de la W3C es del 19 de noviembre 2015, ósea casi fresca la puedes ver aquí, al igual que con la recomendación SVG, sólo será un resumen, tanto SVG y CANVAS son tecnologías amplias y como mi propósito es conocer y ayudar al que quiera aprender, lo más lógico es comenzar por algo, digamos “digerible” para luego profundizar con las bases en todo lo que se refiere a estas dos recomendaciones. Para los que quieren ver el anterior post sobre SVG, aquí esta el link.
CANVAS es un elemento de html y la especificación de la W3C, trata sobre todo lo referente a su msanejo, CANVAS se desarrolló principalmente para crear gráficos en 2 dimensiones, en mis palabras, CANVAS define un lienzo en el documento html, sobre el cual podemos graficar, es similar a SVG, en un próximo post y después de cacharrear un poco con las dos especificaciones, escribiré sobre las diferencias y ventajas de estas tecnologías.
Cuando se busca sobre canvas, hacen mucha referencia de que fue creado para graficar sobre la marcha, eso si, si usando scripting, pero eso también se puede con SVG, mmm bueno algo asi, porque con CANVAS si usamos más scripting para realizar las gráficas (o matachos) de una forma más directa.
Para iniciar definimos un documento html y agregamos un elemento CANVAS y establecemos algunos atributos como el ancho, alto y si queremos un borde para identificar donde está el lienzo para graficar. Lo que es primordial definir es el identificador (atributo id), ya que por medio del identificador vamos a acceder al elemento canvas desde javascript.
Qué podemos hacer en el elemento CANVAS, se puede dibujar texto, figuras geométricas, animaciones, programar eventos (como el clic), además hay muchas librerías javascript de videojuegos basadas en el elemento canvas.
Para pintar (si, si no uso tecnicismos) dentro del elemento CANVAS necesitamos, a nivel de scripting obtener el contexto de renderizado (??? pero qué es, eso?), en mis palabras es identificar el área donde vamos a pintar además de obtener la capacidad de mostrar lo que pintamos, y obtener toda la funcionalidad para graficar, esto se hace en base del identificador del elemento CANVAS, veamos con un ejemplo simple.
<html lang="es">
<head>
<meta charset="UTF-8">
<title>CANVAS</title>
<style type="text/css">
.lienzo{
border: 1px solid;
}
</style>
</head>
<body>
<canvas id="lienzo" class="lienzo" width="500" height="500"></canvas>
</body>
</html>
En el anterior código, en específico la etiqueta CANVAS, se define el espacio donde se va a graficar, o sea un cuadro de 500px X 500px, listo con esto tenemos el primer paso para usar el elemento CANVAS.
Ahora viene lo interesante, graficar, para esto vamos a usar javascript, vamos a empezar por un ejemplo simple, pero que servirá de punto de partida. vamos a pintar un rectángulo con un color, lo cual veremos en el siguiente código.
<html lang="es">
<head>
<meta charset="UTF-8">
<title>CANVAS</title>
<style type="text/css">
.lienzo{
border: 1px solid;
}
</style>
</head>
<body>
<canvas id="lienzo" class="lienzo" width="500" height="500"></canvas>
<script type="text/javascript">
var canvas = document.getElementById('lienzo');
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#5555ff";
ctx.fillRect(10,10,100,100);
</script>
</body>
</html>
El anterior código se agrego una parte de javascript, en la primera línea del código javascript hacemos referencia al elemento CANVAS.
1 - var canvas = document.getElementById('lienzo');
La segunda línea es la que realiza la magia para que accedemos a las funcionalidades de dibujo, esto es obtener el contexto del elemento CANVAS lo cual incluye el área para pintar y todos los métodos para pintar, realizando este llamado ya podemos empezar a pintar sobre el elemento CANVAS.
2 - var ctx = canvas.getContext("2d");
La tercera línea del código javascript es para definir un estilo de relleno de un objeto o figura, en este caso definimos el color de relleno con el hexadecimal 5555ff, que es un color de la gama de los azules.
3 - ctx.fillStyle = "#5555ff";
La cuarta línea es para indicarle al contexto que pinte un rectángulo en el elemento CANVAS definido, en este método definimos las coordenadas de donde va iniciar el rectángulo y su ancho y alto, los dos primeros valores son las coordenadas dentro del lienzo, en eje x 10 y en eje y 10, el tercer valor es el ancho y el cuarto valor es el alto.
4 - ctx.fillRect(10,10,100,100);
Fácil verdad, pero te estarás preguntando (si, si, te escucho agudamente), ¿puedo poner el código javascript arriba dentro de la etiqueta meta?, pues de poder, si puedes, pero se generará el siguiente error: Uncaught TypeError: Cannot read property 'getContext' of null, esto significa que no entiende la propiedad getContext del elemento CANVAS, y esto se debe a que primero se está ejecutando el javascript y en ese momento digámoslo de alguna forma, no se ha creado nuestro elemento CANVAS aún, por tal motivo al no cargar ningún objeto en la variable canvas no va a reconocer el método getContext, por eso ubicamos el código javascript después de la etiqueta CANVAS.
Para hacer corto el post voy a describir algunas de los métodos para dibujar figuras y luego se dejará un código html con algunos ejemplos sencillos.
Métodos para graficar en CANVAS
hay tres atributos que casi por regla se deben definir para dibujar las figura, uno es para definir el estilo de fondo de la figura, otra es para definir el estilo del borde o trazo de la figura, otra es para definir el grosor de la línea, iniciaré por estos atributos.
lineWidth: Define el grosor de las líneas, y acepta números entre mayor sea el número más gruesa será la líneas; ej: para todos los ejemplo el contexto lo nombrare ctx, ej: ctx.lineWidth = “4”.
strokeStyle: Se usa para definir el color de la línea, se hereda a la línea que dibuja la figura, este atributo acepta colores, gradientes o texturas (ups! mejor en inglés, pattern) ej: ctx.strokeStyle = “red”
fillStyle: Se usa para definir el estilo de fondo de las figuras, en mis palabras es el relleno del matacho (“aaahyy que brusco”, pues si, asi soy), acepta colores (hexadecimal, o la palabra del color), gradientes y texturas, ejemplo: ctx.fillSyle = “#3333AA”.
También existen tres métodos que casi por regla se deben usar para dibujar las figuras y trazos, uno de estos es un poco complejo de explicar y la dejare de último.
stroke(): se usa para aplicar el estilo definido para las líneas, en mis palabras que se hagan visibles las líneas con el estilo que se definió (uuff me pase de palabras).
fill(): se usa para aplicar el estilo de relleno para las figuras, o sea, que se haga visible el relleno de los matachos.
beginPath(): Bueno este es un poco complejo de explicar, a ver, en mis palabras es como definir una capa en la cual vamos a dibujar figuras con unos estilos de líneas y de relleno aplicables a todas las figuras en esa capa (fue lo mejor que se me ocurrió), como ejemplo pensemos en algo como, queremos pintar dos rectángulos, uno con las líneas de color rojo y el otro con las líneas de color azul, si solo definimos un solo beginPath() los dos rectángulos quedarán con el color de línea que se definió al final (bueno al primer rectángulo será la suma de los dos colores, rojo y azul), para que los dos queden con color de línea definido, toca definir un beginPath() para cada uno, algo así.
aquí quedan del mismo color
ctx.beginPath();
ctx.strokeStyle = "red";
ctx.rect(10,10,50,50);
ctx.stroke();
ctx.strokeStyle = "blue";
ctx.rect(80,10,50,50);
ctx.stroke();
aqui si se pintan del color definido
ctx.beginPath();
ctx.strokeStyle = "red";
ctx.rect(10,10,50,50);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = "blue";
ctx.rect(80,10,50,50);
ctx.stroke();
Después de este ejemplo pensaríamos que beginPath() limpia los estilos actuales y los establece a los nuevos definidos, es una buena explicación, pero lo mejor que puedes hacer es ir a la recomendación de la W3C sobre CANVAS y verifiques como lo definen.
Ahora vamos con los métodos para pintar figuras.
moveTo(x, y): se usa para posicionar un punto, en el plano, se usa como punto inicial para pintar una línea, los parámetros entrada son las posiciones de cartesianas en el eje X y eje Y, cuando el contexto solicitado es de 2 dimensiones (canvas.getContext("2d")), si, si también podemos solicitar un contexto en 3 dimensiones, para esto solicitamos un contexto con WebGL que es una API basada en OpenGL ES 2.0, en un futuro post escribiré sobre ello, por el momento centrémonos en CANVAS para 2 dimensiones.
Ej: moveTo(10, 50)
lineTo(x, y): se usa para definir el punto final de una línea, los parámetros de entrada son las coordenadas en eje X y eje Y, ej: lineTo(100, 100).
para pintar una línea necesitamos de las dos funciones anteriores seguido de strokeStyle y de stroke() para que se pinte.
ctx.beginPath();
ctx.moveTo(10, 20);
ctx.lineTo(100, 30);
ctx.strokeStyle = "blue";
ctx.stroke();
lineCap: Atributo para definir cómo finaliza los extremos de una línea, por defecto es butt que es rectangular, round es redondeada, y square para mi es parecida a butt pero aumenta un poco diámetro de la línea pero es de mucha utilidad para cuando se usan líneas con el estilo round ya que está también aumente un poco el diámetro de la línea.
arc(x, y, radio, anguloInicial, anguloFinal, [direccion]): se usa para definir arcos o circunferencias, los dos primeros parámetros son para definir el centro de la figura, x punto central en el eje x, y punto central en el eje y, el tercer parámetro es el radio que define la línea imaginaria desde el centro al borde del círculo, el cuarto parámetro es el ángulo inicial (anguloInicial), el quinto parámetro es en ángulo final (anguloFinal), tanto el anguloInical y anguloFinal definen la porción del círculo que se va a pintar, esto se puede calcular con la función de radianes (porción * número PI), la porción la podemos ver como el círculo dividido en cuatro partes iguales y el número PI es aprox 3.1416, cada porción la podemos definir con un número la primera es el valor de 0, la segunda 0,5, la tercera 1, la cuarta 1,5 y la quinta 2 que sería el círculo completo, pero para pintarlo necesitamos del número PI para dar a cada punto el aspecto circular, jejeje, explique tal cual como se me ocurrio como lo ideo mi cabeza, mis disculpas, en el siguiente enlace está la explicación formal Radián (https://es.wikipedia.org/wiki/Radi%C3%A1n), el quinto parametro es la direccion, es opcional y define en que direccion va el a pintar el circulo true se pinta hacia la izquierda, false se pinta a la derecha (en sentido a las manecillas del reloj) que es el valor por defecto.
ej:
ctx.beginPath();
ctx.arc(100, 80, 40, 0, 2*3.1416, false);
ctx.strokeStyle = "blue";
ctx.stroke();
ctx.beginPath();
ctx.arc(200, 80, 40, 0, 1*3.1416, false);
ctx.strokeStyle = "red";
ctx.stroke();
rect(x, y, width, height): Se usa para pintar un rectángulo, parámetros, x e y es el punto inicial del rectángulo, width ancho y height alto.
ej:
ctx.beginPath();
ctx.rect(188, 50, 200, 100);
ctx.fillStyle = 'yellow';
ctx.fill();
ctx.lineWidth = 7;
ctx.strokeStyle = 'black';
ctx.stroke();
Estas tres figuras (líneas, rectángulos y círculo), completamos se pueden combinar para realizar otro tipo de figuras.
Funciones y atributos para texto
font: Este atributo sirve para definir la decoración, el tamaño y tipo de letra del texto a dibujar.
ej: ctx.font = 'italic 30pt Calibri';
Existen dos funciones para pintar texto en el elemento CANVAS
fillText(‘texto’, x, y): para pintar texto, parametros, ‘texto’, es el texto que se desea dibujar, x e y es el punto inicial de donde se empezará a pintar, junto a esta función se usa el atributo fillStyle para definir el color del texto, en mis palabras, es como definir un texto de “fondo algo así”.
ej:
ctx.fillStyle = '#333';
ctx.fillText('canvas pa graficar', 150, 100);
strokeText(‘texto’, x, y): para pintar texto, parametros, ‘texto’, es el texto que se desea dibujar, x e y es el punto inicial de donde se empezará a pintar, junto a esta función se usa el atributo strokeStyle para definir el color de las líneas de borde del texto, también se debe usar el atributo lineWidth para definir el grosor de la linea de borde del texto.
ctx.lineWidth = 2;
ctx.strokeStyle = 'blue';
ctx.strokeText('canvas pa graficar', 150, 100);
bezierCurveTo(x2, y2, x3, y3, x4, y4): se usa con moveTo(x1, y1) para definir una línea curva personalizada.
ej:
ctx.moveTo(20,20);
ctx.bezierCurveTo(20,100,200,100,200,20);
Esta función define la línea curva en base a cuatro puntos, el primer punto (x1, y1) es el que nos da la función moveTo lo llamaremos punto inicial, también se toma como punto inicial el último punto que se a pintado, los cuatro primeros parámetros de bezierCurveTo (x2, y2, x3, y3) son puntos de control, y los parametros quinto y sexto (x4, y4) definen el punto final; lo anterior es tecnicismo pero para mi es dificil de ver, voy a tratar de explicarlo con mis ideas que rondan mi cabeza y con la ayuda de tu imaginación.
Tomemos primero el punto inicial (x1, y1) y el punto final (x4, y4), si unimos estos dos punto pintamos una línea (PASO 1). Ahora el segundo punto (x2, y2) que es uno de los puntos del control, este punto lo ubicamos por encima de la línea y más cerca del punto inicial, y el tercer punto (x3, y3) lo ubicamos por debajo de la línea y más cerca del punto final (PASO 2), ahora imaginemos que los puntos inicial y final siempre van a ser fijos inamovibles y que los puntos de control (segundo punto y tercer punto), son gravedad y atraen a la línea, esto hará que la línea en su punto inicial más o menos al centro tire hacia el punto de control (x2, y2) y que del centro al final de la línea tire hacia el punto de control (x3, y3) (PASO 3).
Si tu imaginación no alcanza a pintar las palabras que lees, no te preocupes aquí hay unas gráficas, que espero sean de claridad.
PASO 1
PASO 2
La parte de la gravedad si la debes imaginar, si no, me tocaría hacer una animación
PASO 3
Hay otras funciones que describiré más adelante en algún otro post donde haga uso de CANVAS, pero por el momento con las que tenemos podemos pintar diferentes objetos.
Bueno, realmente cuando inicie el post pense hacerlo más corto que el anterior de SVG, pero, ya saben mis ideas rondan (jeje, es falta de atención que llaman), y me hacen escribir de más, pero al revisar el material meda gusto y el cerebro me dice “te ganaste la chela”; me demore un tiempo considerable para finalizar este post, entre las fiestas de diciembre y la locha de enero, espero que el siguiente post sea rápido y trate el tema que me interesa que es el de graficas estadisticas, pero en este mundo predomina lo variable o eso es lo que siento.
Ahora dejo el ejemplo de código en jsfiddle, para que lo analisen y practiquen, prueben en quitar los beginPath() a ver que se encuentran.
Espero como siempre ayudar al que lo requiere y ya saben disfruten la vida con lo que más les gusta, AL final de todo, nada queda, nada te llevas, si señores nada.
Saludos