« Защита shareware приложений от взлома с помощью armadillo. Часть 1 | Защита shareware приложений от взлома с помощью armadillo. Часть 2 » |
Тег html canvas. Часть 2
Этой статьей я продолжу серию материалов посвященных тегу canvas – специальному расширению, поддерживаемому передовыми браузерами (opera, firefox) и позволяющему вам, используя вызовы функций javascript, рисовать растровые изображения в окне браузера.В прошлый раз я рассказал об методике внедрения тега canvas внутрь веб-страницы, о том как сделать fallback – механизм позволяющий корректно обработать ситуацию когда страница открывается не поддерживающим возможности canvas браузером (это про тебя дорогой internet explorer). Так же мы рисовали простые фигуры: линии, прямоугольники, эллипсы и дуги. Сегодня мы поговорим о работе с преобразованиями, управлении режимами наложения изображений при отрисовке.
Что такое преобразования? В мире компьютерной графики под ними понимают простейшие математические операции, позволяющие вам перед началом, собственно, рисования выполнить некоторое изменение в системе координат холста. По умолчанию ваш холст имеет точку начала координат (0,0), а масштаб оперирует минимальной цифрой в 1 пиксель, оси же направлены строго под прямым углом друг к другу – одним словом, то, что мы называем прямоугольной декартовой системой координат.
И, соответственно, перед началом рисования вы можете изменить эту систему координат, использую вызовы специальных функций в составе контекста рисования. За это отвечают следующие функции. Translate – эта функция получает в качестве параметра координаты куда переместится центр координат (СК). Функция rotate позволяет выполнить вращение СК. Вращение выполняется против часовой стрелки. Последняя функция преобразования ск – scale - масштабирование. Эта функция получает два параметра x,y, которые будут играть роль коэффициентов масштабирования. Очевидно, что если вы рисуете что-то достаточно сложное, то вы будете многократно вызывать фукцнии изменения свойств СК: вы будете менять параметры, а затем возвращаться в некоторое исходное состояние. Чтобы не запутаться какие свойства у вас сейчас установлены (на самом деле вы можете изменять гораздо большее количество параметров управляющих особенностями рисования, чем я перечислил выше). Так вот, чтобы не забыть какие свойства установлены для canvas, вы можете применять две парные функции: save и restore. Эти функции не получают ни каких параметров. Функция save сохраняет текущее состояние canvas – все его свойства. А функция restore – наоборот, восстанавливает эти параметры. Работа функций сохранить/восстановить построена по принципу стека. Вы можете вызывать фукнцию save любое количество раз и все состояния будут сохраняться укладываясь в некую виртуальную стопку. Каждый же вызов restore будет брать с вершины этой стопки сохраненный набор параметров. Соответственно, вы не можете вызывать restore большее количество раз, чем было положено туда состояний с помощью save.
Теперь давайте сделаем парочку примеров на каждую из этих функций. Начнем с перемещения центра СК. Для пример нарисуем шахматную доску состоящую из множества черных квадратиков на белом фоне. Каждый квадрат будет рисоваться размером в 10px, и иметь координаты 0,0. естественно, чтобы квадратики не накладывались друг на друга я вынужден перед рисованием каждого из них передвигать центр СК.
<html>
<head>
<!-именно здесь будут размещаться функции, которые рисуют на canvas-->
<script language="javascript">
function draw (){
var canvas = document.getElementById('canva');
if (!canvas.getContext) return;
var ctx = canvas.getContext('2d');
// заливаем доску белым цветом
ctx.fillStyle = "rgb(255,255,255)";
ctx.fillRect (0, 0, 400, 400);
for (var i = 0; i < 8; i++)
for (var j = 0; j < 8; j++){
if ( (i +j ) % 2 == 0) continue;
ctx.save ();// сохраняем контекст рисования
ctx.translate (i*50 , j*50);// смещаем центр СК
ctx.fillStyle = "rgb(0,0,0)";
ctx.fillRect (0, 0, 50, 50);
ctx.restore ();// восстанавливаем свойства контекста рисования
}
}
</script>
</head>
<body>
<canvas id="canva" width="400" height="400" style="border: 1px solid black;">
<img src="no_canvas_sorry.jpg" />
</canvas>
<br />
<button onclick="draw()">draw!</button><!-эта кнопка вызывает некоторую функцию рисования -->
</body>
</html>
Для задачи демонстрации преобразования вращения и масштабирования я решил выбрать единый пример – спиральный квадрат. Это изображение множества вложенных друг в друга квадратов, каждый из которых на очередном шаге вложенности уменьшается в размере и вращается вокруг своей оси не некоторый угол. Основу формул я взял с сайта http://fractalworld.xaoc.ru/article/kineskop.html. И код у меня (благодаря преобразованиям) получился более компактным. Вкратце идея в том, что до начала цикла я смещаю центр координат в точку (200,200) – геометрический центр области canvas. Затем в цикле я рисую прямоугольник из точки (-200,-200) и размером (400,400). Эффект вращения и ухода в даль достигается за счет того что предварительно я вращаю ось на небольшой угол PI/20, а также уменьшаю коэффициент масштабирования. Результат работы показан на рис. 2.
Внимание: в случае множественных последовательных операций вращения, масштабирования и смещения эффект накапливается.
<html>
<head>
<!-именно здесь будут размещаться функции, которые рисуют на canvas-->
<script>
function draw (){
var canvas = document.getElementById('canva');
if (!canvas.getContext) return;
var ctx = canvas.getContext('2d');
// заливаем доску белым цветом
ctx.fillStyle = "rgb(255,255,255)";
ctx.fillRect (0, 0, 400, 400);
var DELTA_ANGLE = Math.PI / 20;
ctx.translate (200,200);
for (var i = 1; i < 21; i++){
ctx.rotate (DELTA_ANGLE);
var coeff = Math.sin(Math.PI/4) / Math.sin(3*Math.PI/4 - DELTA_ANGLE);
ctx.scale (coeff,coeff);
ctx.strokeRect(-200,-200, 400,400);
}
}
</script>
</head>
<body>
<canvas id="canva" width="400" height="400" style="border: 1px solid black;">
<img src="no_canvas_sorry.jpg" />
</canvas>
<br />
<button onclick="draw()">draw!</button><!-эта кнопка вызывает некоторую функцию рисования -->
</body>
</html>
drawImage(image, x, y)
Возможно при отрисовке изображения выполнить ее масштабирование – в этом случае используйте функцию
drawImage(image, x, y, width, height)
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
Независимо от того какую версию функции вы используете, ссылка на изображение может быть взята как одна из множества картинок уже внедренных и (и это главное) загруженных на странице. Либо, как вариант, вы можете выполнить динамическую загрузку изображения – в этом случае вам необходимо будет создать некоторый код, который отслеживал бы прогресс загрузки картинки и только после того как все данные будут готовы, запускал процесс отрисовки. В первом примере я показываю как картинка с лисой рисуется в трех вариантах: оригинальном, масштабированном и вырезанном фрагменте.
Пример кода:
<html>
<head>
<!-именно здесь будут размещаться функции, которые рисуют на canvas-->
<script>
function draw (){
var canvas = document.getElementById('canva');
if (!canvas.getContext) return;
var ctx = canvas.getContext('2d');
// заливаем доску белым цветом
ctx.fillStyle = "rgb(255,255,255)";
ctx.fillRect (0, 0, 400, 400);
var img_fox = document.getElementById ('img_fox');
//получаем ссылку на изображение
if (! img_fox){
// выполняем проверку того, что изображение действительно было найдено
alert ('изображение не найдено');
return;
}
// рисуем изображение в его естественном масштабе
ctx.drawImage (img_fox , 0, 0);
// а теперь рисуем изображение немного в стороне и в уменьшенном размере
ctx.drawImage (img_fox , 100, 250, 100, 75);
// последний прием, когда я вырезаю из изображения некоторый фрагмент
ctx.drawImage (img_fox , 100, 0, 80, 100, 250,50, 80, 100);
}
</script>
</head>
<body>
<canvas id="canva" width="400" height="400" style="border: 1px solid black;">
<img src="no_canvas_sorry.jpg" />
</canvas>
<br />
<button onclick="draw()">draw!</button><!-эта кнопка вызывает некоторую функцию рисования -->
<img src="foxes_008.jpg" id="img_fox" />
</body>
</html>
<html>
<head>
<!-именно здесь будут размещаться функции, которые рисуют на canvas-->
<script>
function draw (){
var canvas = document.getElementById('canva');
if (!canvas.getContext) return;
var ctx = canvas.getContext('2d');
// заливаем доску белым цветом
ctx.fillStyle = "rgb(255,255,255)";
ctx.fillRect (0, 0, 400, 400);
var img_fox = new Image ();
// привязываем обработчик события - загрузка картинки завершена
img_fox.onload = function () {
// рисуем изображение в его естественном масштабе
ctx.drawImage (this , 0, 0);
// а теперь рисуем изображение немного в стороне и в уменьшенном размере
ctx.drawImage (this , 100, 250, 100, 75);
// последний прием, когда я вырезаю из изображения некоторый фрагмент
ctx.drawImage (this , 100, 0, 80, 100, 250,50, 80, 100);
};
img_fox.src = 'foxes_008.jpg';
}
</script>
</head>
<body>
<canvas id="canva" width="400" height="400" style="border: 1px solid black;">
<img src="no_canvas_sorry.jpg" />
</canvas>
<br />
<button onclick="draw()">draw!</button><!-эта кнопка вызывает некоторую функцию рисования -->
</body>
</html>
Следующая наша подтема - комбинирование изображений. Идея в том, что когда вы рисуете на canvas некоторое изображение, возникает вопрос как оно должно взаимодействовать с тем изображением, что уже есть. У объекта canvas есть специальное свойство: globalCompositeOperation . Ему можно присваивать набор предопределенных значений. Следующую таблицу я аккуратно позаимствовал на сайте http://developer.mozilla.org/en/docs/Canvas_tutorial. Я решил, что не стоит коверкать эту прекрасную таблицу своими заумствованиями и просто перевел текст. В общем, смотрите ниже:
Таблица-справочник возможных значений переменной globalCompositeOperation с примерами.
« Защита shareware приложений от взлома с помощью armadillo. Часть 1 | Защита shareware приложений от взлома с помощью armadillo. Часть 2 » |