Aerógrafo
Todo el mundo sabe que es un aerógrafo: un dispositivo que pulveriza un fino rocío de pintura. Podemos simular un "aerógrafo" en el canvas de HTML5 utilizando el método getImageData()
, un ejemplo práctico de como manipular una imagen.
Qué necesitamos
Primero necesitamos poder detectar la posición del ratón que es "la boquilla del aerografo" con el cual dibujamos.
function oMousePos(canvas, evt) {
var ClientRect = canvas.getBoundingClientRect();
return { //objeto
x: Math.round(evt.clientX - ClientRect.left),
y: Math.round(evt.clientY - ClientRect.top)
}
También tenemos que establecer algunas variables: la densidad de puntos del aerógrafo, y el radio pulverizado.
var densidad_aerografo = 50; var radio_aerografo = 10;
Asimismo establecemos la variable
var dibujar = false
Se trata de un booleano que nos permite dibujar ( si true
), o no ( si false
).
También necesitamos utilizar algunos eventos del ratón:
- 1. Al presionar el botón del ratón empezamos a dibujar (
dibujar = true;
). El evento del ratón involucrado en este caso esmousedown
( literalmente : ratón abajo ). - 2. Al mover el ratón dibujamos. El evento del ratón involucrado en este caso es
mousemove
( literalmente : ratón moviéndose ). - 3. Al soltar el botón del ratón dejamos de dibujar (
dibujar = false;
). El evento del ratón involucrado en este caso esmouseup
. ( literalmente : ratón arriba ). - 4. Si queremos podemos también tomar en consideración la salida del ratón del canvas:
mouseout
( literalmente : ratón fuera ).
canvas.addEventListener('mousedown', function(evt) {
dibujar = true;
}, false);
canvas.addEventListener('mouseup', function(evt) {
dibujar = false;
}, false);
canvas.addEventListener("mouseout", function(evt) {
dibujar = false;
}, false);
canvas.addEventListener("mousemove", function(evt) {
if (dibujar) {
var m = oMousePos(canvas, evt);
// toda la funcionalidad del aerógrafo va aquí
Aerografo(m);
}
}, false);
Empezamos
Primero iniciamos el canvas, en este caso un canvas de 300 por 300 pixeles:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width = 300,
cx = cw / 2;
var ch = canvas.height = 300,
cy = ch / 2;
var dibujar = false;
var densidad_aerografo = 50;
var radio_aerografo = 10;
Al iniciar el canvas todavía no podemos dibujar.
var dibujar = false;
A continuación dibujamos un rectángulo blanco del tamaño del canvas: la imagen a manipular.
ctx.beginPath();
ctx.fillStyle = "white";
ctx.fillRect(0, 0, cw, ch);
Los píxeles de una imagen "en crudo" tienen una "anchura" de 4 bytes, uno por cada componente R G B A. ( Red ( rojo ), Green ( verde ), Blue ( azul ) y Alpha ( transparente ) ). Accediendo uno por uno los pixeles de una imagen podemos modificar estos componentes de color, y por tanto manipular el aspecto de las imágenes en el canvas.
Lea más acerca de cómo manipular una imágen en canvas
Pero primero tenemos que recuperar los datos de los píxeles del rectángulo especificado, y lo hacemos utilizando el método getImageData()
:
var imgData = ctx.getImageData(0, 0, cw, ch); var pixels = imgData.data;
La función Aerografo()
Al mover el ratón, si dibujar == true
, llamamos a la función Aerografo()
. Practicamente toda la funcionalidad va aquí.
El ratón representa la boquilla del aerógrafo, y la variable densidad_aerografo
representa el número de finas partículas de "pintura" que salen por la boquilla en cada momento.
Para cada una de estas partículas:
for (var p = 0; p < densidad_aerografo; p++) {. . .
la función Aerografo()
escoge al azar:
un ángulo y una distancia desde la boquilla:
var a = Math.random() * Math.PI * 2;// el ángulo var r = Math.random() * radio_aerografo;// la distáncia
calcula las coordenadas de la particula como un punto en la circunferencia de un circulo de radio r
, cuyo centro coincide con la posición del ratón ( m
).
var x = ~~(m.x + r * Math.cos(a)); var y = ~~(m.y + r * Math.sin(a));
y encuentra el índex del pixel cuyas coordenadas son x e y en el objeto imgData
. No hay que olvidar que la "anchura" de cada pixel es de 4 bytes, uno por cada componente R G B A.
var i = (x + y * imgData.width) * 4;
A continuación la función Aerografo()
modifica los componentes R G B de este pixel; en este caso cambia el color de blanco a verde : rgb(106,177,80);
pixels[i + 0] = 106; //rojo pixels[i + 1] = 177; //verde pixels[i + 2] = 80; //azul
Al final pone los datos modificados de nuevo en el canvas
ctx.putImageData(imgData, 0, 0);
function Aerografo(m) {
for (var p = 0; p < densidad_aerografo; p++) {
var a = Math.random() * Math.PI * 2;//el ángulo
var r = Math.random() * radio_aerografo;// el radio
var x = ~~(m.x + r * Math.cos(a));
var y = ~~(m.y + r * Math.sin(a));
var i = (x + y * imgData.width) * 4; //el index
pixels[i + 0] = 106; //rojo
pixels[i + 1] = 177; //verde
pixels[i + 2] = 80; //azul
}
ctx.putImageData(imgData, 0, 0);
}
Finalmente para limpiar el canvas, una función anónima vuelve a dibujar el rectángulo blanco y recupera de nuevo los datos de imgData
.
limpiar.addEventListener('click', function() {
ctx.fillRect(0,0,cw,ch);
imgData = ctx.getImageData(0, 0, cw, ch);
pixels = imgData.data;
}, false);
Lo ponemos todo junto
Es recomendable abrirlo y manosearlo en codepen.io
See the Pen Manipular imágenes #6 aerografo by Gabi (@enxaneta) on CodePen.