Una de las novedades de HTML5 es el objeto canvas. Hoy vamos a aprovecharlo para dibujar un poquito con él gracias a Jquery, que nos permite ejecutar funciones según el ratón se mueve, gracias al evento mousemove.

Si queréis un poco de información básica sobre canvas os recomiendo esta entrada de Vagabundia.


var canvas,
ctx,
color="rgba(0,0,0,.2)",
miPrimerPincelPropiamentePropio={
xAnt:0,//Posiciones anteriores
yAnt:0,

init:function(){
//Aquí irían las configuraciones no variables
canvas.width=400;
canvas.height=300;
//grosor de la línea
ctx.lineWidth=1;
ctx.strokeStyle=color;
ctx.fillStyle=color;
},

dibujo:function (x,y) {
//Configuramos xAnt e yAnt
if(this.xAnt==0||this.yAnt==0){
this.xAnt=x;
this.yAnt=y;
}
//color de la línea y del relleno
//(aunque ahora no hay relleno)
ctx.beginPath();
//nos movemos a la posición actual
ctx.moveTo(x,y);
//Hacemos una línea a la posición anterior
ctx.lineTo(this.xAnt,this.yAnt);
//pintamos la línea
ctx.stroke();
//guardamos los
this.xAnt=x;
this.yAnt=y;
}
}
//cambio de color de prueba
$('#rojo').bind('click',function(e){
ctx.strokeStyle='rgba(255,0,0,.4)';
ctx.lineWidth=4
});

$(function(){//Cogemos canvas y contexto
canvas = document.getElementById('democanvas');
ctx = canvas.getContext('2d');
//iniciamos el pincel
miPrimerPincelPropiamentePropio.init();

$(canvas).bind('mousemove',function(evento){
var canvasOffset=$(canvas).offset(),
//hallamos la posición: page x-y es con respecto al ratón,
//offset con respecto al borde del canvas
posX=Math.floor(evento.pageX-canvasOffset.left),
posY=Math.floor(evento.pageY-canvasOffset.top);
//llamamos a la función de dibujo.
miPrimerPincelPropiamentePropio.dibujo(posX,posY)
});
});

El resultado sería algo así:

Utilizas un navegador no soportado

Y ahora otro de regalo, con formas aleatorias (aunque reconozco que no es demasiado bonito). En verde y rojo gana (se debería de ver más claro):

Utilizas un navegador no soportado

Para terminar, me gustaría deciros que he probado a hacer un fondo de blog a lo Paul Irish, con un pincel de Script-tutorials, pero que no ha salido igual :)

14 pensamientos en “Dibujar con la etiqueta Canvas y jQuery

  1. Imagen de Clara el dijo:

    En primer lugar, no he entendido nada de lo que has escrito, porque hace mucho tiempo que me perdí. Pero me lo he pasado como una enana, pues cuando he pasado el ratón, y se empezó a pintar, he estado un rato pintando. ¡Es muy chulo! Aunque reconozco que me gusta más el segundo, porque tiene unas formas muy raras, y si pasas el ratón muy rápido, parece una línea muy fina, y si vas más lento, salen como triángulos. Muy bueno ;)

    • Imagen de Emilio Cobos Álvarez el dijo:

      Gracias, de todas maneras es una de las primeras veces que uso la etiqueta canvas, así que supongo que con el tiempo podré hacer cosas mucho más bonitas.

      Siento que no entiendas esto (no te culpo), tengo que seguir con las "lecciones básicas", que ya es hora :)…

  2. Imagen de AnonymousAnonymous el dijo:

    Hola, muy bueno, aunque, para ser honesto, tambien me perdió bastante. Me interesa porque estoy interesado en ésto en particular, dibujar sobre el canvas, en fin, comoquiera, Muchas Gracias =D
    PD.: te quedo bien padre!

    • Imagen de Emilio Cobos Álvarez el dijo:

      Lo siento si te perdiste, pero para esto en concreto es necesario tener una pequeña base de Javascript.

      Para dibujar con el canvas es fácil con el evento mousemove, aunque jQuery lo hace aún más con sus utilidades.

      Si te es necesario dímelo y lo explicaré lo más detallado posible :) .

  3. Imagen de ana morenoana moreno el dijo:

    Hola Emilio, mira me ha encantado el articulo que presentas porque es precisamente lo que necesito para una aplicacion en php que estoy realizando y que tiene una parte donde el cliente tiene que firmar. Este script me viene genial. Pero no controlo jquery (pero no me resulta dificil).
    El caso es que tengo un formulario donde un campo es una imagen y esta la cogeria de este script que presentas. Me he quedado un poco desorientada porque no se que codigo necesitaria para llamar a dicho script y que saliera andando
    Pero no controlo jquery. Me he descargado las librerias y ya las tengo instaladas. Tengo idea de php. ¿podrias echarme una mano? Gracias

    • Imagen de Emilio Cobos Álvarez el dijo:

      Claro! :)

      La idea sería hacer algo como esto, que proponen en StackOverflow. Sería ideal, pero hay un problema: no funcionará en IE ni en versiones antiguas de los navegadores. Básicamente, consistiría en hacer un archivo (Blob) a partir de la cadena en base64 obtenida del canvas. Ésto lo podrías hacer cuando se fuera a enviar el formulario:

      /*Suponiendo que estamos en el evento onsubmit del formulario*/
      var archivo = dataUrlABlob(canvas.getAsDataUri('image/jpeg')),
      formData = new FormData(this);
      formData.append("firma", archivo);
      // enviar el formulario...

      Lo dicho, el problema es el soporte.

  4. Imagen de Ana Moreno GaleanoAna Moreno Galeano el dijo:

    EL CODIGO HTML USADO EN EL COMENTARIO ANTERIOR ES ESTE:
    <td><canvas id="lienzo1" style="width: 350px; height: 90px; background: #fff;"></canvas> <input name="firma_rehmy" id="firma_rehmy" type="hidden"/></td>

    • Imagen de Emilio Cobos Álvarez el dijo:

      Deberías usar algo así:

      
      var haySoporte = window.atob && window.ArrayBuffer && window.Uint8Array && window.FormData && window.BlobBuilder;
      
      function dataURIABlob(dataURI) {
      	var byteString = atob(dataURI.split(',')[1]),
      	mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0],
      	ab = new ArrayBuffer(byteString.length),
      	ia = new Uint8Array(ab),
      	bb = new BlobBuilder();
      	for (var i = 0; i < byteString.length; i++) {
      		ia[i] = byteString.charCodeAt(i);
      	}
      	bb.append(ab);
      	return bb.getBlob(mimeString);
      }
      if( haySoporte ) {
      	var canvas = document.getElementById('lienzo1');
      	$('#miFormulario').on('submit', function(e) {
      		var data = new FormData(this),
      			archivo = dataUrlABlob(canvas.getAsDataUri);
      		data.append('firma_rehmy', archivo);
      		// Enviar el formulario
      		$.ajax({
      			url: this.action,
      			data: data,
      			processData: false,
      			contentType: false,
      			type: 'POST',
      			success: function(data){
      				alert("Formulario enviado!");
      			}
      		});
      		e.preventDefault();
      	});
      }
      
  5. Imagen de Ana Moreno GaleanoAna Moreno Galeano el dijo:

    Gracias Emilio por tu aporte, pero tengo dudas:
    ¿Podrias explicarme lo del soporte? Es por mi sistema operativo?
    Lo entiendo mas o menos, pero en la parte de $.ajax me pierdo
    ¿Puedes explicarme estas lineas:
    1. var data = new FormData(this),
    2. archivo = dataUrlABlob(canvas.getAsDataUri);
    3. data.append(‘firma_rehmy’, archivo);
    ?
    Utilizo POO y tengo que conseguir que en la matriz $_POST se grabe ese campo que recoge la firma del cliente y de la empresa. Para que mas o menos sepas como tengo el codigo te lo presento:
    El codigo que tengo es este:

    <?php incluir_plantillas("header.php"); ?><?php include("firma.js");
    if (isset($_POST["submit"])){
    	$findeobra = new Findeobra();
    	$_POST["fecha"] = grabar($_POST["fecha"]);
    	$findeobra = $findeobra->instanciar($_POST);
    
    	if($findeobra->crear()){
    		$mensaje = "Se ha enviado el Documento Fin de Obra";
    	}
    	else{
    		$mensaje = "No se ha enviado el Documento Fin de Obra";
    	}
    }
    ?>
    
    <div id="cuerpo">
    <h3 align="right">Creando Nuevo Documento Fin de Obra </h3>
    <?php
    if(isset($mensaje)){
    	echo "<p>{$mensaje}</p>";
    }
    ?>....mas cosas
    
    <form action="new_findeobra.php" method="post" id="formu_findeobra">
    <<!--  AQUI VAN LAS FIRMAS -->
        <tr>
        <td><canvas id="lienzo1"  style="width: 350px; height: 90px; background: #fff;"></canvas> 	<input type="hidden"  name="firma_rehmy" id="firma_rehmy"/>	</td>
    	    <td><canvas id="lienzo2"  style="width: 350px; height: 90px; background: orange;"></canvas></td>
    	<input type="hidden"  name="firma_cliente" id="firma_rehmy"/>  </tr><!--  FIN DE LAS FIRMAS-->  
    ... mas cosas
    

    He probado a copiar y modificar las variables pertinentes en mi codigo, pero cuando reviso los datos en phpmyadmin me aparece que en ese campo firma que es de tipo blob tiene 0 bytes, total, que no se guarda nada. Gracias de antemano.

  6. Imagen de Emilio Cobos Álvarez el dijo:

    Con formData y $.ajax enviamos el formulario via ajax (sin que se recargue la página). A todo esto, lo siento, me faltaba un pequeño detallito y es la línea con el e.preventDefault(); Deberías de eliminar el <input type="hidden" name="firma_cliente" id="firma_rehmy"/>, ya que se encarga de enviarlo la función.

    Lo del soporte me refiero a los navegadores… En principio esto sólo funcionaría en Chrome/firefox. Por eso tras el if(haySoporte) deberías colocar un else para los navegadores que no lo soportan.

    Ten en cuenta que el Blob es un archivo, y que por lo tanto no es accesible desde $_POST, sino desde $_FILES.

    Prueba a ver con un var_dump($_FILES); si se recibe el archivo en new_findeobra.php ;)

    • Imagen de Ana Moreno GaleanoAna Moreno Galeano el dijo:

      Hola Emilio, despues de lo que me has explicado he realizado un var_dump($_FILES) y me dice
      array empty
      * Y esto me sale cuando hago un print_r($_POST):
      Array ( [nexpediente] => 1234 [razonsocial] => AAA [repcliente] => AAA [dir] => AAA [fecha] => 11-01-2013 [observaciones] => [submit] => Enviar Datos )

      Es decir que todos los datos los recoge, excepto el contenido del canvas. ¿Que estoy haciendo mal? Gracias de antemano por tu respuesta.

    • Imagen de Ana Moreno GaleanoAna Moreno Galeano el dijo:

      Claro que he cambiado el id de mi formulario. Y no me sale el alert de “Formulario enviado”. Es como si se saltara esa parte de guardar el contenido del canvas porque los otros datos que transfiero a través de POST si se guardan en la base de datos.

      ¿Habria alguna manera (si no es mucha molestia) de enviarte mi codigo-es cortito- para que le echaras un vistazo? Estoy un poco desesperada.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Puedes usar las siguientes etiquetas y atributos HTML:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre data-language=""> <ul> <ol> <li>
Para poner código usa <pre data-language="[lenguaje]"><code>[código]</code></pre>, y no olvides escapar el HTMl.