Canvas
Profesor: Javier López
Volver
  • ¿Qué es el elemento CANVAS?
  • Varios ejemplos simples
  • Las palabras mágicas
  • Un truco útil
  • ¿Qué es el elemento CANVAS?
    A través del elemento CANVAS (que traducido al español sería 'lienzo') podemos crear imágenes sencillas o complejas creadas de forma dinámica o a través de la interacción con el usuario. Cabe decir que dichas imágenes no son vectoriales (como ocurre con las imágenes SVG) y que se crean utilizando una base sencilla de JavaScript.

    Una de las cosas fundamentales para entender cómo funciona CANVAS es tener claro que existen DOS partes muy diferenciadas. Una donde se crea y ubica el lienzo (vacío) dentro del <body> (en el lugar del html donde tenga que estar ubidado el dibujo) y otra parte que será donde se dibuja (normalmente al final del html, para facilitar la lectura global).

    Vamos a intentar dibujar el siguiente dibujo básico con CANVAS:
    ;

    ¿Qué haces intentando visualizar este contenido de un curso perteneciente a HTML5 con un navegador más antiguo que la barca de Noé?

    Este sencillo dibujo está compuesto por varios elementos en los que se utilizan:
      -Rectángulos (1 para el cielo).
      -1 rectángulo con degradado (para el mar)
      -Múltiples arcos o círculos (8 para las nubes, 1 para el sol y 2 para la isla)
      -Varias líneas (8 para el barco, 4 para el mastil y 3 para la vela)
      -Colores transparentes para la vela y las nubes.

    Paso a paso
    1. Creación del lienzo
    Lo primero que vamos a hacer es crear el lienzo (vacio), indicando un nombre, unas dimensiones (expresadas en píxeles), grosor y color del borde que rodeará al lienzo.
     <canvas id="lienzo" width="500" height="300" style="border:1px solid blue">;
     </canvas>
    
    Aunque el código anterior es totalmente válido, tendríamos que añadir algo de código extra para contemplar aquellos navegadores que no soportan CANVAS. Así, todo lo que escribamos entre <canvas> y </canvas> será interpretado por este tipo de navegadores.
     <canvas id="lienzo" width="500" height="300" style="border:1px solid blue">;
       <p>Tu navegador no soporta CANVAS. Deberías actualizar tu navegador</p>
       <img src="imagen_falsa.png">
     </canvas>
    
    Así, si un navegador -como Internet Explorer 8- accede a esta página se visualizaría el mensaje que está entre <p> y </p>, además de mostrar la "imagen_falsa.png" (que sustituiría a la imagen generada con CANVAS) y que NO sería mostrada por los navegadores que soportan CANVAS.

    2. Dibujar
    Para dibujar dentro de este CANVAS vamos a crear el código correspondiente AL FINAL del todo el html (incluso después de la etiqueta </html> final), quedando el código de la siguiente manera:
     ...
     </html>
     <script type="text/javascript">
       var hoja=document.getElementById("lienzo");
       var dibujo=hoja.getContext("2d");
       /*Aquí escribiremos TODAS las órdenes que nos permiten dibujar dentro del CANVAS*/
     </script>
    
    Estas 4 líneas, aunque seguramente te suenan a chino mandarín mezclado con Bacardí, son necesarias y aunque bastaría con decir que son un peaje necesario que hay que añadir, voy a intentar explicar su utilidad..

    Las dos líneas que empiezan con "var" son necesarias para configurar (crear) el área de dibujo, teniendo en cuenta que en el primer 'var' tenemos que indicar el nombre de id del lienzo que hemos creado inicialmente, que en nuestro ejemplo ha sido lienzo.

    Cuando añadamos código y lo queramos ir probando, deberemos ir sustituyendo la línea del código anterior, es decir:

    /*Aquí escribiremos TODAS las órdenes que nos permiten dibujar dentro del CANVAS*/
    
    ..por el código que vayamos construyendo a continuación.

    Como ir enumerando etiqueta por etiqueta del CANVAS puede ser más mortifero que un largometraje sueco vamos a ir construyendo el dibujo del inicio y vamos a ir comentando las etiquetas que se vayan utilizando.
    Dibujando el Cielo
    Vamos a empezar a crear el elemento que se colocará más al fondo, osea, el cielo..
    Para ello, primero definiremos un color azul (código hexadecimal: #B5CDFF) y
    posteriormente crearemos un rectángulo de ese color:
    lienzo.fillStyle="#B5CDFF";
    lienzo.fillRect(0,0,500,300);
    

    fillStyle (color) sirve para definir el color del relleno que se creará a partir de ese momento.

    fillRect (x, y, alto, ancho) crea un rectángulo (del color especificado con fillStyle).

    En este ejemplo, se indica donde empezará a dibujar (0px/0px) y seguidamente se indica el ancho y alto (en píxeles) (500px/300px), que son precisamente las dimensiones totales del lienzo.

    Dibujando el Sol
    El siguiente elemento a dibujar será el que se encuentre apilado encima del último
    elemento creado (el cielo), que en este caso será el sol.
    Aunque el sol sea un simple círculo amarillo necesitaremos 5 etiquetas para dibujarlo.
    lienzo.fillStyle="#F8FF5A";
    lienzo.beginPath();
    lienzo.arc(290,130,54,0,Math.PI*2,true);
    lienzo.closePath;
    lienzo.fill();
    

    fillStyle (color) sirve para definir el color del relleno que se creará a partir de ese momento.

    beginPath() indica en qué punto se empezará a dibujar una forma.
    Todas las etiquetas que se encuentren entre este beginPath y un closePath final serán las que compogan esta forma sin levantar el pincel del lienzo.

    arc (x, y, radio, ángulo inicial, ángulo final, sentido) dibuja un arco o círculo. Los parámetros que utiliza son: los dos primeros se corresponden con las coordenadas horizontal y vertical, seguido del radio, el ángulo inicial y final, y finalmente el sentido o dirección (true en el sentido de las agujas del reloj o false para el sentido contrario).
    Para crar un círculo el ángulo inicial será siempre 0 y el final se expresa con la fórmula Math.PI*2

    closepath levanta el pincel del lienzo y por lo tanto se finaliza de dibujar la forma.

    fill() colorea el dibujo y cierra las líneas si fuese necesario.

    Dibujando las Nubes
    Las nubes se colocan por encima de lo dibujado hasta el momento, pero el mar
    que se dibujará después las tapará por su parte inferior.
    Las nubes están compuestas de múltiples círculos.
    lienzo.fillStyle="rgba(232,236,247,0.5)";
    lienzo.beginPath();
    lienzo.arc(10,200,80,0,Math.PI*2, true);
    lienzo.arc(88,220,46,0,Math.PI*2, true);
    lienzo.arc(154,199,30,0,Math.PI*2, true);
    lienzo.arc(232,210,62,0,Math.PI*2, true);
    lienzo.arc(320,205,25,0,Math.PI*2, true);
    lienzo.arc(380,200,44,0,Math.PI*2, true);
    lienzo.arc(442,208,23,0,Math.PI*2, true);
    lienzo.arc(498,200,41,0,Math.PI*2, true);
    lienzo.closePath;
    lienzo.fill();
    

    Se utilizan exactamente las mismas etiquetas y en el mismo orden que la forma anterior, tan solo con una pequeña diferencia:

    Con fillStyle="rgba(rojo, verde, azul, transparencia)" se utiliza un color de tipo rgba. Especificando así el color, es posible definir el color con transparencia del relleno (en este caso 0.5, osea un 50% de transparencia).

    Dibujando el Mar
    El mar tapa parte de las nubes y será creado con un rectángulo (fillRect) al que se
    le ha aplicado como color de relleno (fillStyle) de un color de degradado lineal que
    se ha definido previamente.
    var gr=mi_dibujo.createLinearGradient(0,200,0,280);
    gr.addColorStop(0,"#D3DEF3");
    gr.addColorStop(1,"#0628A4");
    mi_dibujo.fillStyle=gr;
    mi_dibujo.fillRect(0,200,500,300);
    
    Para dibujar un degradado lineal, primero con createLinearGradient creamos el documento que definirá cómo tiene que ser el degradado, que se llamará gr. Los 4 datos que necesita son: la coordenada horizontal (0) y vertical (200) desde donde se empezará a aplicar el degradado y seguidamente la coordenada horizontal y vertical hasta dónde llegará el degradado (siempre: del espacio donde se aplique este degradado).
    Como el degradado tiene que ser vertical, la coordenada horizontal se queda igual (0) y únicamente variamos la cantidad vertical. En este caso, el 280 indica que únicamente se aplicará el degradado de color desde la coordenada vertical 200 a la 280, quedando el resto de la superficie que quede de un color plano.

    Con addColorStop (orden, color) vamos añadiendo colores del degradado.

    fillStyle aplica como color de relleno el degradado llamado 'gr'.

    fillRect define el espacio (el rectángulo) al que se aplicará el degradado.
    Como el rectángulo empieza en las mismas coordenadas que 'gr' (0,200) el degradado empezará en la parte superior del rectángulo. Como el rectángulo tiene una altura de 300px y el degradado de 280px, de la coordenada 280 a la 300 el color será plano.

    Dibujando el Casco del barco
    Para crear formas que no son rectángulos ni círculos se utilizan etiquetas propias
    de creación de líneas, que cuando se cierran es posible rellenar de color o dibujar
    sus líneas de contorno.
    mi_dibujo.beginPath();
    mi_dibujo.fillStyle="#656652";
    mi_dibujo.strokeStyle="#3C3F09"
    mi_dibujo.moveTo(300,219);
    mi_dibujo.lineTo(360,219);
    mi_dibujo.lineTo(368,203);
    mi_dibujo.lineTo(296,206);
    mi_dibujo.lineTo(300,219);
    mi_dibujo.closePath;
    mi_dibujo.stroke();
    mi_dibujo.fill();
    

    Con beginPath() indicamos que empezamos a dibujar sin levantar el pincel del lienzo (hasta que se encuentre un closePath).

    fillStyle (color) define el color de relleno.

    strokeStyle (color) define el color del trazo.

    Con moveTo movemos el puntero del pincel a un lugar determinado del lienzo (sin pintar).

    Utilizando lineTo (x, y) vamos creando líneas rectas (desde el punto anterior hasta las coordenadas especificadas).

    closePath levanta el pincel del lienzo y finaliza la forma.

    stroke() dibuja el trazo o las lineas de la forma con el color especificado con strokeStyle.

    fill() dibuja el color de relleno especificado con fillStyle.

    Dibujando la Quilla del barco
    Es la misma forma básica del casco del barco, pero abarcando únicamente la
    parte baja del mismo con un color más oscuro.
    mi_dibujo.beginPath();
    mi_dibujo.fillStyle="#3C3F09";
    mi_dibujo.beginPath();
    mi_dibujo.moveTo(300,219);
    mi_dibujo.lineTo(360,219);
    mi_dibujo.lineTo(364,212);
    mi_dibujo.lineTo(298,214);
    mi_dibujo.lineTo(300,219);
    mi_dibujo.fill();
    

    Se utilizan exactamente las mismas etiquetas y en el mismo orden que en la forma anterior.
    Dibujando el Mástil del barco
    mi_dibujo.fillStyle="#867048";
    mi_dibujo.beginPath();
    mi_dibujo.moveTo(314,205);
    mi_dibujo.lineTo(330,101);
    mi_dibujo.lineTo(334,103);
    mi_dibujo.lineTo(322,204);
    mi_dibujo.fill();
    

    Se utilizan exactamente las mismas etiquetas y en el mismo orden que en la forma anterior.
    Dibujando la Vela del barco
    Para la creación de la vela se utiliza un color de relleno de tipo rgba para poder
    indicar un grado de transparencia.
    mi_dibujo.fillStyle="rgba(210,151,50,0.6)";
    mi_dibujo.beginPath();
    mi_dibujo.moveTo(333,105);
    mi_dibujo.lineTo(378,194);
    mi_dibujo.lineTo(322,188);
    mi_dibujo.lineTo(333,105);
    mi_dibujo.closePath;
    mi_dibujo.fill();
    

    Se utilizan exactamente las mismas etiquetas y en el mismo orden que en la forma anterior.
    Dibujando la Isla
    mi_dibujo.fillStyle="#2E7B10";
    mi_dibujo.beginPath();
    mi_dibujo.arc(100,250,45,-0.3,Math.PI*1.1, true);
    mi_dibujo.arc(135,246,33,-0.3,Math.PI*1.1, true);
    mi_dibujo.closePath;
    mi_dibujo.fill();
    

    En el caso de la isla se ha optado por dibujar dos círculos partidos por casi la mitad variando sus valores de ángulo inicial y ángulo final.

    Así:
    arc (x, y, radio, ángulo inicial, ángulo final, sentido)

    En 'ángulo inicial' se ha especificado -0.3 para que corte el círculo 3 grados por encima desde el centro del círculo.
    Para que el final del contorno del círculo no dé una vuelta entera (que sería multiplicando x 2) y queremos que da un poquito más de media vuelta especificamos 1.1 en la multiplicación por PI.

    Vamos a probar diferentes valores para:

    mi_dibujo.arc(100, 250, 45, -0.3, Math.PI*1.1, true);

    Que corresponde al primer semicirculo que forma la isla:



    Así, si el código tubiese los valores 0, y Math.PI*2 crearíamos un círculo perfecto:
    mi_dibujo.arc(100, 250, 45, 0, Math.PI*2, true);




    Si modificamos el valor del ángulo final a Math.PI*1 crearíamos un semicírculo perfecto:
    mi_dibujo.arc(100, 250, 45, 0, Math.PI*1, true);



    Si modificamos un poco más el valor del ángulo final, dejándolo en 1.1 crearíamos un semicírculo, pero un contorno menos extenso en su parte izquierda:
    mi_dibujo.arc(100, 250, 45, 0, Math.PI*1.1, true);



    Por el contrario, si con un ángulo final en 1, modificamos el ángulo inicial dejándolo en -0.3, podemos ver cómo el semicirculo se recorta por el lado contrario.
    mi_dibujo.arc(100, 250, 45, -0.3, Math.PI*1, true);



    Por lo tanto, si recortamos del lado derecho con -0.3 en el ángulo inicial y recortamos también por el lado izquierdo con 1.1 en el ángulo final, tenemos el resultado final:
    mi_dibujo.arc(100, 250, 45, -0.3, Math.PI*1.1, true);


    Otras etiquetas...
    Existen muchas otras etiquetas que aportan más posibilidades a la herramientas CANVAS, como son:

    strokeRect (x, y, ancho, alto): Dibuja un contorno rectangular (sin relleno).

    createRadialGradient (x1, y1, radio1, x2, y2, radio2): crea un degradado de tipo circular especificando el círculo de inicio y el círculo que limitará el degradado. Osea, el degradado se aplicará en el área que esté comprendida entre el primer y segundo círculo).

    clearRect (x, y, ancho, alto): Borra una zona especificada y hace que ésta sea totalmente transparente.

    lineWidth = grosor: Establece el grosor de las lineas (por defecto es 1).

    lineCap (tipo): Determina el aspecto de los extremos de las líneas (puede ser 'butt' (normal), 'round' (final redondeado) o 'square' (extremo cuadrado)).

    globalAlpha: Establece un nivel de transparencia (de 0-1).

    quadraticCurveTo (x del punto de control, y del punto de control, x del punto final, y del punto final): Dibuja curvas cuadráticas de Bezier (con un solo punto de control enmedio que define el ángulo de la curva).

    bezierCurveTo (x del punto de control 1, y del punto de control 1, x del punto de control 2, y del punto de control 2, x, y): Dibuja curvas cúbicas de Bézier (utilizan dos puntos de control para definir el ángulo de la curva).

    Para más información es muy positivo (aunque poco sano para la salud mental) visitar www.html5canvastutorials.com