{}const=>[]async()letfn</>var
WebDesarrollo

Creamos una aplicación de dibujo en HTML, CSS y JavaScript

La aplicación de dibujo en la página web es una gran oportunidad para practicar HTML, CSS y JavaScript, así como para crear herramientas interactivas

К

Kodik

Autor

11 min de lectura

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.

Demo del proyecto

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:

  1. <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.

  2. <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.

  3. <canvas>:

    • Este es el lienzo principal en el que se realizará el dibujo. No contiene contenido predeterminado y utiliza JavaScript para dibujar.

  4. 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.

  5. 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.

  • clearCanvas y saveImg: 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:

  1. 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.

  1. 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.

  1. 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.

  1. 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.

  1. 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.

  1. 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.

🎯Deja de postergar

¿Te gustó el artículo?
¡Hora de practicar!

En Kodik no solo lees — escribes código de inmediato. Teoría + práctica = habilidades reales.

Práctica instantánea
🧠IA explica código
🏆Certificado

Sin registro • Sin tarjeta