Компоновка и обрезка
Во всех наших предыдущих примерах фигуры всегда рисовались друг на друге. Это вполне достаточно для большинства ситуаций, но оно ограничивает порядок построения составных фигур. Однако мы можем изменить это поведение, установив свойство globalCompositeOperation. Кроме того, свойство clip позволяет скрыть нежелательные части фигур.
globalCompositeOperation
Мы можем не только рисовать новые фигуры позади существующих, но и использовать их для маскирования определенных областей, очистки участков с холста (не ограничиваясь прямоугольниками, как это делает метод clearRect()) и многое другое.
globalCompositeOperation = type-
Это задаёт тип операции компоновки, применяемой при рисовании новых фигур, где тип — строка, определяющая, какая из двенадцати операций компоновки должна быть использована.
Обрезка по траекториям
Область обрезки — это обычная фигура холста, но она действует как маска для скрытия нежелательных частей фигур. Это показано на изображении ниже. Красная звёздчатая фигура — это наша область обрезки. Всё, что попадает за пределы этой области, не будет нарисована на холсте.
Если сравнить области обрезки со свойством globalCompositeOperation выше, то мы увидим два режима компоновки, которые достигают более или менее того же эффекта в source-in и source-atop. Самые важные различия между ними заключаются в том, что области обрезки никогда фактически не рисуются на холсте, и область обрезки никогда не изменяется при добавлении новых фигур. Это делает области обрезки идеальными для рисования нескольких фигур в ограниченной области.
В главе о рисовании фигур я упомянул только методы stroke() и fill(), но есть третий метод, который мы можем использовать с траекториями, называемый clip().
clip()-
Преобразует траекторию, которая в данный момент строится, в текущую область обрезки.
Вы используете clip() вместо closePath() для закрытия траектории и превращения её в область обрезки вместо обводки или заливки траектории.
По умолчанию элемент <canvas> имеет область обрезки, размер которой точно такой же, как размер холста. Другими словами, обрезка не выполняется.
Пример clip
В этом примере мы будем использовать круговую область обрезки для ограничения рисования набора случайных звёзд в определённом регионе.
function draw() {
const ctx = document.getElementById("canvas").getContext("2d");
ctx.fillRect(0, 0, 150, 150);
ctx.translate(75, 75);
// Create a circular clipping path
ctx.beginPath();
ctx.arc(0, 0, 60, 0, Math.PI * 2, true);
ctx.clip();
// Draw background
const linGrad = ctx.createLinearGradient(0, -75, 0, 75);
linGrad.addColorStop(0, "#232256");
linGrad.addColorStop(1, "#143778");
ctx.fillStyle = linGrad;
ctx.fillRect(-75, -75, 150, 150);
generateStars(ctx);
}
function generateStars(ctx) {
for (let j = 1; j < 50; j++) {
ctx.save();
ctx.fillStyle = "#fff";
ctx.translate(
75 - Math.floor(Math.random() * 150),
75 - Math.floor(Math.random() * 150),
);
drawStar(ctx, Math.floor(Math.random() * 4) + 2);
ctx.restore();
}
}
function drawStar(ctx, r) {
ctx.save();
ctx.beginPath();
ctx.moveTo(r, 0);
for (let i = 0; i < 9; i++) {
ctx.rotate(Math.PI / 5);
if (i % 2 === 0) {
ctx.lineTo((r / 0.525731) * 0.200811, 0);
} else {
ctx.lineTo(r, 0);
}
}
ctx.closePath();
ctx.fill();
ctx.restore();
}
В первых строках кода мы рисуем чёрную прямоугольную область размером с холст в качестве фона, затем перемещаем начало координат в центр. Затем мы создаём круговую область обрезки, рисуя дугу и вызывая clip(). Области обрезки также являются частью состояния сохранения холста. Если бы мы хотели сохранить исходную область обрезки, мы могли бы сохранить состояние холста до создания новой.
Всё, что рисуется после создания области обрезки, будет отображаться только внутри этой области. Это чётко видно на линейном градиенте, который рисуется дальше. После этого рисуется набор из 50 случайных по положению и масштабу звёзд, используя пользовательскую функцию drawStar(). Опять же, звёзды отображаются только внутри определённой области обрезки.
Обратная область обрезки
Обратной области обрезки не существует. Однако мы можем определить маску, которая заполняет весь холст прямоугольником и имеет отверстие для тех частей, которые вы хотите пропустить. При рисовании фигуры с отверстием нам нужно нарисовать отверстие в противоположном направлении, чем внешнюю фигуру. В примере ниже мы пробиваем дыру в небе.
Прямоугольник не имеет направления рисования, но он ведёт себя так, как будто мы нарисовали его по часовой стрелке. По умолчанию команда дуги также идёт по часовой стрелке, но мы можем изменить её направление последним аргументом.
function draw() {
const canvas = document.getElementById("canvas");
if (canvas.getContext) {
const ctx = canvas.getContext("2d");
ctx.translate(75, 75);
// Clipping path
ctx.beginPath();
ctx.rect(-75, -75, 150, 150); // Outer rectangle
ctx.arc(0, 0, 60, 0, Math.PI * 2, true); // Hole anticlockwise
ctx.clip();
// Draw background
const linGrad = ctx.createLinearGradient(0, -75, 0, 75);
linGrad.addColorStop(0, "#232256");
linGrad.addColorStop(1, "#143778");
ctx.fillStyle = linGrad;
ctx.fillRect(-75, -75, 150, 150);
generateStars(ctx);
}
}
© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Compositing