Приложение для рисования на веб-странице — это отличная возможность для практики работы с HTML, CSS и JavaScript, а также для создания интерактивных инструментов. В этой статье мы создадим простое приложение для рисования, которое будет включать инструменты для рисования различных фигур, выбор цветов и сохранение созданного изображения. Приложение будет иметь удобный интерфейс с несколькими инструментами, настройками размера кисти и цветов.
Для полного исходного кода и, возможно, дополнительных улучшений, загляни на наш GitHub.
Перед тем как начать писать код, убедимся, что у нас есть необходимые компоненты:
HTML — для структуры страницы.
CSS — для стилизации интерфейса.
JavaScript — для функционала рисования, обработки событий и сохранения изображений.
Нам также понадобятся иконки для кнопок, которые будут использоваться для выбора инструментов рисования. Эти иконки будут загружены в нашем проекте через файлы в папке icons
.
Начнем с создания HTML-страницы. Это будет основная структура нашего приложения.
HTML создает структуру страницы и задает разметку для всех элементов, которые будут отображаться в приложении. Вот более подробное описание каждого элемента в коде 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>
<section class="tools-board">
:
Это панель инструментов, которая содержит несколько опций для пользователя. Здесь можно выбрать форму (прямоугольник, круг, треугольник), цвет кисти, размер кисти, и другие настройки.
<ul class="options">
:
Внутри панели инструментов создаются списки (<ul>
), каждый из которых представляет группу опций. Это список кнопок для выбора формы (прямоугольник, круг и т.д.), изменения цвета, размера кисти и других настроек.
<canvas>
:
Это основной холст, на котором будет происходить рисование. Он не содержит контента по умолчанию и используется JavaScript для рисования.
Кнопки и ползунки:
Кнопки "Очистить" и "Сохранить как фото" дают возможность очистить холст и сохранить изображение соответственно. Ползунок (<input type="range">
) позволяет изменять размер кисти.
Цветовые кнопки:
В разделе цветов есть несколько кнопок для выбора цвета кисти. Каждая кнопка представляет цвет, а последний элемент — это элемент для выбора цвета с помощью стандартного цветового picker.
Теперь, когда структура HTML готова, можно перейти к стилизации с помощью CSS. Вот пример стилей для нашего приложения:
@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%;
}
Этот CSS оформляет элементы, такие как кнопки инструментов, цвета и размеры, создавая современный и удобный интерфейс.
Теперь перейдем к самой интересной части — функционалу рисования. Мы будем использовать JavaScript, чтобы обрабатывать события, связанные с рисованием на холсте. Код JavaScript подключается через файл script.js
, который мы рассмотрим ниже:
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";
canvas
: Ссылается на элемент <canvas>
на странице, на котором будет происходить рисование.
toolBtns
: Список всех кнопок инструментов (щетка, ластик и формы), с которыми пользователь может взаимодействовать.
fillColor
: Переменная для отслеживания состояния чекбокса "Цвет заливки".
sizeSlider
: Ссылка на ползунок для выбора размера кисти.
colorBtns
: Переменная для всех кнопок выбора цвета, которые пользователь может кликать для выбора цвета.
colorPicker
: Ссылка на стандартный HTML-пикер цвета.
clearCanvas
и saveImg
: Кнопки для очистки холста и сохранения изображения.
ctx
: Контекст рисования канваса, с помощью которого рисуются линии, фигуры и выполняются другие операции.
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();
});
При загрузке страницы устанавливается размер холста, соответствующий его текущим размерам на экране (через offsetWidth
и offsetHeight
). Затем вызывается функция для установки фона.
Обработчики выбора инструмента (щетка, ластик и фигуры):
toolBtns.forEach(btn => {
btn.addEventListener("click", () => {
document.querySelector(".options .active").classList.remove("active");
btn.classList.add("active");
selectedTool = btn.id;
});
});
Каждая кнопка инструмента (toolBtns
) добавляет обработчик события на клик, который делает кнопку активной, добавляя класс active
, и меняет выбранный инструмент, обновляя переменную selectedTool
.
Изменение размера кисти:
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");
});
});
Каждая кнопка выбора цвета обновляет текущий цвет кисти (selectedColor
) и делает выбранную кнопку активной, добавляя класс selected
.
Использование цветового пикера:
colorPicker.addEventListener("change", () => {
colorPicker.parentElement.style.background = colorPicker.value;
colorPicker.parentElement.click();
});
Когда пользователь выбирает цвет через стандартный HTML-пикер, цвет обновляется и на кнопке.
Очистка холста:
clearCanvas.addEventListener("click", () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
setCanvasBackground();
});
При нажатии на кнопку "Очистить" весь холст очищается, и фон восстанавливается.
Сохранение изображения:
saveImg.addEventListener("click", () => {
const link = document.createElement("a");
link.download = `${Date.now()}.jpg`;
link.href = canvas.toDataURL();
link.click();
});
При нажатии на кнопку "Сохранить как фото" создается временная ссылка для скачивания изображения, преобразуя содержимое холста в формат data URL
.
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
: Когда пользователь нажимает на холст, начинается рисование. Сохраняются начальные координаты, и создается снимок текущего состояния холста (для отмены).
drawing
: Когда пользователь двигает мышью, выполняется рисование в зависимости от выбранного инструмента.
В общем, HTML создает интерфейс и структуру, а JavaScript управляет всем функционалом рисования, изменением инструментов и сохранением рисунка.
Отлично. А вот так выглядит весь java script код:
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();
});
// Функции для рисования форм
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();
}
// Обработчики для инструментов
toolBtns.forEach(btn => {
btn.addEventListener("click", () => {
document.querySelector(".options .active").classList.remove("active");
btn.classList.add("active");
selectedTool = btn.id;
});
});
// Обработчики для кисти
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();
});
// Очистка холста
clearCanvas.addEventListener("click", () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
setCanvasBackground();
});
// Сохранение изображения
saveImg.addEventListener("click", () => {
const link = document.createElement("a");
link.download = `${Date.now()}.jpg`;
link.href = canvas.toDataURL();
link.click();
});
// Рисование
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);
Этот код реализует:
Рисование различных фигур (прямоугольник, круг, треугольник).
Выбор инструментов, включая кисть, ластик и опции заливки.
Изменение цвета и размера кисти.
Очистка холста и сохранение изображения.
Мы создали простое приложение для рисования на HTML, CSS и JavaScript, которое позволяет рисовать различные фигуры, изменять цвет и размер кисти, а также сохранять изображение. Это приложение может быть расширено добавлением дополнительных инструментов, улучшением интерфейса и интеграцией с сервером для сохранения и обмена рисунками.
Не нашли нужной статьи?
Напишите нам и ее сделаем!