HTML5: Canvas. Основы

Знакомство с новым элементом
Первый пример
Настройки цвета и размера
Прямоугольники
Линии и дуги
Окружности
Закруглённые углы
Кривые Безье
Функция clip() - ограничиваем область рисования
Тени
Градиенты
Прозрачность
Используем шаблоны
Треугольник Серпинского
Рисование изображений
Рисование текста
Комбинирование наложений

Знакомство с новым элементом

Canvas - это новый элемент HTML5, который предназначен для создания растрового изображения при помощи JavaScript. Само слово canvas переводится как холст или канва. Текст внутри тега будет проигнорирован браузером с поддержкой canvas и показан в браузере без поддержки canvas.


<canvas id="test" width="500" height="500">
    Здесь можно указать текст для тех,
    у кого не поддерживается тег canvas
</canvas>

У тега есть два атрибута — height (высота) и width (ширина). Если размеры не указать, то по умолчанию размер холста будет равен 150х300 пикселей. Canvas создает область фиксированного размера, содержимым которого управляют контексты. Атрибуты не имеют отношения к CSS, они обозначают ширину и высоту canvas в пикселях не на экране, а на координатной плоскости холста.

Также требуется установить обязательный идентификатор для обращению к элементу в JavaScript.

Также можно применить стиль, например, сделаем рамку вокруг холста и не будем устанавливать размеры, чтобы увидеть ширину и высоту по умолчанию.

Canvas

<canvas id="border" style = "border:2px solid black">Canvas</canvas>

Сейчас все современные браузеры поддерживают canvas. Если такой уверенности нет, то можно устроить небольшую проверку.


var canvas = document.getElementById('my_canvas');
if (canvas.getContext){
    var context = canvas.getContext('2d');
}else{
    //  Сделать  что-то для  вывода  скрытого  содержимого 
    //  или  позволить  браузеру  вывести  текст элемента canvas
}

Мы находим элемент canvas по идентификатору, а затем вызываем метод getContext() с единственным параметром - строкой 2d. Если getContext() возвращает ответ, мы получаем 2D-контекст холста для добавления объектов.

Размер холста можно вычислить программно через свойства canvas.width и canvas.height.

Первый пример


  <canvas height='320' width='480' id='first_example'>Пример</canvas>
  <script>
    var canvas = document.getElementById("first_example");
    var context = canvas.getContext('2d');
    context.fillRect(0, 0, canvas.width, canvas.height);
  </script>

Пример

Если открыть созданный пример браузером, то увидим область с чёрным прямоугольником. Это и есть тот самый холст, на котором нарисован прямоугольник, размеры которого равны размерам элемента canvas. Если бы мы не рисовали чёрный прямоугольник, то у нас был бы прозрачный холст. Размеры задаются в пикселях, а отсчёт идёт от верхнего левого угла. На холсте можно рисовать различные фигуры. Можно указать отрицательные значения для координат, ошибки не произойдёт, но смысла в этом нет - фигуры не будут видны на экране.

Настройки цвета и размера

Стили для заливки и обводки имеют глобальный параметр. Если вы задали какое-то свойство, то оно применится для всех элементов, если не был после этого изменен. Например, мы сначала задали зелёный цвет для заливки и синий для обводки. Если после этого мы нарисуем несколько фигур, то они все будут иметь зелёный фон и синюю обводку.

За заливку отвечает свойство fillStyle. По умолчанию для заливки используется чёрный цвет. За цвет и стиль обводки отвечает свойство strokeStyle.

Цвет задается точно так же как и в CSS (четыре способа)


// все четыре строки задают оранжевый цвет заливки
context.fillStyle = "orange";
context.fillStyle = "#FFA500";
context.fillStyle = "rgb(255,165,0)";
context.fillStyle = "rgba(255,165,0,1)"

Есть ещё редко используемый способ через HSL - hsl(219, 58%, 93%).

Установим желаемые настройки - укажем, что мы хотим красный цвет (#FF0000) и толщину в 3 пиксела для обводки и зеленый цвет (#00FF00) для заливки:


context.strokeStyle = '#FF0000'; // Цвет обводки
context.lineWidth = 3; // Ширина линии
context.fillStyle = '#00FF00'; // Цвет заливки

Прямоугольники

Начнем с прямоугольника. В canvas есть два вида прямоугольников — залитые и незалитые (обводка). Предусмотрены три функции для рисования прямоугольников.

  • strokeRect(x, y, ширина, высота) — рисует границы прямоугольника
  • fillRect(x, y, ширина, высота) — рисует закрашенный прямоугольник
  • clearRect(x, y, ширина, высота) — Очищает область на холсте размер с прямоугольника заданного размера в указанной позиции

Функция clearRect() как бы вырезает кусок фигуры, за которым можно увидеть холст.


context.clearRect(10, 10, 200, 200); // Очистка области указанного размера и положения
context.clearRect(0, 0, canvas.width, canvas.height); // Очистка всего холста 

Нарисуем два вида прямоугольников.

Пример

var canvas = document.getElementById("rectangles");
var context = canvas.getContext('2d');

context.strokeStyle = '#FF0000'; // Цвет обводки
context.lineWidth = 3; // Ширина линии
context.fillStyle = '#00FF00'; // Цвет заливки

context.fillRect(10, 10, 390, 100);
context.strokeRect(40, 130, 200, 150);

Попробуйте нарисовать ещё один закрашенный прямоугольник и вырезать из него прямоугольник меньшего размера.

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

Наложение прямоугольников

<canvas id='rects'>Наложение прямоугольников</canvas>

<script>
    var canvas = document.getElementById("rects");
    var context = canvas.getContext('2d');
    canvas.height = 200;
    canvas.width = 300;
    
    context.fillStyle = "rgb(200, 0, 0)";
    context.fillRect(15, 15, 100, 100); 
    context.fillStyle = "rgb(0, 200, 0)";
    context.fillRect(30, 30, 100, 100);
    context.fillStyle = "rgb(0, 0, 200)";
    context.fillRect(45, 45, 100, 100);
</script>

Рисуем шахматную доску


<canvas id='chessboard'>Шахматная доска</canvas>

<script>
    var canvas = document.getElementById("chessboard");
    var context = canvas.getContext('2d');
    // Размеры холста
    canvas.width  = 300;
    canvas.height = 300;
    // Внешняя рамка для доски
    context.strokeRect(15, 15, 266, 266);
    // Внутренняя рамка для доски
    context.strokeRect(18, 18, 260, 260);
    // Закрашиваем внутреннюю область черным цветом
    context.fillRect(20, 20, 256, 256);
    for (i = 0; i < 8; i += 2)
      for (j = 0; j < 8; j += 2) {
        context.clearRect(20 + i * 32, 20 + j * 32, 32, 32);
        context.clearRect(20 + (i + 1) * 32, 20 + (j + 1) * 32, 32, 32);
      }
</script>
Шахматная доска

В этом примере мы установили размер холста 300 на 300 пикселей. Далее мы нарисовали два пустых прямоугольника, которые формируют рамку вокруг нашей «шахматной доски». Далее закрашиваем внутреннюю часть рамки прямоугольником черного цвета, а затем в цикле делаем в них своеобразные квадратные "дырки", чтобы через них просвечивал белый цвет. В итоге у нас получится красивая шахматная доска.

Раскрашиваем шахматную доску

Цветная шахматная доска

<canvas id='color_chessboard'>Цветная шахматная доска</canvas>

<script>
  var canvas = document.getElementById("color_chessboard");
  var context = canvas.getContext('2d');
  canvas.width  = 300;
  canvas.height = 300;
  context.strokeStyle = '#B70A02'; // меняем цвет рамки
  context.strokeRect(15, 15, 266, 266);
  context.strokeRect(18, 18, 260, 260);
  context.fillStyle = '#AF5200'; // меняем цвет клеток
  context.fillRect(20, 20, 256, 256);
  for (i = 0; i < 8; i += 2)
    for (j = 0; j < 8; j += 2) {
      context.clearRect(20 + i * 32, 20 + j * 32, 32, 32);
      context.clearRect(20 + (i + 1) * 32, 20 + (j + 1) * 32, 32, 32);
    }
</script>

Линии и дуги

Мы можем рисовать прямые и изогнутые линии, окружности и другие фигуры. Замкнутые линии можно заливать цветом. В отличии от рисования прямоугольников, рисование линий это не одна команда, а их последовательность. Так, сначала надо объявить начало новой линии с помощью beginPath(), а в конце сказать от том, что рисование линии заканчивается с помощью closePath(). У каждого отрезка линии есть начало и конец.

beginPath используется что бы «начать» серию действий описывающих отрисовку фигуры. Каждый новый вызов этого метода сбрасывает все действия предыдущего и начинает «рисовать» снова.

closePath является не обязательным действием и по сути оно пытается завершить рисование проведя линию от текущей позиции к позиции с которой начали рисовать.

Завершающий шаг - это вызов методов stroke или fill. stroke обводит фигуру линиями, а fill заливает фигуру сплошным цветом.

Также существуют такие методы как,

  • moveTo(x, y) - перемещает "курсор" в позицию x, y и делает её текущей
  • lineTo(x, y) - ведёт линию из текущей позиции в указанную, и делает в последствии указанную текущей
  • arc(x, y, radius, startAngle, endAngle, anticlockwise) - рисование дуги, где x и y центр окружности, далее начальный и конечный угол, последний параметр указывает направление

Давайте нарисуем ломаную, состоящую из двух отрезков:


context.beginPath();
context.moveTo(10, 10); // Начало линии 
context.lineTo(100, 100); // Узел линии  
context.lineTo(150, 100); // Конец линии 
context.closePath();

Если набор отрезков будет замкнут, то у нас получится полигон, который можно залить цветом. Создадим и зальём треугольник с помощью функции fill().


context.beginPath();  
context.moveTo(50, 50);  
context.lineTo(50, 250);  
context.lineTo(250, 250);  
context.closePath();  
context.fill();

Изменяем ширину линии

Значение ширины линии хранится в свойстве lineWidth контекста canvas и одна единица соответствует одному пикселю. Значение по умолчанию естественно 1.0

Стиль верхушки линий

Стиль верхушки линии хранится в свойстве lineCap и для него существуют три возможных значения:

  • butt (по умолчанию)
  • round
  • sqare
,

Стиль соединения линий

Стиль соединения линий хранится в свойстве lineJoin и может принимать три возможных значения:

  • miter (по умолчанию)
  • round
  • bevel

Мы можем ограничить длину огромного хвоста miter с помощью свойства miteLimit, которое по умолчанию принимает значение 10.

Рисуем корону

Корона

<canvas id='crown'>Корона</canvas>

<script>
    var canvas = document.getElementById("crown");
    var context = canvas.getcanvas('2d');
    canvas.height = 200;
    canvas.width = 200;
    context.beginPath();
    context.arc(80, 100, 56, 3/4 * Math.PI, 1/4 * Math.PI, true);
	//Заливаем дугу
    context.fill();
    context.moveTo(40, 140);
    context.lineTo(20, 40);
    context.lineTo(60, 100);
    context.lineTo(80, 20);
    context.lineTo(100, 100);
    context.lineTo(140, 40);
    context.lineTo(120, 140);
	// Обводим контур короны
    context.stroke();
</script>

Окружности

Окружности рисуются с помощью команды arc(ox, oy, radius, startAngle, endAngle, antiClockWise), где ox и oy — координаты центра, radius — радиус окружности, startAngle и endAngle — начальный и конечный углы (в радианах) для отрисовки окружности, а antiClockWise — направление движения при отрисовке (true для против часовой стрелке, false — против). С помощью arc() можно рисовать как круги и окружности, так и дуги и части окружности.

Окружность с радиусом в 100 пикселей:


context.beginPath();  
context.arc(250, 250, 100, 0, Math.PI * 2, false);  
context.closePath();
context.fill(); // Заливка окружности

Нарисуем разноцветный круг:

Код нарисует круг, состоящий из 6 сегментов с произвольными цветами, которые будут меняться при обновлении страницы


<canvas id="color_circle" width="300" height="200"></canvas>
 
<script>
    canvas = document.getElementById("color_circle");
    context = canvas.getContext("2d");
    
    for(var i = 0; i < 6;i++){
        context.fillStyle = 'rgb(' + Math.round(Math.random()*255) + ',' + Math.round(Math.random() * 255) + ',' + Math.round(Math.random()*255) +')'
    context.beginPath();
    context.arc(100, 100, 70, Math.PI/3 * i, Math.PI/3 * (i + 1), false)
    context.lineTo(100, 100);
    context.fill();
}
</script>

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

Дольки

<canvas id='arc_demo'>Дольки</canvas>

<script>
  var canvas = document.getElementById("arc_demo");
  var context = canvas.getContext('2d');
  canvas.height = 200;
  canvas.width = 500;
  
  function drawArc(xPos, yPos, radius, startAngle, endAngle, anticlockwise, lineColor, fillColor)
  {
    var startAngle = startAngle * (Math.PI/180);
    var endAngle = endAngle * (Math.PI/180);
    var radius = radius;
    context.strokeStyle = lineColor;
    context.fillStyle = fillColor;
    context.lineWidth = 8;
    context.beginPath();
    context.arc(xPos, yPos, radius, startAngle, endAngle, anticlockwise);
    context.fill();
    context.stroke();
  }
  
  drawArc(50, 15, 40, 0, 180, false, "aqua", "yellow");
  drawArc(150, 15, 50, 350, 170, false, "green", "pink");
  drawArc(270, 70, 60, 0, 100, true, "red", "white");
  drawArc(400, 60, 50, 350, 20, true, "blue", "purple");
</script>

Теперь нарисуем круги из этих же фигур.

Дольки

<canvas id='circles_demo'>Дольки</canvas>

<script>
  var canvas = document.getElementById("circles_demo");
  var context = canvas.getContext('2d');
  canvas.height = 200;
  canvas.width = 500;
  
  function drawCircle(xPos, yPos, radius, lineColor, fillColor)
  {
    var startAngle = 0 * (Math.PI/180);
    var endAngle = 360 * (Math.PI/180);
    var radius = radius;
    context.strokeStyle = lineColor;
    context.fillStyle = fillColor;
    context.lineWidth = 8;
    context.beginPath();
    context.arc(xPos, yPos, radius, startAngle, endAngle, false);
    context.fill();
    context.stroke();
  }
  
  drawCircle(50, 45, 40, "aqua", "yellow");
  drawCircle(150, 55, 50, "green", "pink");
  drawCircle(270, 70, 60, "red", "white");
  drawCircle(400, 65, 50, "blue", "purple");
</script>

Частичная заливка окружности

Нарисуем частично залитую окружность.

Частично залитая окружность

<canvas id='part_circle'>Частично залитая окружность</canvas>

<script>
  var canvas = document.getElementById("part_circle");
  var context = canvas.getContext('2d');
  canvas.height = 400;
  canvas.width = 400;
  context.beginPath();
  context.arc(200, 200, 100, 0, Math.PI * 0.85, false)
  context.stroke();

  context.beginPath();
  context.arc(200, 200, 100, 0, Math.PI * 0.85, true);
  context.fill();
</script>

Много кругов

Нарисуем круги в случайном порядке.

круги в случайном порядке

<canvas id='random_circle'>круги в случайном порядке</canvas>

<script>
  var canvas = document.getElementById("random_circle");
  var context = canvas.getContext('2d');
  canvas.height = 400;
  canvas.width = 400;
  
  var numCircles = 500;
  var maxRadius = 20;
  var minRadius = 3;
  var colors =
      ["aqua", "black", "blue", "fuchsia", "green", "cyan", "lime", "maroon",
      "navy", "olive", "purple", "red", "silver", "teal", "yellow", "azure",
      "gold", "bisque", "pink", "orange"];
  var numColors = colors.length;
  
  // в цикле создаем круги
  for(var n = 0; n < numCircles; n++)
  {
    // в случайном порядке установим характеристики
    var xPos = Math.random() * canvas.width;
    var yPos = Math.random() * canvas.height;
    var radius = minRadius + (Math.random() * (maxRadius-minRadius));
    var colorIndex = Math.random() * (numColors - 1);
    colorIndex = Math.round(colorIndex);
    var color = colors[colorIndex];
    drawCircle(context, xPos, yPos, radius, color);
  }
  
  // функция для рисования круга
  function drawCircle(context, xPos, yPos, radius, color)
  {
    var startAngle = (Math.PI / 180) * 0;
    var endAngle = (Math.PI / 180) * 360;
    context.shadowColor = "gray";
    context.shadowOffsetX = 1;
    context.shadowOffsetY = 1;
    context.shadowBlur = 5;
    context.beginPath();
    context.arc(xPos, yPos, radius, startAngle, endAngle, false);
    context.fillStyle = color;
    context.fill();
  }
</script>

Закруглённые углы

Закруглённые углы рисуются при помощи функции arcto(), который содержит пять параметров.

  • xBeginning - координата X начала дуги
  • yBeginning - координата Y начала дуги
  • xEnd - координата X конца дуги
  • yEnd - координата Y конца дуги
  • Radius - радиус дуги
Закруглённые углы

<canvas id='arcto'>Закруглённые углы</canvas>

<script>
  var canvas = document.getElementById("arcto");
  var context = canvas.getContext('2d');
  canvas.height = 150;
  canvas.width = 400;
  
  var xPos = 25; 
  var yPos = 25; 
  var width = 150;
  var height = 75; 
  var radius = 30;
  
  context.strokeStyle = "blue"; 
  context.lineWidth = 20;
  context.lineCap = "square"; 
  context.shadowOffsetX = 3;
  context.shadowOffsetY = 3; 
  context.shadowBlur = 5;
  context.shadowColor = "gray";
  context.beginPath();
  context.moveTo(xPos, yPos);  
  context.lineTo(xPos + width - radius, yPos);
  context.arcTo(xPos + width, yPos, xPos + width, yPos + radius, radius);
  context.lineTo(xPos + width, yPos + height);
  context.stroke();
</script>

Кривые Безье

Имеются две функции, для построения кубической и квадратичной кривой Безье:

quadraticCurveTo(Px, Py, x, y)
bezierCurveTo(P1x, P1y, P2x, P2y, x, y)

x и y - это точки в которые необходимо перейти, а координаты P(Px, Py) в квадратичной кривой это дополнительные точки, которые используются для построения кривой. В кубической кривой соответственно две дополнительные точки.

Рисуем кривые Безье

Кривая Безье

<canvas id='bezier_demo'>Кривая Безье</canvas>

<script>
    var canvas = document.getElementById("bezier_demo");
    var context = canvas.getContext('2d');
    canvas.height = 200;
    canvas.width = 260;
    context.beginPath();
    context.moveTo(10, 15);
    context.bezierCurveTo(75, 55, 175, 20, 250, 15);
    context.moveTo(10, 15);
    context.quadraticCurveTo(100, 100, 250, 15);
    context.stroke();
</script>

Раскрашиваем кривые Безье

Раскрашиваем кривые Безье

<canvas id='color_bezier'>Раскрашиваем кривые Безье</canvas>

<script>
  var canvas = document.getElementById("color_bezier");
  var context = canvas.getContext('2d');
  canvas.height = 100;
  canvas.width = 260;
  context.strokeStyle = '#f00';
  context.beginPath();
  context.moveTo(10, 15);
  context.bezierCurveTo(75, 55, 175, 20, 250, 15);
  context.stroke();
  context.strokeStyle = '#0f0';
  context.beginPath();
  context.moveTo(10, 15);
  context.quadraticCurveTo(100, 100, 250, 15);
  context.stroke();
</script>

Это точка на фигуре?

Функция isPointInPath(float x, float y) вернёт значение true, если точка с переданными координатами находится внутри пути. Создадим путь в виде прямоугольника и проверим:

Пример 8

Данный скрипт должен вывести в отладочную консоль сначала true, а затем false.


<p><canvas id='example8'>Пример 8</canvas></p>

<script type="text/javascript">
  var example = document.getElementById("example8");
  var ctx = example.getContext('2d');
  example.height = 400;
  example.width = 400;
  ctx.beginPath();
  ctx.rect(200, 200, 100, 200);
  ctx.stroke();
  console.log(ctx.isPointInPath(250, 250));
  console.log(ctx.isPointInPath(100, 100));
</script>

Функция clip() - ограничиваем область рисования

Функция clip() ничего не рисует. После её вызова любой объект будет рисоваться только в том случае, когда он находится в области на которой определён путь. Нарисуем круг и ограничим область рисования этим кругом. Затем нарисуем две линии, которые будут видны только внутри круга:

Clip

Если закомментировать вызов функции clip(), то увидим, как на самом деле рисуются линии.

No clip

<canvas id='clip_demo'>Clip</canvas>

<script>
  var canvas = document.getElementById("clip_demo");
  var context = canvas.getContext('2d');
  canvas.height = 400;
  canvas.width = 600;
  context.beginPath();
  context.arc(200, 200, 150, 0, Math.PI * 2, true);
  context.stroke();  //Нарисуем круг по которому определим область пути
  context.clip();       //Ограничим область для рисования областью пути

  context.beginPath();
  context.moveTo(100, 320);
  context.lineTo(500, 120);
  context.lineTo(50, 250);
  context.stroke() //Нарисуем линии, которые будут видны только внутри круга
</script>

Тени

Тени canvas отбрасываются всегда, просто они отбрасываются с нулевым смещением и нулевым размытием. Есть четыре свойства управляющие тенями (через знак равно указаны стандартные значения):

  • shadowOffsetX = 0.0
  • shadowOffsetY = 0.0
  • shadowBlur = 0.0
  • shadowColor = "transparent black"

Возьмем предыдущий пример и посмотрим на тени

Shadow

<canvas id='clip_shadow'>Shadow</canvas>

<script>
  var canvas = document.getElementById("clip_shadow");
  var context = canvas.getContext('2d');
  canvas.height = 400;
  canvas.width = 600;
  context.beginPath();
  context.arc(200, 200, 150, 0, Math.PI * 2, true);
  context.stroke();  //Нарисуем круг по которому определим область пути
  context.clip();       //Ограничим область для рисования областью пути
    
  context.shadowOffsetX = -10;
  context.shadowOffsetY = -10;
  context.shadowBlur = 2;
  context.shadowColor = 'black';

  context.beginPath();
  context.moveTo(100, 320);
  context.lineTo(500, 120);
  context.lineTo(50, 250);
  context.stroke() //Нарисуем линии, которые будут видны только внутри круга
</script>

Пример с прямоугольниками.

Shadow

<canvas id='rect_shadow'>Shadow</canvas>

<script>
  var canvas = document.getElementById("rect_shadow");
  var context = canvas.getContext('2d');
  canvas.height = 100;
  canvas.width = 600;
  
  var x1Pos = 25;
  var x2Pos = 200;
  var yPos = 10;
  var length = 150; var height = 50;
  
  // первый прямоугольник с тенью
  context.shadowOffsetX = 4;
  context.shadowOffsetY = 4;
  context.shadowBlur = 3;
  context.fillStyle = "deeppink";
  context.shadowColor = "gray";
  context.fillRect (x1Pos, yPos, length, height);
  
  // второй прямоугольник с тенью
  context.shadowOffsetX = 12;
  context.shadowOffsetY = 12;
  context.shadowBlur = 4;
  context.strokeStyle = "aqua";
  context.shadowColor = "lightgreen";
  context.lineWidth = 8;
  context.strokeRect (x2Pos, yPos, length, height);
</script>

Градиенты

Линейные градиенты

Сначала создаётся объект градиента при помощи функции createLinearGradient(float x1, float y1, float x2, float y2) из точки (x1; y1) в точку (x2; y2). Затем добавляются цвета при помощи функции addColorStop(float offset, string color), где offset - отступ со значениями от 0 до 1, а color - нужный цвет. Далее созданный градиент применяется как стиль заливки в свойстве fillStyle.


<canvas id="lineargradient" width="160" height="160"></canvas>
    
<script>
    var canvas = document.getElementById("lineargradient");
    var context = canvas.getContext("2d");
    var gradient = context.createLinearGradient(0, 0, 150, 150);
    gradient.addColorStop(0.0, 'blue');
    gradient.addColorStop(0.5, 'red');
    gradient.addColorStop(1.0, 'green');
    context.fillStyle = gradient;
    
    // рисуем залитый прямоугольник
    context.fillRect(0, 0, 150, 150);
        
</script>

Радиальные градиенты

Радиальный градиент создаётся с помощью функции createRadialGradient(float x1, float y1, float r1, float x2, float y2, float r2) - плавный переход цвета из окружности с центром в точке (x1; y1) и радиусом r1 в окружность с центром точке (x2; y2) и радиусом r2.

Нарисуем шар с псевдо-освещением


<canvas id="radialgradient" width="500" height="170"></canvas>
    
<script>
    var canvas = document.getElementById("radialgradient");
    var context = canvas.getContext("2d");
    
    context.shadowOffsetX = 10;
    context.shadowOffsetY = 15;
    context.shadowBlur = 10;
    context.shadowColor = '#0F0';
    
    var gradient = context.createRadialGradient(60, 60, 15, 75, 75, 75);
    gradient.addColorStop(0.0, '#0F0');
    gradient.addColorStop(1.0, '#0DA805');

    context.fillStyle = gradient;

    context.beginPath();
    context.arc(75, 75, 75, 0, Math.PI * 2, false);
    context.fill();
        
</script>

Прозрачность

Прозрачность задаётся через атрибут globalAlpha. Значения находятся в диапазоне от 0 до 1, где 0 - полная прозрачность, 1 - сплошной цвет.


<canvas id="transparent_demo" width="500" height="100"></canvas>
    
<script>
    var canvas = document.getElementById("transparent_demo");
    var context = canvas.getContext("2d");
    
    // первый объект
    var xPos = 20;
    var yPos = 20;
    var gap = -20;
    var width = 80; var height = 80;
    
    // тень
    context.shadowOffsetX = 4;
    context.shadowOffsetY = 4;
    context.shadowBlur = 3;
    context.shadowColor = "gray";
    
    // прозрачность
    context.globalAlpha = 1;
    context.fillStyle = "orange";
    context.fillRect (xPos + (0 * width) + (0 * gap), yPos, width, height);
    context.globalAlpha = .5;
    context.fillStyle = "blue";
    context.fillRect (xPos + (1 * width) + (1 * gap), yPos, width, height);
    context.globalAlpha = .25;
    context.fillStyle = "red";
    context.fillRect (xPos + (2 * width) + (2 * gap), yPos, width, height);
    context.globalAlpha = .25;
    context.fillStyle = "limegreen";
    context.fillRect (xPos + (3 * width) + (3 * gap), yPos, width, height);
    context.globalAlpha = .4;
    context.fillStyle = "magenta";
    context.fillRect (xPos + (4 * width)+(4 * gap), yPos, width, height);
    context.globalAlpha = .25;
    context.fillStyle = "gold";
    context.fillRect (xPos + (5 * width) + (5 * gap), yPos, width, height);
    context.globalAlpha = .4;
    context.fillStyle = "turquoise";
    context.fillRect (xPos + (6 * width) + (6 * gap), yPos, width, height);

Также прозрачность можно задать в атрибутах цвета:


context.fillStyle = "rgb(0, 0, 255, .5)";

Используем шаблоны

Кроме цветов и градиентов fillStyle и strokeStyle в качестве значения могут принимать и так называемые шаблоны. Шаблоны можно создать из того же самого canvas элемента, изображения или видео. Для примера будем использовать изображение. Шаблон создается методом createPattern(object any, string repeat), где repeat может принимать следующие значения:«repeat» (по умолчанию),«repeat-x»,«repeat-y»,«no-repeat».

Треугольник Серпинского


<canvas id="pascalCanvas" width="800" height="800"></canvas>
 
<script>
 
    function drawPixel(x, y, context) {
        context.fillRect(x, y, 1, 1);
    }
 
    var canvas = document.getElementById("pascalCanvas");
    var context = canvas.getContext("2d");
 
    // gradient style
    var gradient = context.createLinearGradient(0, 0, 0, canvas.height);
    gradient.addColorStop(0, "#00f");
    gradient.addColorStop(1, "#f30");
    context.fillStyle = gradient;
    //context.fillStyle = "#000";
 
    //Pascal's triangle
    var tr = new Array(canvas.height);
    for (i = 0; i < canvas.height; i++) {
        tr[i] = new Array(canvas.width);
        for (k = 0; k < canvas.width; k++) {
            if (k == 0)
                tr[i][k] = 1;
            else
                tr[i][k] = 0;
        }
    }
 
    for (i = 1; i < canvas.height; i++) {
        for (k = 1; k < canvas.width; k++) {
            tr[i][k] = (tr[i-1][k-1] + tr[i-1][k]) % 2;
        }
    }
 
    //draw
    for (i = 0; i < canvas.height; i++) {
        for (k = 0; k < canvas.width; k++) {
            if (tr[i][k] != 0)
            drawPixel(k, i, context);
        }
    }
</script>

Отсюда

Рисование изображений

Чтобы нарисовать изображение, нужно создать его объект с помощью конструктора Image, затем установить путь к изображению через свойство src полученного объекта.

Прежде чем рисовать изображение, его стоит загрузить. Для этого добавим обработчик события load для объекта img, добавим его после создания объекта.

Далее можно нарисовать изображение исходного размера с помощью функции drawImage(object img, float x, float y), где указывается его верхний левый угол в точке (x;y).

Для масштабирования используется другая версия функции - drawImage(object img, float x, float y, float w, float h) - в последних двух параметрах указывается ширина и высота.

Также можно обрезать картинку через ещё одну версию функции drawImage(object img, float sx, float sy, float sw, float sh, float cx, float cy, float cw, float ch) - нарисует часть изображения шириной sw и высотой sh расположенную в точке (sx,sy) в исходном изображении на canvas с шириной cw и высотой ch в точке (cx,cy).


var img = new Image()
img.onload =  function(){
    //Тут ваш код для работы с контекстом
}
img.src = 'path.png'

Выведем изображения с разными размерами.


<canvas id="images_demo" width="500" height="150" style = "border:2px solid black"></canvas>
    
<script>
    var canvas = document.getElementById("images_demo");
    var context = canvas.getContext("2d");
    
    var smallImageXPos = 40;
    var smallImageYPos = 55;
    var smallImageWidth = 75;
    var smallImageHeight = 75;
    var largeImageXPos = 225;
    var largeImageYPos = 10;
    var sourceCropX = 25;
    var sourceCropY = 25;
    var sourceCropWidthX = 50;
    var sourceCropWidthY = 50;
    var imageWidth = 80;
    var imageHeight = 80;
    
    var smallImage = new Image();
    var largeImage = new Image();
    
    smallImage.onload = function()
    {
        context.drawImage(smallImage, smallImageXPos, smallImageYPos);
        context.drawImage(smallImage, smallImageXPos + 80, smallImageYPos - 25,
        smallImageWidth, smallImageHeight);
    }
    
    largeImage.onload = function()
    {
        context.drawImage(largeImage, largeImageXPos, largeImageYPos);
         context.drawImage (largeImage, sourceCropX, sourceCropY,
        sourceCropWidthX, sourceCropWidthY,
        largeImageXPos + 140, largeImageYPos + 10,
        imageWidth, imageHeight);
    }
    
    smallImage.src = "../images/star.jpg";
    largeImage.src = "../images/star.jpg";

    context.shadowOffsetX = -3;
    context.shadowOffsetY = 3;
    context.shadowBlur = 8;
    context.shadowColor = "gray";
</script>

Нельзя вызывать метод drawImage(), если картинка не загружена в браузер. В примере я заранее вывел картинку при помощи тега img. Обычно, в подобных случаях используют вызов window.onload() или document.getElementById("imageID").onload.

Ваш браузер не поддерживает canvas

<canvas id="otherImage" width="250" height="300" style="border:1px solid #d3d3d3;">
    Ваш браузер не поддерживает canvas
</canvas>

<script>
window.onload = function() {
    var canvas = document.getElementById('otherImage');
    var context = canvas.getContext('2d');
    var image = new Image();

    image.onload = function() {
       context.drawImage(image, 30, 30);
    };
      
    image.src = 'http://developer.alexanderklimov.ru/android/images/android_cat.jpg';
}
</script>

Для сохранения изображений существует три метода (getAsFile,getBlob,toDataURL), самый удобный - toDataURL поскольку именно он наиболее хорошо поддерживается браузерами. Стоит заметить что метод применяется не к контексту, а к canvas элементу, впрочем его можно получить как свойство 'canvas' контекста, также этот метод принимает как аргумент тип изображения (по умолчанию 'png'). Этот метод вернет изображение в формате base64.

Рисование текста

Существуют функции рисование текста. Залитый текст рисуется через функцию context.fillText(string text, float x, float y) в точке (x;y)

Функция fillText() имеет необязательный аргумент maxWidth, который не совсем корректно работает в некоторых браузерах.

Свойство контекста font управляет стилем текста и имеет синтаксис схожий с css:


// формат
// context.font = "style weight size face";

Не все атрибуты свойства font обязательно указывать. Если какой-то атрибут пропущен, то будет использоваться значение по умолчанию.

Для стилей используются следующие значения

  • normal(the default)
  • italic
  • oblique(similar to italic, usually associated with sans-serif faces)
  • inherit (style comes from the parent element)

Для веса используются значения:

  • normal(the default)
  • bold | bolder
  • lighter
  • 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
  • inherit(weight comes from the parent element)

Для размеров:

  • px - pixels
  • pt - points
  • em

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

  • Sans-serif: Arial, Verdana
  • Serif: Georgia, Times New Roman, Times
  • Monospace: Courier New, Courier
    
context.font = "bold italic 30px sans-serif";
context.fillText("Hello Kitty", 300, 300);

Управлять цветом мы можем через свойства fillStyle и strokeStyle.

Для рисования контуров текста применяется функции strokeText() вместо fillText().

Для выравнивания текста существует свойство textAlign, оно может принимать пять возможных значений:

  • left — текст выравнивается слева
  • right — текст выравнивается справа
  • center — текст выравнивается по центру
  • start — (значение по умолчанию) текст выравнивается от начала линии слева для письма слева на право и выравнивается справа для письма справа налево
  • end — текст выравнивается от начала линии справа для письма слева на право и выравнивается слева для письма справа налево

<canvas id="textalign_demo" width="500" height="170" style = "border:2px solid black"></canvas>
    
<script>
    var canvas = document.getElementById("textalign_demo");
    var context = canvas.getContext("2d");
    var xPos = canvas.width/2;
    var yPos = 30;
    
    context.font = "15pt Arial";
    context.fillStyle = "blue";
    context.strokeStyle = "hotpink";
    context.lineWidth = 1;
    context.beginPath();
    context.moveTo(xPos, 0);
    context.lineTo(xPos, canvas.height);
    context.stroke();
    context.textAlign = "right";
    context.fillText("right", xPos, yPos * 1);
    context.textAlign = "end";
    context.fillText("end", xPos, yPos * 2);
    context.textAlign = "center";
    context.fillText("center", xPos, yPos * 3);
    context.textAlign = "left";
    context.fillText("left", xPos, yPos * 4);
    context.textAlign = "start";
    context.fillText("start", xPos, yPos * 5);
</script>

Для управления линией основания текста существует свойство textBaseline, оно может принимать следующие значения:

  • top
  • hanging
  • middle
  • alphabetic
  • ideographic
  • bottom

Измерить ширину текста можно через measureText(string text). Она вернет специальный объект TextMetrics, который обладает свойством width — ширина текста в пикселях.


<canvas id="drawtext_demo" width="500" height="170"></canvas>
    
<script>
    var canvas = document.getElementById("drawtext_demo");
    var context = canvas.getContext("2d");
    
    // центрируем текст
    var mText = "Hello Kitty!";
    var xPos = canvas.width/2;
    var yPos = canvas.height/2;

    context.font = "60pt Comic Sans MS";
    context.fillStyle = "lime";
    context.textAlign = "center";
    context.textBaseline = "middle";
    context.fillText(mText, xPos, yPos);
        
</script>

Комбинирование наложений

Наложение двух фигур можно осуществить при помощи свойства globalCompositeOperation, которое может принимать одно из значений.

  • source-over
  • source-in
  • source-out
  • source-atop
  • destination-over
  • destination-in
  • destination-out
  • destination-atop
  • lighter
  • copy
  • xor

Выведем все способы в таблице.


source-over

source-in

source-out

source-atop

destination-over

destination-in

destination-out

destination-atop

lighter

copy

xor

<table border="1" align="center">
  <tr>
    <td>
      <canvas id="source-over" width="120" height="110"></canvas><br/><l>source-over</l>
    </td>
    <td>
        <canvas id="source-in" width="120" height="110"></canvas><br/><l>source-in</l>
    </td>
    <td>
        <canvas id="source-out" width="120" height="110"></canvas><br/><l>source-out</l>
    </td>
    <td>
        <canvas id="source-atop" width="120" height="110"></canvas><br/><l>source-atop</l>
    </td>
  </tr>
  <tr>
    <td>
        <canvas id="destination-over" width="120" height="110"></canvas><br/><l>destination-over</l>
    </td>
    <td>
        <canvas id="destination-in" width="120" height="110"></canvas><br/><l>destination-in</l>
    </td>
    <td>
        <canvas id="destination-out" width="120" height="110"></canvas><br/><l>destination-out</l>
    </td>
    <td>
        <canvas id="destination-atop" width="120" height="110"></canvas><br/><l>destination-atop</l>
    </td>
  </tr>
  <tr>
      <td>
        <canvas id="lighter" width="120" height="110"></canvas><br/><l>lighter</l>
      </td>
      <td>
        <canvas id="copy" width="120" height="110"></canvas><br/><l>copy</l>
      </td>
      <td>
        <canvas id="xor" width="120" height="110"></canvas><br/><l>xor</l>
      </td>
    </tr>
</table>

<script>
    function drawShapes(type)
    {
        canvas = document.getElementById(type);
        context = canvas.getContext("2d");
        var squareOffset = 15;
        var squareSide = 70;
        var circleOffset = 73;
        var circleRadius = 35;

        context.fillStyle = "blue";
        context.fillRect(squareOffset, squareOffset, squareSide, squareSide);

        context.globalCompositeOperation = type;

        context.fillStyle = "red";
        context.beginPath();
        context.arc(circleOffset, circleOffset, circleRadius, 0, Math.PI * 2, true);
        context.fill();
    }
    
    drawShapes("source-over");
    drawShapes("source-in");
    drawShapes("source-out");
    drawShapes("source-atop");
    drawShapes("destination-over");
    drawShapes("destination-in");
    drawShapes("destination-out");
    drawShapes("destination-atop");
    drawShapes("lighter");
    drawShapes("copy");
    drawShapes("xor");
</script>
Реклама