Herramienta de zoom con canvas de HTML 5

En post anteriores ya habíamos hablado del método drawImage() y también de cómo dibujar constantemente sobre nuestro lienzo. En este ejercicio vamos a utilizar estas dos opciones para crear algo útil. una herramienta de zoom. El canvas se convertirá en una pequeña lupa que acompañará al mouse mientras se encuentre sobre la imagen.

Respondiendo al click

En los ejercicios para trabajar (archivo inicio.html) vamos a comenzar como se quedó el archivo del ejercicio anterior. Lo primero que vamos a hacer es ajustar un poco el código para que se dibuje la foto hasta que el usuario haga click en la imagen.

Parecido al ejercicio de la animación, vamos a hacer una función previa a la de dibujo, en la cual vamos a dar de alta a la variable contexto, pero también vamos a registrar el evento de click a la imagen. Primero en la etiqueta <body> se sustituye la función que debe llamar al cargar. Como esta acción la realiza al iniciar la página, la llamaremos inicio()

<body onLoad="inicio()">

Dentro de la etiqueta <script> definimos la función y ponemos la asignación de la variable contexto. Muy importante, como esta variable se va a usar en dos funciones, debemos declararla global.

var contexto;
function inicio(){
 contexto = document.getElementById("elCanvas").getContext("2d"); 
}

Después de la asignación de la variable, registramos el listener de click a laFoto. La función inicio() queda de la siguiente manera.

function inicio(){
 contexto = document.getElementById("elCanvas").getContext("2d");
 laFoto.addEventListener("click",dibujar); 
}

Y la función dibujo()

function dibujar(){
 contexto.drawImage(laFoto, 200 , 100, 120, 120, 50, 50, 180, 180);
 }

Revisando el archivo en el navegador, la imagen no aparece en el canvas hasta que se le de click. Eso está bien, sin embargo siempre pone el mismo pedazo de imagen ¿No sería más interesante que pusiera el pedazo de imagen de acuerdo al lugar donde se hiciera click?




Detectando la posición del mouse

Para los que no saben o ya lo tienen olvidado, dentro de javascript ocurre que cada vez que se dispara un evento (como el click) le envía a la función un objeto de datos, conocido como el objeto event. Este objeto trae una serie de propiedades bastante útiles, como el tipo de evento ocurrido (type), o quién disparó la acción (target). Sin embargo, en este caso vamos a usar otras propiedades menos famosas, las cuales se llaman clientX y clientY. Como se puede sospechar un poco por su nombre, nos dicen las coordenadas en x y y en donde se disparó el evento. Muy importante, esta información es con respecto al documento, NO con respecto a la imagen.

Usando clientX y clientY, y aprovechando que la imagen está en la parte superior izquierda del archivo, vamos a decirle a la función de drawImage() que dibuje desde este punto. Para mantener un poco de limpieza en el código, antes de usarlas las vamos a poner guardar en variables con un nombre más corto. Y de paso, debemos definir como parámetro al objeto event, el cual se llamará en evento.

function dibujar(evento){
 var posX = evento.clientX;
 var posY = evento.clientY;
 contexto.drawImage(laFoto, posX , posY, 120, 120, 50, 50, 180, 180);
}

Con este cambio, ahora al dar click sobre la imagen, se toma un pedazo de la foto desde el lugar donde se encuentra el mouse. O casi.

Ajustes de posición y de evento.

Dependiendo de la foto que se utilice puede ser más o menos notorio, pero en realidad no está tomando como referencia el mismo punto. Hay un ligero desface. Y esto se debe a lo que ya habíamos mencionado antes, que clientX y clientY nos dan la posición del mouse con respecto al documento, a body. Y la foto en realidad está un poco movida hacia abajo y hacia la derecha. Esto se debe a que de manera predeterminada siempre hay un pequeño margen. Para resolverlo, usando css vamos a decirle al body que no tenga márgenes arriba ni a la izquierda.

Dentro de la etiqueta  de la página, ponemos una regla para body.

body{
 margin-top:0px;
 margin-left:0px; 
}

Listo, la posición quedó ajustada. Ahora ¿No sería más divertido que fuera el cambio más rápido, sin necesidad de hacer click? Vamos a cambiar el evento de laFoto, para que llame a la función cada vez que se mueva el mouse sobre laImagen. Simplemente sustituimos el evento click por mousemove.

laFoto.addEventListener("mousemove",dibujar);

Ajustes de diseño

Podemos darnos cuenta que el canvas es demasiado grande para el dibujo de la foto, así que haremos unos cambios para que sea más pequeño. De paso, haremos que nuestra herramienta de zoom sea al 200% y no al 150%. Entonces el dibujo será de 240 x 240.

Primero, en la etiqueta <canvas> cambiamos el alto y ancho.

<canvas id=”elCanvas” width=”240″ height=”240″>

Dentro de la función drawImage(), cambiaremos los valores 5 a 9, para decir que el dibujo en el canvas sea desde la coordenada 0, 0 y que mida 240 x 240, igual que la etiqueta.

contexto.drawImage(laFoto, posX , posY, 120, 120, 0, 0, 240, 240);

Con esto, el resultado se vería de la siguiente manera.

canvaszoom01

La siguiente parte, es darle más aspecto de lupa. Por estilos, vamos a hacer el canvas redondo, que tenga un poco de borde y además una sombra. Dentro de la etiqueta <style> escribimos la siguiente regla:

canvaszoom02

Siguiendo el cursor y ajustando la mirilla.

Está un poco raro que el zoom quede a un lado. Para que siga al mouse, vamos a jugar con las propiedades left y top del canvas, para que se encuentren cerca del cursor. Recordemos que si queremos modificar estas propiedades, el elemento debe tener una posición como absoluta o relativa. Dentro de la regla del canvas le indicamos que sea absolute.

#elCanvas{
 border-radius:120px;
 border:3px solid black;
 box-shadow:8px 8px 5px rgba(0,0,0,.5);
 position:absolute; 
}

Ahora en la función de dibujar le indicamos por javascript que las propiedades left y top sean las de las variables que usamos para seleccionar el punto de dibujo del canvas. Es decir: posX y posY.

function dibujar(evento){
 var posX = evento.clientX;
 var posY = evento.clientY;
 contexto.drawImage(laFoto, posX , posY, 120, 120, 0, 0, 240, 240);
 elCanvas.style.left = posX + "px";
 elCanvas.style.top = posY + "px";
}

Con este cambio, en cuanto el mouse entra a la foto, el canvas sigue al mouse. Moviéndonos hacia la izquierda y/o arriba funciona bien, pero hacia la derecha o abajo se detiene el movimiento. ¿Por qué? Muy simple. Al hacer esto entramos al área del canvas, con lo cual dejamos de estar encima de la foto. El canvas nos tapa. Para mejorar esto, vamos a decir que el mouse no esté exactamente encima del mouse, sino que quede un poco separado. Le vamos a poner una separación de 10 pixeles, pero eso pueden ajustarlo a su propio gusto.

Las dos últimas líneas de la función dibujar() quedarán de la siguiente manera.

elCanvas.style.left = (posX + 10) + "px";
elCanvas.style.top = (posY + 10) + "px";

canvaszoom03

El canvas se comporta mejor. Pero ahora nos podemos dar cuenta de otras cosas, como que el punto que señala el mouse no aparece dentro del círculo. Y es que hasta ahora nuestro código indica que el puntero sea la esquina superior izquierda del dibujo. Le vamos a decir que ponga la referencia de la imagen a partir de donde está el mouse menos la mitad del ancho y alto que estamos tomando de la foto. Con esto el dibujo quedará centrado. En este ejemplo, el ancho y alto de la foto (parámetros 4 y 5 de drawImage()), están en 120, por lo que indicaremos que al punto de inicio del dibujo (parámetros 2 y 3) se le reste 60.

contexto.drawImage(laFoto, posX - 60 , posY - 60, 120, 120, 0, 0, 240, 240);

¡Muy bien! Ahora lo que está apuntando el mouse queda en el centro del canvas. Ya solo faltan hacer unos cuantos ajustes.

Mostrar y ocultar la lupa.

Resulta extraño que cuando carga la página, el círculo ya está ahí. Y también que se quede cuando nos salimos del área de la foto.

Esto se puede resolver modificando los estilos por javascript. En esta ocasión jugaremos con la propiedad display del canvas, para decirle que al cargar la página y al salir de la foto, se ponga como “none”. Y que al ponerse sobre la foto, cambie a su valor predeterminado: inline. Por cierto, también se pudo usar con visibility, pero soy fan de display. Gustos personales.

Dentro de la función de inicio, ponemos la siguiente orden.

elCanvas.style.display = "none";

Debajo de esta línea, vamos a añadir el registro a dos eventos más para laFoto, en este caso para que al ponerse encima de esta (mouseover) haga una función para cambiar el display a “inline”, y una para que al salir (mouseout), la vuelva a ocultar.

laFoto.addEventListener("mouseover",mostrar);
 laFoto.addEventListener("mouseout",ocultar);

Ya lo último que se va a hacer es poner las dos funciones que estamos llamando.

function mostrar(){
elCanvas.style.display = "inline";
}
function ocultar(){
elCanvas.style.display = "none";
}




El código final quedó de la siguiente manera:

<!doctype html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Zoom con canvas</title>
<style>
#elCanvas{
 background-color:#FC3;
 border:1px solid black; 
}
body{
 margin-top:0px;
 margin-left:0px; 
}
#elCanvas{
 border-radius:120px;
 border:3px solid black;
 box-shadow:8px 8px 5px rgba(0,0,0,.5);
 position:absolute; 
}
</style>
<script>
var contexto;
function inicio(){
 contexto = document.getElementById("elCanvas").getContext("2d");
 laFoto.addEventListener("mousemove",dibujar);
 elCanvas.style.display = "none";
 laFoto.addEventListener("mouseover",mostrar);
 laFoto.addEventListener("mouseout",ocultar); 
}
function dibujar(evento){
 var posX = evento.clientX;
 var posY = evento.clientY;
 contexto.drawImage(laFoto, posX - 60 , posY - 60, 120, 120, 0, 0, 240, 240);
 elCanvas.style.left = (posX + 10) + "px";
 elCanvas.style.top = (posY + 10) + "px";
}
function mostrar(){
 elCanvas.style.display = "inline";
}
function ocultar(){
 elCanvas.style.display = "none";
}
</script>
</head>
<body onLoad="inicio()">
<img id="laFoto" src="foto.jpg" width="500" height="500">
<canvas id="elCanvas" width="240" height="240">
Tu navegador no entiende HTML 5
</canvas>
</body>
</html>

Be the first to comment

Leave a Reply

Your email address will not be published.


*