Introducción
Una aplicación de dibujo en una página web es una gran oportunidad para practicar con HTML, CSS y JavaScript, así como para crear herramientas interactivas. En este artículo, crearemos una aplicación de dibujo simple que incluirá herramientas para dibujar varias formas, elegir colores y guardar la imagen creada. La aplicación tendrá una interfaz fácil de usar con varias herramientas, ajustes de tamaño del pincel y colores.
Para obtener el código fuente completo y posiblemente mejoras adicionales, echa un vistazo a nuestro GitHub.

Preparación
Antes de empezar a escribir el código, asegurémonos de que tenemos los componentes necesarios:
HTML — para la estructura de la página.
CSS — para estilizar la interfaz.
JavaScript — para la funcionalidad de dibujo, gestión de eventos y almacenamiento de imágenes.
También necesitaremos iconos para los botones que se utilizarán para seleccionar las herramientas de dibujo. Estos iconos se cargarán en nuestro proyecto a través de los archivos de la carpeta icons.
Creación de HTML y conexión de fotos y archivos
Comencemos por crear una página HTML. Esta será la estructura básica de nuestra aplicación.
HTML crea la estructura de la página y define el marcado para todos los elementos que se mostrarán en la aplicación. Aquí hay una descripción más detallada de cada elemento en el código HTML:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Приложение для рисования</title>
<link rel="stylesheet" href="style.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="script.js" defer></script>
</head>
<body>
<div class="container">
<!-- Панель инструментов -->
<section class="tools-board">
<div class="row">
<label class="title">Формы</label>
<ul class="options">
<!-- Инструмент для рисования прямоугольника -->
<li class="option tool" id="rectangle">
<img src="icons/rectangle.svg" alt="Rectangle">
<span>Прямоугольник</span>
</li>
<!-- Инструмент для рисования круга -->
<li class="option tool" id="circle">
<img src="icons/circle.svg" alt="Circle">
<span>Круг</span>
</li>
<!-- Инструмент для рисования треугольника -->
<li class="option tool" id="triangle">
<img src="icons/triangle.svg" alt="Triangle">
<span>Треугольник</span>
</li>
<li class="option">
<input type="checkbox" id="fill-color">
<label for="fill-color">Цвет заливки</label>
</li>
</ul>
</div>
<div class="row">
<label class="title">Опции</label>
<ul class="options">
<!-- Инструмент кисть -->
<li class="option active tool" id="brush">
<img src="icons/brush.svg" alt="Brush">
<span>Щетка</span>
</li>
<!-- Инструмент ластик -->
<li class="option tool" id="eraser">
<img src="icons/eraser.svg" alt="Eraser">
<span>Ластик</span>
</li>
<!-- Ползунок для изменения размера кисти -->
<li class="option">
<input type="range" id="size-slider" min="1" max="30" value="5">
</li>
</ul>
</div>
<div class="row colors">
<label class="title">Цвета</label>
<ul class="options">
<!-- Кнопки выбора цвета -->
<li class="option"></li>
<li class="option selected"></li>
<li class="option"></li>
<li class="option"></li>
<li class="option">
<input type="color" id="color-picker" value="#4A98F7">
</li>
</ul>
</div>
<div class="row buttons">
<!-- Кнопки очистки и сохранения -->
<button class="clear-canvas">Очистить</button>
<button class="save-img">Сохранить как фото</button>
</div>
</section>
<!-- Холст для рисования -->
<section class="drawing-board">
<canvas></canvas>
</section>
</div>
</body>
</html>Explicación de HTML:
<section class="tools-board">:Esta es una barra de herramientas que contiene varias opciones para el usuario. Aquí puedes elegir la forma (rectángulo, círculo, triángulo), el color del pincel, el tamaño del pincel y otras configuraciones.
<ul class="options">:Dentro de la barra de herramientas se crean listas (
<ul>), cada una de las cuales representa un grupo de opciones. Esta es una lista de botones para seleccionar una forma (rectángulo, círculo, etc.), cambiar el color, el tamaño del pincel y otras configuraciones.
<canvas>:Este es el lienzo principal en el que se realizará el dibujo. No contiene contenido predeterminado y utiliza JavaScript para dibujar.
Botones y controles deslizantes:
Los botones «Borrar» y «Guardar como foto» permiten borrar el lienzo y guardar la imagen, respectivamente. El control deslizante (
<input type="range">) permite cambiar el tamaño del pincel.
Botones de color:
En la sección de colores hay varios botones para seleccionar el color del pincel. Cada botón representa un color, y el último elemento es un elemento para seleccionar un color usando un selector de color estándar.
Estilización
Ahora que la estructura HTML está lista, puedes pasar a la estilización con CSS. Aquí hay un ejemplo de estilos para nuestra aplicación:
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
}
body {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
background: #040925;
}
.container {
display: flex;
width: 100%;
gap: 10px;
padding: 10px;
max-width: 1050px;
}
section {
background: #fff;
border-radius: 7px;
}
.tools-board {
width: 210px;
padding: 15px 22px 0;
}
.tools-board .row {
margin-bottom: 20px;
}
.row .options {
list-style: none;
margin: 10px 0 0 5px;
}
.row .options .option {
display: flex;
cursor: pointer;
align-items: center;
margin-bottom: 10px;
}
.option:is(:hover, .active) img {
filter: invert(17%) sepia(90%) saturate(3000%) hue-rotate(900deg) brightness(100%) contrast(100%);
}
.option :where(span, label) {
color: #5A6168;
cursor: pointer;
padding-left: 10px;
}
.option:is(:hover, .active) :where(span, label) {
color: #4A98F7;
}
.option #fill-color {
cursor: pointer;
height: 14px;
width: 14px;
}
#fill-color:checked ~ label {
color: #4A98F7;
}
.option #size-slider {
width: 100%;
height: 5px;
margin-top: 10px;
}
.colors .options {
display: flex;
justify-content: space-between;
}
.colors .option {
height: 20px;
width: 20px;
border-radius: 50%;
margin-top: 3px;
position: relative;
}
.colors .option:nth-child(1) {
background-color: #fff;
border: 1px solid #bfbfbf;
}
.colors .option:nth-child(2) {
background-color: #000;
}
.colors .option:nth-child(3) {
background-color: #E02020;
}
.colors .option:nth-child(4) {
background-color: #6DD400;
}
.colors .option:nth-child(5) {
background-color: #4A98F7;
}
.colors .option.selected::before {
position: absolute;
content: "";
top: 50%;
left: 50%;
height: 12px;
width: 12px;
background: inherit;
border-radius: inherit;
border: 2px solid #fff;
transform: translate(-50%, -50%);
}
.colors .option:first-child.selected::before {
border-color: #ccc;
}
.option #color-picker {
opacity: 0;
cursor: pointer;
}
.buttons button {
width: 100%;
color: #fff;
border: none;
outline: none;
padding: 11px 0;
font-size: 0.9rem;
margin-bottom: 13px;
background: none;
border-radius: 4px;
cursor: pointer;
}
.buttons .clear-canvas {
color: #6C757D;
border: 1px solid #6C757D;
transition: all 0.3s ease;
}
.clear-canvas:hover {
color: #fff;
background: #6C757D;
}
.buttons .save-img {
background: #4A98F7;
border: 1px solid #4A98F7;
}
.drawing-board {
flex: 1;
overflow: hidden;
}
.drawing-board canvas {
width: 100%;
height: 100%;
}
Este CSS da forma a elementos como botones de herramientas, colores y tamaños, creando una interfaz moderna y fácil de usar.
Escribir lógica en JavaScript
Ahora pasemos a la parte más interesante: la funcionalidad de dibujo. Usaremos JavaScript para manejar eventos relacionados con el dibujo en el lienzo. El código JavaScript se conecta a través del archivo script.js, que veremos a continuación:
El código JavaScript controla la funcionalidad de dibujo en el lienzo, interactúa con el usuario y actualiza la pantalla en función de la configuración seleccionada. Consideremos los detalles de cada fragmento de código.
Inicialización de variables:
const canvas = document.querySelector("canvas"),
toolBtns = document.querySelectorAll(".tool"),
fillColor = document.querySelector("#fill-color"),
sizeSlider = document.querySelector("#size-slider"),
colorBtns = document.querySelectorAll(".colors .option"),
colorPicker = document.querySelector("#color-picker"),
clearCanvas = document.querySelector(".clear-canvas"),
saveImg = document.querySelector(".save-img"),
ctx = canvas.getContext("2d");
let prevMouseX, prevMouseY, snapshot,
isDrawing = false,
selectedTool = "brush",
brushWidth = 5,
selectedColor = "#000";canvas: Se refiere al elemento<canvas>en la página donde se realizará el dibujo.toolBtns: Lista de todos los botones de herramientas (pincel, borrador y formas) con los que el usuario puede interactuar.fillColor: Variable para el seguimiento del estado de la casilla de verificación "Color de relleno".sizeSlider: Enlace al control deslizante para seleccionar el tamaño del pincel.colorBtns: Variable para todos los botones de selección de color en los que el usuario puede hacer clic para seleccionar un color.colorPicker: Enlace al selector de color HTML estándar.clearCanvasysaveImg: Botones para borrar el lienzo y guardar la imagen.ctx: Contexto de dibujo del lienzo, con el que se dibujan líneas, figuras y se realizan otras operaciones.
Establecer el fondo del lienzo:
const setCanvasBackground = () => {
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = selectedColor;
}Este código establece un fondo blanco para el lienzo y luego restaura el color actual del pincel para dibujar.
Inicialización del lienzo después de cargar la página:
window.addEventListener("load", () => {
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
setCanvasBackground();
});Cuando se carga la página, el tamaño del lienzo se establece de acuerdo con su tamaño actual en la pantalla (a través de offsetWidth y offsetHeight). Luego se llama a la función para configurar el fondo.
Controladores de eventos:
Controladores de selección de herramientas (pincel, borrador y figuras):
toolBtns.forEach(btn => {
btn.addEventListener("click", () => {
document.querySelector(".options .active").classList.remove("active");
btn.classList.add("active");
selectedTool = btn.id;
});
});Cada botón de la herramienta (toolBtns) agrega un controlador de eventos de clic que activa el botón agregando la clase active y cambia la herramienta seleccionada actualizando la variable selectedTool.
Cambio del tamaño del pincel:
sizeSlider.addEventListener("change", () => brushWidth = sizeSlider.value);Cuando el usuario cambia el valor del control deslizante, se actualiza el tamaño del pincel.
Cambio de color:
colorBtns.forEach(btn => {
btn.addEventListener("click", () => {
document.querySelector(".options .selected").classList.remove("selected");
btn.classList.add("selected");
selectedColor = window.getComputedStyle(btn).getPropertyValue("background-color");
});
});Cada botón de selección de color actualiza el color actual del pincel (selectedColor) y activa el botón seleccionado añadiendo la clase selected.
Uso del selector de color:
colorPicker.addEventListener("change", () => {
colorPicker.parentElement.style.background = colorPicker.value;
colorPicker.parentElement.click();
});Cuando el usuario selecciona un color a través del selector HTML estándar, el color se actualiza en el botón.
Borrar lienzo:
clearCanvas.addEventListener("click", () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
setCanvasBackground();
});
Al hacer clic en el botón «Borrar», se borra todo el lienzo y se restaura el fondo.
Guardar imagen:
saveImg.addEventListener("click", () => {
const link = document.createElement("a");
link.download = `${Date.now()}.jpg`;
link.href = canvas.toDataURL();
link.click();
});Al hacer clic en el botón "Guardar como foto", se crea un enlace temporal para descargar la imagen, convirtiendo el contenido del lienzo al formato data URL.
Dibujo sobre lienzo:
const startDraw = (e) => {
isDrawing = true;
prevMouseX = e.offsetX;
prevMouseY = e.offsetY;
ctx.beginPath();
ctx.lineWidth = brushWidth;
ctx.strokeStyle = selectedColor;
ctx.fillStyle = selectedColor;
snapshot = ctx.getImageData(0, 0, canvas.width, canvas.height);
}
const drawing = (e) => {
if (!isDrawing) return;
ctx.putImageData(snapshot, 0, 0);
if (selectedTool === "brush" || selectedTool === "eraser") {
ctx.strokeStyle = selectedTool === "eraser" ? "#fff" : selectedColor;
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();
} else if (selectedTool === "rectangle") {
drawRect(e);
} else if (selectedTool === "circle") {
drawCircle(e);
} else {
drawTriangle(e);
}
}
canvas.addEventListener("mousedown", startDraw);
canvas.addEventListener("mousemove", drawing);
canvas.addEventListener("mouseup", () => isDrawing = false);startDraw: Cuando el usuario hace clic en el lienzo, comienza a dibujar. Se guardan las coordenadas iniciales y se crea una instantánea del estado actual del lienzo (para cancelar).drawing: Cuando el usuario mueve el ratón, el dibujo se realiza en función de la herramienta seleccionada.
En general, HTML crea la interfaz y la estructura, y JavaScript gestiona toda la funcionalidad de dibujo, cambio de herramientas y guardado del dibujo.
Perfecto. Así es como se ve todo el código de JavaScript:
const canvas = document.querySelector("canvas"),
toolBtns = document.querySelectorAll(".tool"),
fillColor = document.querySelector("#fill-color"),
sizeSlider = document.querySelector("#size-slider"),
colorBtns = document.querySelectorAll(".colors .option"),
colorPicker = document.querySelector("#color-picker"),
clearCanvas = document.querySelector(".clear-canvas"),
saveImg = document.querySelector(".save-img"),
ctx = canvas.getContext("2d");
let prevMouseX, prevMouseY, snapshot,
isDrawing = false,
selectedTool = "brush",
brushWidth = 5,
selectedColor = "#000";
const setCanvasBackground = () => {
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = selectedColor;
}
window.addEventListener("load", () => {
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
setCanvasBackground();
});
// Funciones para dibujar formas
const drawRect = (e) => {
if (!fillColor.checked) {
return ctx.strokeRect(e.offsetX, e.offsetY, prevMouseX - e.offsetX, prevMouseY - e.offsetY);
}
ctx.fillRect(e.offsetX, e.offsetY, prevMouseX - e.offsetX, prevMouseY - e.offsetY);
}
const drawCircle = (e) => {
ctx.beginPath();
let radius = Math.sqrt(Math.pow((prevMouseX - e.offsetX), 2) + Math.pow((prevMouseY - e.offsetY), 2));
ctx.arc(prevMouseX, prevMouseY, radius, 0, 2 * Math.PI);
fillColor.checked ? ctx.fill() : ctx.stroke();
}
const drawTriangle = (e) => {
ctx.beginPath();
ctx.moveTo(prevMouseX, prevMouseY);
ctx.lineTo(e.offsetX, e.offsetY);
ctx.lineTo(prevMouseX * 2 - e.offsetX, e.offsetY);
ctx.closePath();
fillColor.checked ? ctx.fill() : ctx.stroke();
}
// Manipuladores de herramientas
toolBtns.forEach(btn => {
btn.addEventListener("click", () => {
document.querySelector(".options .active").classList.remove("active");
btn.classList.add("active");
selectedTool = btn.id;
});
});
// Acondicionadores para pinceles
sizeSlider.addEventListener("change", () => brushWidth = sizeSlider.value);
colorBtns.forEach(btn => {
btn.addEventListener("click", () => {
document.querySelector(".options .selected").classList.remove("selected");
btn.classList.add("selected");
selectedColor = window.getComputedStyle(btn).getPropertyValue("background-color");
});
});
colorPicker.addEventListener("change", () => {
colorPicker.parentElement.style.background = colorPicker.value;
colorPicker.parentElement.click();
});
// Borrar lienzo
clearCanvas.addEventListener("click", () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
setCanvasBackground();
});
// Guardar imagen
saveImg.addEventListener("click", () => {
const link = document.createElement("a");
link.download = `${Date.now()}.jpg`;
link.href = canvas.toDataURL();
link.click();
});
// Dibujo
const startDraw = (e) => {
isDrawing = true;
prevMouseX = e.offsetX;
prevMouseY = e.offsetY;
ctx.beginPath();
ctx.lineWidth = brushWidth;
ctx.strokeStyle = selectedColor;
ctx.fillStyle = selectedColor;
snapshot = ctx.getImageData(0, 0, canvas.width, canvas.height);
}
const drawing = (e) => {
if (!isDrawing) return;
ctx.putImageData(snapshot, 0, 0);
if (selectedTool === "brush" || selectedTool === "eraser") {
ctx.strokeStyle = selectedTool === "eraser" ? "#fff" : selectedColor;
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();
} else if (selectedTool === "rectangle") {
drawRect(e);
} else if (selectedTool === "circle") {
drawCircle(e);
} else {
drawTriangle(e);
}
}
canvas.addEventListener("mousedown", startDraw);
canvas.addEventListener("mousemove", drawing);
canvas.addEventListener("mouseup", () => isDrawing = false);
Este código implementa:
Dibujar varias figuras (rectángulo, círculo, triángulo).
Selección de herramientas, incluyendo pincel, goma de borrar y opciones de relleno.
Cambio de color y tamaño del pincel.
Borrar el lienzo y guardar la imagen.
Conclusiones y conclusión
Hemos creado una aplicación sencilla para dibujar en HTML, CSS y JavaScript, que permite dibujar varias figuras, cambiar el color y el tamaño del pincel, así como guardar la imagen. Esta aplicación se puede ampliar añadiendo herramientas adicionales, mejorando la interfaz e integrándose con el servidor para guardar y compartir dibujos.
