Тег CANVAS: рисование на веб-странице (ч.5)

Автор: Topol Воскресенье, Май 6th, 2012 Нет комментариев

Рубрика: Операционные системы

14. Преобразования системы координат
Преобразования - это различные действия, которые мы можем выполнять над системой координат канвы. В число таких преобразований входят смещение точки начала координат, изменение масштаба системы координат и её поворот. Это может пригодиться, если мы собираемся создать фигуру, которую иными средствами нарисовать невозможно или очень сложно.

Отметим, что преобразования затрагивают только систему координат канвы. Уже присутствующая на ней графика останется неизменной. Однако графика, которую мы нарисуем после этого, будет выводиться уже в изменённой системе координат.
14.1. Сохранение и загрузка состояния канвы
Прежде чем начать разговор о поддерживаемых канвой HTML 5 преобразованиях, давайте рассмотрим ещё одну доступную в ней возможность. Это сохранение текущего состояния канвы и восстановление сохранённого ранее состояния. Мы имеем возможность сохранить в оперативной памяти текущее состояние канвы, которое включает:

 

  • все заданные преобразования канвы (будут описаны далее);
  • значения свойств fillStyle, lineCap, lineJoin, lineWidth, miterLimit и strokeStyle (все они были описаны ранее), а также свойств globalAlpha и globalCompositeOperation, которые мы рассмотрим потом;
  • все заданные маски (будут описаны далее).

Отметим, что сама графика, присутствующая на канве, в состояние канвы не входит и, следовательно, вместе с ним не сохраняется.

Сохрание состояния канвы выполняется вызовом метода save объекта CanvasRenderingContext2D. Этот метод не принимает параметров и не возвращает результата.

Код:
ctx1.save();

Впоследствии мы можем восстановить состояние канвы, сохранённое ранее. При этом все упомянутые выше свойства и параметры канвы получат те значения, что были на момент сохранения её состояния.

Для восстановления состояния канвы применяется метод restore объекта CanvasRenderingContext2D. Он также не принимает параметров и не возвращает результата.

Код:
ctx1.restore();

Мы можем сохранять состояние канвы несколько раз подряд и потом восстановить все сохранённые состояния. При первом вызове метод restore будет восстановлено самое последнее сохранённое состояние канвы, при последующем вызове — предпоследнее состояние и т. д. Такое многократное сохранение и восстановление состояния канвы часто применяется при создании сложной графики.

14.2. Смещение начала координат
Самое простое преобразование, которое мы можем применить к системе координат канвы, — смещение её начала координат в указанную точку. После этого координаты будут отсчитываться от нового начала координат. Для смещения начала координат канвы следует вызвать метод translate объекта CanvasRenderingContext2D:

Код:
контекст рисования.translate(
горизонтальная координата,
вертикальная координата
);

Параметры этого метода указывают координаты точки, в которой будет находиться новое начало системы координат. Результата этот метод не возвращает.

Код:
ctx1.save();
ctx1.translate(100, 100);
ctx1.fillStyle = «red»;
ctx1.fillRect(0, 0, 50, 50);
ctx1.fillStyle = «green»;
ctx1.translate(100, 100);
ctx1.fillRect(0, 0, 50, 50);
ctx1.restore();
ctx1.fillStyle = «blue»;
ctx1.fillRect(0, 0, 50, 50);

Этот код выполняет следующие действия:

  • Сохраняет текущее состояние канвы, в том числе и положение её системы координат (см. выше).
  • Перемещает начало координат в точку с координатами [100, 100].
  • Рисует красный квадрат размерами 50×50 пикселов, верхний левый угол которого находится в точке начала координат.
  • Опять перемещает начало координат в точку [100, 100]. Обратим внимание, что координаты этой точки теперь отсчитываются от нового начала системы координат, установленного предыдущим вызовом метода translate.
  • Рисует зелёный квадрат размерами 50×50 пикселов, верхний левый угол которого находится в начале координат.
  • Восстанавливает сохраненное состояние канвы, в том числе и положение начала системы координат (в нашем случае это положение по умолчанию, то есть верхний левый угол канвы).
  • Рисует синий квадрат размерами 50×50 пикселов, верхний левый угол которого находится в начале координат.

В результате мы увидим три разноцветных квадрата, расположенных по диагонали.

Примечание:
К сожалению, не существует простого способа вернуться к изначальному состоянию системы координат канвы. Единственный выход: перед выполнением самого первого преобразования сохранить состояние канвы и впоследствии, когда будет нужно, восстановить его.

14.3. Изменение масштаба системы координат
Ещё мы можем изменить масштаб системы координат канвы отдельно для горизонтальной и вертикальной оси в большую или меньшую сторону.

Для указания нового масштаба системы координат мы вызовем метод scale объекта canvasRenderingContext2D:

Код:
контекст рисования.scale(
масштаб по горизонтали,
масштаб по вертикали
);

Параметры этого метода задают новый масштаб для горизонтальной и вертикальной оси соответственно. Масштаб задаётся в виде числа с плавающей точкой; значение меньше 1.0 задаёт уменьшение масштаба, значения большие 1.0 — его увеличение, а значение 1.0 предписывает веб-браузера оставить масштаб без изменения. Метод scale не возвращает результата.

Код:
ctx1.save();
ctx1.strokeStyle = «red»;
ctx1.strokeRect(0, 0, 50, 50);
ctx1.scale(3, 1);
ctx1.strokeStyle = «green»;
ctx1.strokeRect(0, 0, 50, 50);
ctx1.restore();
ctx1.save();
ctx1.scale(1, 3);
ctx1.strokeStyle = «blue»;
ctx1.strokeRect(0, 0, 50, 50);
ctx1.restore();
ctx1.save();
ctx1.scale(3, 3);
ctx1.strokeStyle = «yellow»;
ctx1.strokeRect(0, 0, 50, 50);
ctx1.restore();

Этот код выполняет следующие действия:

  • Сохраняет текущее состояние канвы.
  • Рисует красный квадрат размерами 50х50 пикселов, верхний левый угол которого находится в начале координат.
  • Увеличивает масштаб по горизонтальной координатной оси в 3 раза.
  • Рисует зелёный квадрат размерами 50х50 пикселов, верхний левый угол которого находится в начале координат.
  • Восстанавливает сохранённое ранее состояние канвы и сохраняет его снова.
  • Увеличивает масштаб по вертикальной координатной оси в 3 раза.
  • Рисует синий квадрат размерами 50х50 пикселов, верхний левый угол которого находится в начале координат.
  • Восстанавливает сохранённое ранее состояние канвы и сохраняет его снова.
  • Увеличивает масштаб по обеим координатным осям в 3 раза.
  • Рисует жёлтый квадрат размерами 50х50 пикселов, верхний левый угол которого находится в начале координат.
  • Восстанавливает сохранённое ранее состояние канвы.

В результате мы увидим четыре разноцветных прямоугольника с реальными размерами 50х50, 150х50, 50х150 и 150х150 пикселов.

14.4. Поворот системы координат
Напоследок рассмотрим третью из поддерживаемых канвой HTML 5 преобразований — поворот системы координат на произвольный угол. Поворот этот выполняется относительно начала координат.

Чтобы повернуть систему координат, мы используем метод rotate объекта canvasRenderingContext2D. Этот метод принимает единственный параметр — угол поворота в виде числа, измеряемый в радианах. Результата он не возвращает.

Не забываем, что поворот выполняется вокруг начала системы координат. Поэтому, возможно, перед собственно поворотом нам придётся сместить начало системы координат в нужную точку (для этого применяется уже знакомый нам метод translate объекта canvasRenderingContext2D).

Код:
ctx1.translate(200, 150);
for (var i = 0; i < 4; i++) {
ctx1.beginPath();
ctx1.moveTo(0, -80);
ctx1.lineTo(-130, 80);
ctx1.lineTo(130, 80);
ctx1.closePath();
ctx1.stroke();
ctx1.rotate(Math.PI / 6);
}

Этот код сначала сдвигает начало координат в центр канвы (в точку [200, 150]), а потом четырежды рисует контур равностороннего треугольника и каждый раз после этого поворачивает систему координат на угол «число пи» / 6 радиан (или 30 градусов). В результате мы увидим четыре треугольника, каждый из которых повёрнут относительно «соседа».

15. Управление прозрачностью рисуемой графики
Мы уже давно научились задавать цвета рисуемых на канве фигур. В том числе, создавать полупрозрачные цвета. Однако канва HTML 5 позволяет нам непосредственно указать уровень прозрачности графики, которую мы впоследствии нарисуем (его называют глобальным уровнем прозрачности). Для этого используется свойство globalAlpha объекта canvasRenderingContext2D. В качестве значения оно принимает число с плавающей точкой от 0.0 (полная прозрачность) до 1.0 (полная непрозрачность либо уровень прозрачности, заданный в значении цвета; это, кстати, значение по умолчанию).

Как только мы укажем новое значение свойства globalAlpha, вся последующая графика будет нарисована с уровнем прозрачности, который мы указали. Уровень прозрачности уже нарисованной к данному моменту графики не изменится.

Значение свойства globalAlpha при рисовании графики умножается на значение полупрозрачности, заданное в цвете. Так, если мы указали в цвете значение полупрозрачности 0.5 и дополнительно задали значение свойства globalAlpha, равное 0.7, то результирующая степень полупрозрачности всех фигур, что мы впоследствии нарисуем, будет равна 0.5 * 0.7 = 0.35.

Код:
var img1 = new Image();
img1.src = «picture.jpg»;
img1.addEventListener(«load»,
function ()
{
ctx1.drawImage(img1, 0, 0, 400, 300);
ctx1.fillStyle = «#CCCCCC»;
ctx1.globalAlpha = 0.5;
ctx1.fillRect(0, 0, 400, 300);
}, false);

Этот код помещает на канву внешнее изображение, устанавливает глобальный уровень прозрачности в 0.5 и рисует поверх изображения серый прямоугольник. В результате мы получим мутное, размытое графическое изображение, словно наблюдаемое сквозь туман.

16. Управление наложением графики
Когда мы рисуем что-то на канве, то графика, нарисованная позднее, быдет перекрывать всю графику, что была нарисована ранее. Это поведение канвы по умолчанию. Однако мы можем изменить это поведение. Например, мы можем сделать так, чтобы графика, нарисованная позднее, наоборот, перекрывалась ранее нарисованной графикой или даже комбинировалась с ней каким-либо образом. Это поможет нам создать сложные фигуры, которые иным способом вряд ли получится нарисовать.

Свойство globalCompositeOperation объекта canvasRenderingContext2D как раз и служит для указания правила, согласно которым канва будет выполнять наложение графики. Доступные значения этого свойства перечислены ниже:

  • «source-over» — новая фигура накладывается на старую, перекрывая её (поведение по умолчанию).
  • «destination-over» — старая фигура накладывается на новую.
  • «source-in» — отображается только та часть новой фигуры, которая накладывается на старую. Остальные части новой фигуры и вся старая фигура не выводятся.
  • «destination-in» — отображается только та часть старой фигуры, на которую накладывается новая. Остальные части старой фигуры и вся новая фигура не выводятся.
  • «source-out» — отображается только та часть новой фигуры, которая не накладывается на старую. Остальные части новой фигуры и вся старая фигура не выводятся.
  • «destination-out» — отображается только та часть старой фигуры, на которую не накладывается новая. Остальные части старой фигуры и вся новая фигура не выводятся.
  • «source-atop» — отображается только та часть новой фигуры, которая накладывается на старую; остальная часть новой фигуры не выводится. Старая фигура выводится целиком и находится ниже новой.
  • «destination-atop» — отображается только та часть старой фигуры, на которую накладывается новая; остальная часть старой фигуры не выводится. Новая фигура выводится целиком и находится ниже старой.
  • «lighter» — цвета накладывающихся частей старой и новой фигур складываются, в результирующий цвет, который получается более светлым, окрашиваются накладывающиеся части фигур.
  • «darker» — цвета накладывающихся частей старой и новой фигур вычитаются, в полученный цвет, который получается более тёмным, окрашиваются накладывающиеся части фигур.
  • «xor» — отображаются только те части старой и новой фигур, которые не накладываются друг на друга.
  • «copy» — выводится только новая фигура; все старые фигуры удаляются с канвы.

 

Код:
var img1 = new Image();
img1.src = «picture.jpg»;
img1.addEventListener(«load»,
function ()
{
ctx1.fillStyle = «#CCCCCC»;
ctx1.globalAlpha = 0.8;
ctx1.fillRect(0, 0, 400, 300);
ctx1.globalCompositeOperation = «destination-out»;
ctx1.globalAlpha = 1.0;
ctx1.fillStyle = «green»;
ctx1.beginPath();
ctx1.arc(200, 150, 100, 0, 2 * Math.PI, false);
ctx1.fill();
ctx1.globalCompositeOperation = «destination-over»;
ctx1.drawImage(img1, 0, 0, 400, 300);
}, false);

Этот код выполняет следующие действия:

  • Рисует прямоугольник серого цвета с уровнем прозрачности 0.8, занимающий всю канву.
  • Задаёт правило наложения, согласно которому будет отображаться только та часть старой фигуры, на которую не накладывается новая; остальные части старой фигуры и вся новая фигура выводиться не будут (значение «destination-out» свойства globalCompositeOperation).
  • Рисует в центре канвы непрозрачную окружность. В результате мы получим серый прямоугольник с круглой «прорехой» посередине.
  • Задаёт правило наложения, согласно которому новая фигура будет выводиться ниже старой (значение «destination-over» свойства globalCompositeOperation).
  • Выводит на канву внешнее изображение, занимающее всю канву целиком. В результате мы получим изображение, закрытое нарисованным ранее полупрозрачным прямоугольником с круглой «прорехой».

Фактически мы взяли пример из параграфа 15 и дополнили его круглым «окошком», сквозь которое изображение видно чётко. Интересный, кстати, получился эффект! Попробуйте сами!

17. Создание масок
Ещё канва HTML 5 поддерживает чрезвычайно интересный и полезный эффект, который заслуживает отдельного разговора.

Предположим, что мы нарисовали два изображения — одно над другим. Первое (верхнее) изображение назовём маскирующим, а второе (нижнее) - маскируемым. Понятно, что маскирующее изображение будет частично или полностью скрывать маскируемое.

После этого мы создали ещё одно — третье по счёту — изображение. Но при этом указали канве не вывести его на экран, а «вырезать» в маскирующем изображении «дырку», форма которой в точности совпадает с третьим изображением. Эту «дырку» мы назовём маской.

Что мы получим в результате? Да, маскирующее изображение будет скрывать большую часть маскируемого. Но та часть маскируемого изображения, что «просвечивает» сквозь маску — «дырку» в маскирующем изображении, — будет видна.

Процесс создания маскирующего и маскируемого изображений и маски описан ниже. Отметим, что мы должны действовать именно в такой последовательности, иначе не получим нужного результата.

  • Рисуем маскирующее изображение.
  • Рисуем маску. В текущей реализации канвы маской может быть только сложная фигура (как они создаются, описано в параграфе 8). Рисуется она практически так же, как обычная сложная фигура, за одним-единственным исключением. Вместо методов stroke или fill для завершения её рисования следует вызвать метод clip объекта canvasRenderingContext2D. Этот метод не принимает параметров и не возвращает результата.
  • Рисуем маскируемое изображение.

Маскирующее и маскируемое изображения могут быть абсолютно любыми: прямоугольниками, сложными фигурами, текстом или внешним изображением.

Код:
var img1 = new Image();
img1.src = «picture.jpg»;
img1.addEventListener(«load»,
function ()
{
ctx1.fillStyle = «#CCCCCC»;
ctx1.globalAlpha = 0.4;
ctx1.drawImage(img1, 0, 0, 400, 300);
ctx1.globalAlpha = 1.0;
ctx1.beginPath();
ctx1.arc(200, 150, 100, 0, 2 * Math.PI, false);
ctx1.clip();
ctx1.drawImage(img1, 0, 0, 400, 300);
}, false);

Этот код выполняет следующие действия:

  • Выводит внешнее изображение с уровнем прозрачности 0.4, занимающее всю канву. Это будет маскирующее изображение.
  • Рисует окружность, расположенную в центре канвы. Это будет маска.
  • Выводит то же самое внешнее изображение, на этот раз полностью непрозрачное (уровень прозрачности 1.0). Это будет маскируемое изображение.

В результате мы получим мутное, малоразличимое изображение с «дыркой» посередине, в которой видно то же изображение, но уже чёткое, прекрасно видимое. Выглядит, кстати, отлично — поверьте автору, который сейчас воочию наблюдает всё это!

Примечание:
Если мы после создания маскирующего изображения, маски и маскируемого изображения создадим ещё одну маску, то предыдущая маска с маскирующим и маскируемым изображениями станет маскирующим изображением для новой маски. Нам останется только создать для новой маски маскируемое изображение — и система из двух масок, наложенных друг на друга готова! Таким образом мы можем создавать сложные изображения, накладывающиеся друг на друга и скрывающие части друг друга.

Продолжение следует…

Источник: thevista.ru

Оставить комментарий

Чтобы оставлять комментарии Вы должны быть авторизованы.

Похожие посты