W3docs

JavaScript Canvas API

Узнайте, как рисовать графику с помощью элемента canvas и JavaScript: контекст 2D, фигуры, линии, трансформации и анимация с requestAnimationFrame.

Введение в HTML Canvas с JavaScript

Элемент HTML <canvas> — это поверхность для рисования, которой вы управляете с помощью JavaScript. В отличие от изображений или SVG, canvas работает в режиме немедленного рисования: здесь нет объектов фигур, за которыми нужно следить. Вы отдаёте команды рисования, и пиксели закрашиваются немедленно. После закрашивания фигура превращается в просто окрашенные пиксели — canvas не помнит о ней, и именно поэтому перерисовка является ключевой идеей любой анимации.

В этой главе рассматриваются: получение 2D-контекста, рисование фигур и линий, преобразование системы координат и анимация с помощью requestAnimationFrame.

На этой странице описывается контекст рендеринга 2D (getContext('2d')). Canvas также предоставляет контекст webgl для аппаратно-ускоренной 3D-графики, который является отдельным API.

Понимание элемента 'canvas'

Элемент <canvas> создаёт поверхность для рисования фиксированного размера, которая отображает графику «на лету». Он хорошо подходит для задач с интенсивной графикой — игры, диаграммы, обработка изображений, эффекты частиц — там, где нужен контроль на уровне пикселей и высокая частота кадров. Сам по себе тег ничего не рисует; это пустой контейнер, и всё рисование выполняет JavaScript.

Важный момент, который стоит усвоить сразу: атрибуты width и height задают размер буфера рисования, тогда как CSS-свойства width/height задают отображаемый размер. При несовпадении canvas растягивается, и рисунки выглядят размыто или искажённо. Устанавливайте размер через атрибуты (или в JS через canvas.width/canvas.height), а не через CSS, если только вы намеренно не хотите масштабировать изображение.

Базовая настройка Canvas

Чтобы начать рисовать, разместите тег <canvas> в HTML, затем получите его 2D-контекст рисования в JavaScript с помощью getContext('2d'). Объект контекста содержит все методы рисования.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Canvas Example</title>
<style>
  canvas {
    border: 1px solid #000;
  }
</style>
</head>
<body>
<canvas id="myCanvas" width="200" height="200"></canvas>
<script>
  const canvas = document.getElementById('myCanvas');
  const ctx = canvas.getContext('2d');
</script>
</body>
</html>

Здесь мы определяем canvas размером 200×200, добавляем ему рамку, чтобы видеть его границы, и получаем контекст с помощью getContext('2d'). Рамка чисто визуальная; сама поверхность canvas изначально полностью прозрачна.

Обратите внимание на систему координат: начало (0, 0) находится в верхнем левом углу. Ось x направлена вправо, а ось y — вниз, то есть (0, 0) — это верхний край, а большие значения y смещаются к нижнему. Это сбивает с толку новичков, привыкших к математическим осям.

Рисование фигур

Самый быстрый способ что-то нарисовать — это fillRect(x, y, width, height), который рисует закрашенный прямоугольник за один вызов. Сначала установите fillStyle, чтобы выбрать цвет (подходит любая строка цвета CSS). Также существует strokeRect для прямоугольника только с контуром и clearRect для очистки области до прозрачной.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Rectangle Example</title>
<style>
  canvas {
    border: 1px solid black;
  }
</style>
</head>
<body>
<canvas id="rectangleCanvas" width="200" height="200"></canvas>
<script>
  const canvas = document.getElementById('rectangleCanvas');
  const ctx = canvas.getContext('2d');
  ctx.fillStyle = '#FF0000'; // Set the fill color to red
  ctx.fillRect(20, 20, 150, 100); // Draw the rectangle
</script>
</body>
</html>

Создание линий и путей

Линии, кривые и произвольные фигуры строятся из путей. Порядок действий всегда одинаков:

  1. beginPath() — начать новый путь (если пропустить, новая линия продолжит предыдущую).
  2. moveTo(x, y) — поднять «перо» и переместить его без рисования.
  3. lineTo(x, y) — нарисовать отрезок до новой точки (вызывайте несколько раз для цепочки отрезков).
  4. stroke() — нарисовать контур, или fill() — заполнить замкнутую область.

Управляйте внешним видом линии с помощью lineWidth, strokeStyle и lineCap перед вызовом stroke().

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Line Drawing Example</title>
<style>
  canvas {
    border: 1px solid black;
  }
</style>
</head>
<body>
<canvas id="lineCanvas" width="200" height="200"></canvas>
<script>
  const canvas = document.getElementById('lineCanvas');
  const ctx = canvas.getContext('2d');
  ctx.beginPath(); // Start the path
  ctx.moveTo(50, 50); // Move the pen to (50, 50)
  ctx.lineTo(150, 50); // Draw a line to (150, 50)
  ctx.lineTo(150, 150); // Continue to (150, 150)
  ctx.lineWidth = 4; // Thicker line
  ctx.strokeStyle = 'navy'; // Line color
  ctx.stroke(); // Render the path visible
</script>
</body>
</html>

Рисование окружностей и дуг

Окружности рисуются с помощью arc(x, y, radius, startAngle, endAngle), где углы задаются в радианах (полная окружность — это 2 * Math.PI). Оберните вызов в путь, затем вызовите fill() или stroke():

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Circle Example</title>
<style>
  canvas {
    border: 1px solid black;
  }
</style>
</head>
<body>
<canvas id="circleCanvas" width="200" height="200"></canvas>
<script>
  const canvas = document.getElementById('circleCanvas');
  const ctx = canvas.getContext('2d');
  ctx.beginPath();
  // Center (100, 100), radius 60, full circle
  ctx.arc(100, 100, 60, 0, 2 * Math.PI);
  ctx.fillStyle = 'orange';
  ctx.fill();
  ctx.stroke(); // Add an outline on top of the fill
</script>
</body>
</html>

Продвинутые операции с Canvas

Трансформации Canvas

translate, rotate и scale изменяют систему координат canvas, а не отдельные фигуры. Важно: они накапливаются — каждая из них строится на предыдущей, а поворот происходит вокруг текущего начала координат, а не центра фигуры. Чтобы повернуть вокруг точки, сначала выполните translate к этой точке, а затем rotate.

Поскольку трансформации накапливаются, оборачивайте их в ctx.save() / ctx.restore(), чтобы вернуться к предыдущему состоянию, не отменяя каждое преобразование вручную:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Transformation Example</title>
<style>
  canvas {
    border: 1px solid black;
  }
</style>
</head>
<body>
<canvas id="transformCanvas" width="200" height="200"></canvas>
<script>
  const canvas = document.getElementById('transformCanvas');
  const ctx = canvas.getContext('2d');
  ctx.save(); // Remember the untransformed state
  ctx.translate(50, 50); // Move the canvas origin to (50, 50)
  ctx.rotate((Math.PI / 180) * 25); // Rotate 25 degrees (converted to radians)
  ctx.fillStyle = 'blue'; // Set fill color to blue
  ctx.fillRect(0, 0, 100, 50); // Draw at the new, rotated origin
  ctx.restore(); // Back to the original coordinate system
</script>
</body>
</html>

Анимация с помощью Canvas

В canvas нет встроенной анимации; движение создаётся путём многократной очистки и перерисовки всей поверхности. Функция браузера requestAnimationFrame планирует запуск вашей функции рисования перед следующей перерисовкой — как правило, 60 раз в секунду — и автоматически приостанавливается, когда вкладка скрыта, именно поэтому она предпочтительнее setInterval.

Цикл всегда состоит из трёх шагов: очистить canvas (clearRect), обновить состояние (здесь — позицию x) и нарисовать новый кадр. Если забыть clearRect, вместо движущейся фигуры вы увидите след от всех прошлых кадров.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Animation Example</title>
<style>
  canvas {
    border: 1px solid black;
  }
</style>
</head>
<body>
<canvas id="animationCanvas" width="200" height="200"></canvas>
<script>
  const canvas = document.getElementById('animationCanvas');
  const ctx = canvas.getContext('2d');
  let x = 0; // Starting position
  function drawFrame() {
    ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear the canvas for the new frame
    ctx.fillStyle = 'green'; // Set the fill color to green
    ctx.fillRect(x, 20, 50, 50); // Draw a moving rectangle
    x++; // Increment the horizontal position
    if (x > canvas.width) {
      x = 0;
    }
    requestAnimationFrame(drawFrame); // Continue the animation
  }
  drawFrame();
</script>
</body>
</html>

Типичные ошибки

  • Размытый вывод: несовпадение размера буфера и CSS-размера. Устанавливайте размеры через атрибуты width/height, а не через CSS, если только вы намеренно не масштабируете.
  • Фигуры сливаются: если забыть beginPath() перед новым путём, он продолжит предыдущий.
  • Линии исчезают: вы вызвали stroke() или fill(), но не построили путь, либо нарисовали за пределами canvas.
  • Анимация оставляет следы: отсутствует clearRect в начале каждого кадра.
  • Ничего не отображается: скрипт выполнился до того, как <canvas> появился в DOM. Разместите скрипт после элемента или запустите его по событию DOMContentLoaded.

Заключение

Элемент <canvas> предоставляет низкоуровневую поверхность с точностью до пикселя для графики, которую нельзя создать средствами HTML и CSS: диаграммы, редактирование изображений, системы частиц и полноценные игры. API невелик — получить контекст, установить стиль, выдать команду рисования — а анимации — это просто тот же цикл, выполняемый много раз в секунду.

Чтобы углубиться в тему, смотрите тег HTML canvas и основы рисования на canvas для разметки, а также анимации JavaScript и API анимаций на основе requestAnimationFrame для более плавного движения. Чтобы надёжно выбирать canvas, ознакомьтесь с getElement и querySelector.

Практика

Практика
Что можно сделать с элементом Canvas в JavaScript согласно материалам на w3docs.com?
Что можно сделать с элементом Canvas в JavaScript согласно материалам на w3docs.com?
Was this page helpful?