Cómo crear un selector de color con HTML5 Canvas

by Janeth Kent Date: 30-05-2023 canvas html5

HTML5 Canvas es una tecnología que permite a los desarrolladores generar gráficos y animaciones en tiempo real utilizando JavaScript. Proporciona un lienzo en blanco en el cual se pueden dibujar y manipular elementos gráficos, como líneas, formas, imágenes y texto, con gran flexibilidad y control.

Aquí hay algunos conceptos clave sobre HTML5 Canvas:

1. Elemento Canvas: El elemento <canvas> es la base del lienzo en el que se dibujan los gráficos. Se define mediante etiquetas HTML y se puede dimensionar utilizando los atributos `width` (ancho) y `height` (alto). Todos los elementos gráficos se dibujan dentro de este lienzo.

2. Contexto: El contexto (`context`) es el objeto que proporciona métodos y propiedades para dibujar en el lienzo. Hay dos tipos de contexto: 2D y WebGL. Para gráficos 2D, se utiliza el contexto 2D (`context2d`), que es más común. Para acceder al contexto 2D, se utiliza el método getContext('2d') en el elemento <canvas>.

3. Coordenadas y sistema de coordenadas: El lienzo de Canvas utiliza un sistema de coordenadas en el que `(0, 0)` representa la esquina superior izquierda del lienzo y las coordenadas positivas aumentan hacia abajo y hacia la derecha. Esto significa que los valores más altos de `x` están a la derecha y los valores más altos de `y` están hacia abajo.

4. Métodos de dibujo: El contexto 2D proporciona una amplia gama de métodos para dibujar diferentes elementos gráficos en el lienzo, como líneas, rectángulos, círculos, curvas, imágenes y texto. Algunos de los métodos más comunes incluyen fillRect(), strokeRect(), arc(), drawImage() y fillText().

5. Estilos y atributos: El contexto 2D también permite establecer estilos y atributos para los elementos gráficos. Puedes establecer colores de trazo y de relleno, grosor de línea, tipografía y otros atributos que afectan la apariencia visual de los gráficos.

6. Animaciones: Una de las ventajas de HTML5 Canvas es su capacidad para crear animaciones fluidas y dinámicas. Esto se puede lograr utilizando técnicas como la actualización periódica del lienzo, el uso de la función requestAnimationFrame() y la manipulación de los elementos gráficos en cada fotograma.

HTML5 Canvas ofrece una amplia gama de posibilidades creativas y es utilizado en muchas áreas, como juegos en línea, visualizaciones de datos, aplicaciones interactivas y gráficos generativos. Es una herramienta poderosa para el desarrollo web y brinda a los desarrolladores un control completo sobre la representación gráfica en el navegador.

En este tutorial vamos a explicar como utilizar el elemento Canvas para crear un sencillo selector de color.

Empezamos por el código HTML básico de la página:


<!DOCTYPE html>
 <html lang="en">
 <head>
 <meta charset="utf-8" />
 <title>Colorpicker demo</title>
 </head>
 <body>
 

Pasamos a definir algunos estilos CSS para los elementos en la página. Se establecen estilos para el cuerpo (body), un encabezado (h2) y se importa una fuente de Google Fonts llamada "Open Sans".


<style>
 @import url(https://fonts.googleapis.com/css?family=Open+Sans);
 body {
 margin: 0;
 padding: 0;
 background-color: #e6e6e6;
 }
 h2 {
 background-color: #dbdbdb;
 margin: 0;
 margin-bottom: 15px;
 padding: 10px;
 font-family: 'Open Sans';
 }
 /* Estilos CSS adicionales para los elementos de la página */
 

Seguímos con nuestro encabezado que indica el propósito del color picker.


<h2>Canvas Color Picker</h2>

Luego creamos los dos elementos que mostrarán el color seleccionado en formato RGBA y HEX: se utilizarán los identificadores txtRgba y txtHex para actualizar los valores más tarde desde el código JavaScript.

<label for="color-input" id="color-label" style="background-color: red"></label>
<input type="checkbox" id="color-input" checked></input>

Aquí creamos una etiqueta <label> con el identificador color-label. Esta etiqueta se utiliza como muestra visual del color seleccionado. También hay un <input> de tipo checkbox con el identificador color-input, que se utiliza para controlar la visibilidad del selector de color.

A continuación creamos un contenedor <div> con el identificador color-picker, que contiene dos elementos <canvas>. El primer <canvas> con el identificador color-block se utiliza como el lienzo principal donde se selecciona el color. El segundo <canvas> con el identificador color-strip se utiliza para mostrar una tira de colores para seleccionar el componente de saturación del color.


<div id="color-picker">
<canvas id="color-block" height="150" width="150"></canvas>
<canvas id="color-strip" height="150" width="30"></canvas>
</div>

Ahora empieza lo divertido...
Vamos a ver como funciona nuestro JavaScript:


<script type="text/javascript">
 // Aquí comienza el bloque de código JavaScript
 
 var colorBlock = document.getElementById('color-block');
var ctx1 = colorBlock.getContext('2d');
var width1 = colorBlock.width;
var height1 = colorBlock.height;

 

Estas líneas de código obtienen el elemento del lienzo principal con el identificador "color-block" del documento HTML. Luego, se obtiene el contexto 2d del lienzo utilizando getContext('2d'). También se almacenan las dimensiones (ancho y alto) del lienzo en las variables width1 y height1. Seguimos:


var colorStrip = document.getElementById('color-strip');
var ctx2 = colorStrip.getContext('2d');
var width2 = colorStrip.width;
var height2 = colorStrip.height;
   

Como podéis ver, el código es parecido al anterior, pero en este caso obtienen el elemento del lienzo de la tira de colores con el identificador "color-strip". Se obtiene el contexto 2d del lienzo y se almacenan las dimensiones en las variables width2 y height2.

Ahora tenemos que obtener los elementos del documento HTML con los identificadores "color-label", "txtRgba" y "txtHex" y los tenemos que almacenar en variables correspondientes. Estos elementos se utilizan para mostrar y actualizar los valores de color seleccionado.


var colorLabel = document.getElementById('color-label');
var txtRgba = document.getElementById('txtRgba');
var txtHex = document.getElementById('txtHex');
 

Vamos a añadir las variables necesarias para realizar un seguimiento de la posición del ratón en el lienzo para poder controlar si se está arrastrando o no: x y y almacenan las coordenadas del ratón, drag indica si se está arrastrando el ratón y rgbaColor almacena el valor inicial del color en formato RGBA (rojo, verde, azul y transparencia).


var x = 0;
var y = 0;
var drag = false;
var rgbaColor = 'rgba(255,0,0,1)';
 

Y ahora definimos los gradientes de color en los lienzos. En el lienzo colorBlock, se dibuja un rectángulo que cubre todo el lienzo y luego se llama a la función fill


ctx1.rect(0, 0, width1, height1);
  fillGradient();
    
    ctx2.rect(0, 0, width2, height2);
    var grd1 = ctx2.createLinearGradient(0, 0, 0, height1);
    grd1.addColorStop(0, 'rgba(255, 0, 0, 1)');
    grd1.addColorStop(0.17, 'rgba(255, 255, 0, 1)');
    grd1.addColorStop(0.34, 'rgba(0, 255, 0, 1)');
    grd1.addColorStop(0.51, 'rgba(0, 255, 255, 1)');
    grd1.addColorStop(0.68, 'rgba(0, 0, 255, 1)');
    grd1.addColorStop(0.85, 'rgba(255, 0, 255, 1)');
    grd1.addColorStop(1, 'rgba(255, 0, 0, 1)');
    ctx2.fillStyle = grd1;
    ctx2.fill();
  

Añadimos la función que se ejecuta cuando se hace clic en el lienzo de la tira de colores (colorStrip) con las siguientes características: al hacer clic, se tienen que obtener las coordenadas (offsetX y offsetY) del punto donde se hizo clic. Luego, se obtiene el color de píxel correspondiente a esas coordenadas utilizando getImageData(). El resultado se almacena en imageData, que es un objeto que contiene información sobre los componentes RGBA del píxel. Se construye una cadena rgbaColor utilizando esos valores y se llama a la función fillGradient() para actualizar el color en el lienzo principal.


function click(e) {
 x = e.offsetX;
 y = e.offsetY;
 var imageData = ctx2.getImageData(x, y, 1, 1).data;
 rgbaColor = 'rgba(' + imageData[0] + ',' + imageData[1] + ',' + imageData[2] + ',1)';
 fillGradient();
 }

Creamos la función fillGradient() se encarga de dibujar los gradientes en el lienzo principal (colorBlock) para representar el color seleccionado. Primero, se establece el color de relleno en ctx1 con el valor de rgbaColor y se dibuja un rectángulo que cubre todo el lienzo. Luego, se crean dos gradientes lineales, grdWhite y grdBlack, utilizando el contexto del lienzo de la tira de colores (ctx2). Estos gradientes se utilizan para crear un efecto de degradado en el lienzo principal, proporcionando áreas de blanco y negro para ajustar el brillo y contraste del color seleccionado.


function fillGradient() {
   ctx1.fillStyle = rgbaColor;
   ctx1.fillRect(0, 0, width1, height1);

   var grdWhite = ctx2.createLinearGradient(0, 0, width1, 0);
   grdWhite.addColorStop(0, 'rgba(255,255,255,1)');
   grdWhite.addColorStop(1, 'rgba(255,255,255,0)');
   ctx1.fillStyle = grdWhite;
   ctx1.fillRect(0, 0, width1, height1);
   
   var grdBlack = ctx2.createLinearGradient(0, 0, 0, height1);
   grdBlack.addColorStop(0, 'rgba(0,0,0,0)');
   grdBlack.addColorStop(1, 'rgba(0,0,0,1)');
   ctx1.fillStyle = grdBlack;
   ctx1.fillRect(0, 0, width1, height1);
   }
 

Las funciones siguientes se utilizan para controlar la interacción del usuario con el lienzo principal (colorBlock). Cuando el usuario presiona el botón del mouse dentro del lienzo (mousedown), se establece drag en true para indicar que se está arrastrando. La función changeColor() se llama para actualizar el color seleccionado.

Durante el movimiento del mouse (mousemove), si drag es true, se llama a changeColor() para actualizar el color seleccionado mientras se arrastra el mouse.

Cuando se suelta el botón del mouse dentro del lienzo (mouseup), se establece drag en false para indicar que el arrastre ha terminado.


function mousedown(e) {
 drag = true;
 changeColor(e);
 }
 
 function mousemove(e) {
   if (drag) {
   changeColor(e);
   }
   }
   
   function mouseup(e) {
   drag = false;
   }
 

Vamos adelante con el código para la función changeColor() se utiliza para actualizar el color seleccionado cuando el usuario interactúa con el lienzo principal. Primero, se obtienen las coordenadas del punto donde se produjo la interacción (offsetX y offsetY). Luego, se obtiene el color de píxel correspondiente utilizando getImageData() y se actualiza la variable rgbaColor.

Después de eso, se actualiza el color de fondo del elemento colorLabel con el color seleccionado, se muestra el valor del color en formato RGBA en el elemento txtRgba y se convierte el color de RGBA a formato hexadecimal utilizando la función rgbaToHex(). El resultado se muestra en el elemento txtHex y también se imprime en la consola.


function changeColor(e) {
 x = e.offsetX;
 y = e.offsetY;
 var imageData = ctx1.getImageData(x, y, 1, 1).data;
 rgbaColor = 'rgba(' + imageData[0] + ',' + imageData[1] + ',' + imageData[2] + ',1)';
 colorLabel.style.backgroundColor = rgbaColor;
 txtRgba.innerHTML = rgbaColor;

 var hexColor = rgbaToHex(rgbaColor);
   console.log(hexColor);
   txtHex.innerHTML = hexColor;
   }
 

Estas líneas de código siguientes asignan los controladores de eventos a los elementos de lienzo y al elemento de la tira de colores. Cuando se hace clic en la tira de colores, se ejecuta la función click(). Cuando el mouse se presiona, se suelta o se mueve dentro del lienzo principal, se ejecutan las funciones correspondientes (mousedown(), mouseup(), mousemove()) para controlar la interacción y actualizar el color seleccionado.

colorStrip.addEventListener("click", click, false);
colorBlock.addEventListener("mousedown", mousedown, false);
colorBlock.addEventListener("mouseup", mouseup, false);
colorBlock.addEventListener("mousemove", mousemove, false);

La función rgbaToHex() convierte un color en formato RGBA a formato hexadecimal. Primero, se extraen los valores de los componentes R, G, B y A del color RGBA utilizando expresiones regulares. Luego, se convierten los valores R, G y B a formato hexadecimal utilizando toString(16) y padStart(2, '0') para asegurarse de que tengan dos dígitos. Finalmente, los valores hexadecimales se combinan y se devuelve el color en formato hexadecimal.


function rgbaToHex(rgbaColor) {
 var values = rgbaColor.match(/d+/g);
 var r = parseInt(values[0]);
 var g = parseInt(values[1]);
 var b = parseInt(values[2]);
 var a = parseFloat(values[3]);

 var hexR = r.toString(16).padStart(2, '0');
 var hexG = g.toString(16).padStart(2, '0');
 var hexB = b.toString(16).padStart(2, '0');
 var hexColor = '#' + hexR + hexG + hexB;
 return hexColor;
 }
 

Aquí tenéis todo el código:


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Colorpicker demo</title>
</head>
<body>
<style>
   @import url(https://fonts.googleapis.com/css?family=Open+Sans);
   body {
   margin: 0;
   padding: 0;
   background-color: #e6e6e6;
   }
   h2 {
   background-color: #dbdbdb;
   margin: 0;
   margin-bottom: 15px;
   padding: 10px;
   font-family: 'Open Sans';
   }
   #color-input {
   display: none;
   }
   #color-label {
   margin-left: 15px;
   position: absolute;
   height: 30px;
   width: 50px;
   } 
   #color-input:checked ~ #color-picker {
   opacity: 1;
   }
   #color-picker {
   position: absolute;
   left: 70px; 
   background-color: white;
   height: 150px;
   width: 185px;
   border: solid 1px #ccc;
   opacity: 0;
   padding: 5px;
   }
   canvas:hover {
   cursor: crosshair;
   }
   </style>
<h2>Canvas Color Picker</h2>
<div><p>Color in RGBA is: <span id="txtRgba"></span> </p>
<div><p>Color in HEX is: <span id="txtHex"></span> </p>
</div>
<label for="color-input" id="color-label" style="background-color: red"></label>
<input type="checkbox" id="color-input" checked></input>
<div id="color-picker">
<canvas id="color-block" height="150" width="150"></canvas>
<canvas id="color-strip" height="150" width="30"></canvas>
</div>
<script type="text/javascript">
   var colorBlock = document.getElementById('color-block');
   var ctx1 = colorBlock.getContext('2d');
   var width1 = colorBlock.width;
   var height1 = colorBlock.height;
var colorStrip = document.getElementById('color-strip');
   var ctx2 = colorStrip.getContext('2d');
   var width2 = colorStrip.width;
   var height2 = colorStrip.height;
var colorLabel = document.getElementById('color-label');
   var txtRgba = document.getElementById('txtRgba');
   var txtHex = document.getElementById('txtHex');
 
var x = 0;
   var y = 0;
   var drag = false;
   var rgbaColor = 'rgba(255,0,0,1)';
ctx1.rect(0, 0, width1, height1);
   fillGradient();
ctx2.rect(0, 0, width2, height2);
   var grd1 = ctx2.createLinearGradient(0, 0, 0, height1);
   grd1.addColorStop(0, 'rgba(255, 0, 0, 1)');
   grd1.addColorStop(0.17, 'rgba(255, 255, 0, 1)');
   grd1.addColorStop(0.34, 'rgba(0, 255, 0, 1)');
   grd1.addColorStop(0.51, 'rgba(0, 255, 255, 1)');
   grd1.addColorStop(0.68, 'rgba(0, 0, 255, 1)');
   grd1.addColorStop(0.85, 'rgba(255, 0, 255, 1)');
   grd1.addColorStop(1, 'rgba(255, 0, 0, 1)');
   ctx2.fillStyle = grd1;
   ctx2.fill();
function click(e) {
   x = e.offsetX;
   y = e.offsetY;
   var imageData = ctx2.getImageData(x, y, 1, 1).data;
   rgbaColor = 'rgba(' + imageData[0] + ',' + imageData[1] + ',' + imageData[2] + ',1)';
   fillGradient();
   
   }
function fillGradient() {
   ctx1.fillStyle = rgbaColor;
   ctx1.fillRect(0, 0, width1, height1);
 var grdWhite = ctx2.createLinearGradient(0, 0, width1, 0);
   grdWhite.addColorStop(0, 'rgba(255,255,255,1)');
   grdWhite.addColorStop(1, 'rgba(255,255,255,0)');
   ctx1.fillStyle = grdWhite;
   ctx1.fillRect(0, 0, width1, height1);
 var grdBlack = ctx2.createLinearGradient(0, 0, 0, height1);
   grdBlack.addColorStop(0, 'rgba(0,0,0,0)');
   grdBlack.addColorStop(1, 'rgba(0,0,0,1)');
   ctx1.fillStyle = grdBlack;
   ctx1.fillRect(0, 0, width1, height1);
   }
function mousedown(e) {
   drag = true;
   changeColor(e);
   }
function mousemove(e) {
   if (drag) {
   changeColor(e);
   }
   }
function mouseup(e) {
   drag = false;
   }
function changeColor(e) {
   x = e.offsetX;
   y = e.offsetY;
   var imageData = ctx1.getImageData(x, y, 1, 1).data;
   rgbaColor = 'rgba(' + imageData[0] + ',' + imageData[1] + ',' + imageData[2] + ',1)';
   colorLabel.style.backgroundColor = rgbaColor;
   txtRgba.innerHTML = rgbaColor;
 
 var hexColor = rgbaToHex(rgbaColor);
   console.log(hexColor); // Imprime el color en formato HEX en la consola
   txtHex.innerHTML = hexColor;
   }
colorStrip.addEventListener("click", click, false);
colorBlock.addEventListener("mousedown", mousedown, false);
   colorBlock.addEventListener("mouseup", mouseup, false);
   colorBlock.addEventListener("mousemove", mousemove, false);
function rgbaToHex(rgbaColor) {
   // Obtener los valores de R, G, B y A del color RGBA
   var values = rgbaColor.match(/d+/g);
   var r = parseInt(values[0]);
   var g = parseInt(values[1]);
   var b = parseInt(values[2]);
   var a = parseFloat(values[3]);
 // Convertir los valores R, G y B a formato hexadecimal
   var hexR = r.toString(16).padStart(2, '0');
   var hexG = g.toString(16).padStart(2, '0');
   var hexB = b.toString(16).padStart(2, '0');
 // Combinar los valores hexadecimales y retornar el color en formato HEX
   var hexColor = '#' + hexR + hexG + hexB;
   return hexColor;
   }
 
</script>
</body>
</html>

Espero que este tutorial haya demostrado el gran potencial que existe al crear aplicaciones utilizando Canvas. Existen aplicaciones mucho más avanzadas, e incluso se están desarrollando juegos utilizando esta tecnología. Por lo tanto, es un campo que vale la pena explorar, ya que ofrece la posibilidad de crear cosas increíbles y sorprendentes.

 
by Janeth Kent Date: 30-05-2023 canvas html5 visitas : 13480  
 
Janeth Kent

Janeth Kent

Licenciada en Bellas Artes y programadora por pasión. Cuando tengo un rato retoco fotos, edito vídeos y diseño cosas. El resto del tiempo escribo en MA-NO WEB DESIGN AND DEVELOPMENT.

 
 
 

Artículos relacionados

10 increíbles experimentos con HTML5

Los laboratorios de innovación se llenan de creación e ideas impresionantes. Este es el caso de Chrome Experiments, creado para que los desarrolladores  den rienda suelta a la  imaginación y expongan…

Clicky