Урок - Пример 2

Главная » Курсы » Курс HTML5 Canvas » Урок - Пример 2

Обучающий онлайн курс
HTML5 Canvas

Лицензия: Копирование запрещено.

Слайдшоу с использованием элемента HTML5 canvas

Источник: http://ruseller.com/lessons.php?rub=32&id=770
Вероятно, что вы уже слышали о новом элементе HTML5 canvas. Это специальный элемент, который позволяет создавать и модифицировать графику. К тому же, мы можем использовать его как любой другой элемент на странице – применять анимации jQuery для него, обрабатывать события для него и интегрировать его в шаблон.

Обычно использование элемента canvas ограничивается играми и концептуальными демонстрациями. В данном уроке мы будем использовать его практично - сделаем слайдшоу с отличным эффектом перехода, которое будет работать и в старых браузерах.

Идея

С помощью JavaScript сделаем специальный фильтр для каждого изображения в слайдшоу. Мы будем создавать новую версию изображения с более высоким контрастом и более яркими цветам, и сохранять ее в элементе canvas.

схема
Когда пользователь хочет перейти к следующему слайду, элемент canvas выводится на экран с помощью анимации fadeIn, создавая плавный эффект перехода.

HTML

Начнем с создания разметки HTML.

html5-slideshow.html

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Слайд шоу на основе элемента HTML5 сanvas и jQuery | Демонстрация для сайта RUSELLER.COM</title>

<link rel="stylesheet" type="text/css" href="styles.css" />
</head>
<body>

<div id="slideshow">
<ul class="slides">
<li><img src="img/photos/1.jpg" width="620" height="320" alt="Броненосец Русского флота" /></li>
<li><img src="img/photos/2.jpg" width="620" height="320" alt="Русская атомная подводная лодка" /></li>
<li><img src="img/photos/3.jpg" width="620" height="320" alt="Высадка русского десанта" /></li>
<li><img src="img/photos/4.jpg" width="620" height="320" alt="Русский флот в дальнем походе" /></li>
</ul>

<span class="arrow previous"></span>
<span class="arrow next"></span>
</div>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script src="script.js"></script>
</body>
</html>

Разметка для слайдшоу очень проста. Основной элемент div  #slideshow содержит неупорядоченный список и стрелки на следующий и предыдущий слайды. Неупорядоченный список содержит слайды, которые определены как элементы li. На иллюстрации выше показано, что элемент canvas с модифицированным изображением будет вставляться сюда.

В конце включаются jQuery и наш файл script.js, который будет разбираться позже в данном уроке.

CSS

Все стили для слайдшоу содержатся в файле styles.css. Мы используем id основного элемента #slideshow в качестве определения пространства имен, поэтому можно просто добавить данные стили к вашему проекту без риска конфликта имен.

styles.css

#slideshow{
background-color:#F5F5F5;
border:1px solid #FFFFFF;
height:340px;
margin:150px auto 0;
position:relative;
width:640px;

-moz-box-shadow:0 0 22px #111;
-webkit-box-shadow:0 0 22px #111;
box-shadow:0 0 22px #111;
}

#slideshow ul{
height:320px;
left:10px;
list-style:none outside none;
overflow:hidden;
position:absolute;
top:10px;
width:620px;
}

#slideshow li{
position:absolute;
display:none;
z-index:10;
}

#slideshow li:first-child{
display:block;
z-index:1000;
}

#slideshow .slideActive{
z-index:1000;
}

#slideshow canvas{
display:none;
position:absolute;
z-index:100;
}

#slideshow .arrow{
height:86px;
width:60px;
position:absolute;
background:url('img/arrows.png') no-repeat;
top:50%;
margin-top:-43px;
cursor:pointer;
z-index:5000;
}

#slideshow .previous{ background-position:left top;left:0;}
#slideshow .previous:hover{ background-position:left bottom;}
#slideshow .next{ background-position:right top;right:0;}
#slideshow .next:hover{ background-position:right bottom;}


Мы можем разделить наших посетителей, которые будут взаимодействовать со слайдшоу, на три группы:

Те, у кого отключен JavaScript. Такие пользователи будут видеть только первый слайд, у них не будет возможности переключиться на другие слайды.
Те, у кого включен JavaScript, но отсутствует поддержка элемента canvas. Для таких посетителей слайды будут переключаться мгновенно без эффекта перехода.
Те, у кого включена поддержка JavaScript и поддерживается элемент canvas.Эта группа использует последние версии Firefox, Safari, Chrome, Opera. Они будут видеть слайдшоу во всей красе.
Правила разработаны с учетом первых двух групп. С помощью селектора first-child будет выводиться только первый слайд по умолчанию.
1-й слайд

JavaScript

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

script.js – Часть 1

$(window).load(function(){

// Мы используем событие window.load, поэтому уверены, что
// изображения слайдшоу загружены без ошибок.

// Проверяем, поддерживает ли текущий браузер элемент canvas:
var supportCanvas = 'getContext' in document.createElement('canvas');

// Манипуляции с элементом canvas создают интенсивную нагрузку на процессор,
// поэтому мы используем setTimeout, чтобы сделать работу асинхронной и улучшить
// время отклика страницы

var slides = $('#slideshow li'),
current = 0,
slideshow = {width:0,height:0};

setTimeout(function(){

window.console && window.console.time && console.time('Сгенерировано за:');

if(supportCanvas){
$('#slideshow img').each(function(){

if(!slideshow.width){
// Получаем размеры первого изображения:
slideshow.width = this.width;
slideshow.height = this.height;
}

// Выводим модифицированную версию изображения
createCanvasOverlay(this);
});
}

window.console && window.console.timeEnd && console.timeEnd('Сгенерировано за:');

$('#slideshow .arrow').click(function(){

var li = slides.eq(current),
canvas = li.find('canvas'),
nextIndex = 0;

// В зависимости от того, какая стрелка была нажата,
// вычисляем индекс следующего слайда

if($(this).hasClass('next')){
nextIndex = current >= slides.length-1 ? 0 : current+1;
}
else {
nextIndex = current <= 0 ? slides.length-1 : current-1;
}
for
var next = slides.eq(nextIndex);

if(supportCanvas){

// Данный браузер поддерживает элемент canvas, выводим его:

canvas.fadeIn(function(){

// Выводим следующий слайд ниже текущего:
next.show();
current = nextIndex;

// Выключаем текущий слайд:
li.fadeOut(function(){
li.removeClass('slideActive');
canvas.hide();
next.addClass('slideActive');
});
});
}
else {

// Данный браузер не поддерживает элемент canvas.
// Используем упрощенную версию слайдшоу.

current=nextIndex;
next.addClass('slideActive').show();
li.removeClass('slideActive').hide();
}
});

},100);

С помощью document.createElement() вы можете создать любой элемент DOM , который нужен. Поэтому, для определения поддержки браузером элемента canvas (в противном случае просто не будет создан такой элемент), мы используем оператор in для проверки наличия метода getContext(), который является частью стандарта. Результат выполнения данного кода используется для определения пользователей, у которых нет поддержки элемента canvas.

Отметим вызов функции createCanvasOverlay (которая будет рассматриваться в следующей части) завершает setTimeout. Данная функция интенсивно нагружает процессор и может привести к остановке функционирования окна браузера. setTimeout. прерывает выполнение основной функции и выполняет код в асинхронном режиме, максимизируя скорость реакции страницы на действия пользователя.

script.js – Часть 2

// Данная функция получает изображение и перерисовывает его
// версию, как режим Overlay в Фотошоп

function createCanvasOverlay(image){

var canvas = document.createElement('canvas'),
canvasContext = canvas.getContext("2d");

// Делаем элемент canvas таким же, как и изображение
canvas.width = slideshow.width;
canvas.height = slideshow.height;

// Рисуем текущую версию изображения в элементе canvas:
canvasContext.drawImage(image,0,0);

// Получаем данные изображения и сохраняем их в массиве imageData:
var imageData = canvasContext.getImageData(0,0,canvas.width,canvas.height),
data = imageData.data;

// проходим циклом по всем пикселям в массиве imageData и модифицируем
// значения для красного, синего и зеленого цветов.

for(var i = 0,z=data.length;i<z;i++){

// Значения цветов красного, синего и зеленого располагаются последовательно
// в массиве imageData. Мы модифицируем все три сразу:

data[i] = ((data[i] < 128) ? (2*data[i]*data[i] / 255) : (255 - 2 * (255 - data[i]) * (255 - data[i]) / 255));
data[++i] = ((data[i] < 128) ? (2*data[i]*data[i] / 255) : (255 - 2 * (255 - data[i]) * (255 - data[i]) / 255));
data[++i] = ((data[i] < 128) ? (2*data[i]*data[i] / 255) : (255 - 2 * (255 - data[i]) * (255 - data[i]) / 255));

// Затем следует элемент RGB для значения alpha, но мы его оставляем без изменений.
++i;
}

// Выводим модифицированный массив imageData в элемент canvas.
canvasContext.putImageData(imageData,0,0);

// Вставляем элемент canvas в DOM перед изображением:
image.parentNode.insertBefore(canvas,image);

}

});


Здесь выполняются все магические действия. Элемент canvas по своей сути является большим куском бумаги, на котором можно рисовать с помощью JavaScript. Выше приведенный код создает пустой элемент canvas и импортирует изображение, которое передается как параметр, методу drawImage().Затем мы используем метод getImageData()для экспорта содержимого всех пикселей массиву imageData.

Для каждого пикселя мы имеем четыре значения в массиве – для цветов красного, зеленого и синего, и для альфа канала (прозрачность). Все эти величины лежат в диапазоне от 0 до 255. Основной цикл for проходит по всем пикселям и применяет специальное выражение фильтра, которое осветляет светлые цвета и затемняет темные. Похожий эффект можно получить в программе Фотошоп.

Основной цикл  for выполняет огромный объем работы – для 600x400 пикселей изображения нужно сделать 240 000 итераций! Это означает, что код должен быть оптимальным на столько, насколько это возможно. Поэтому формула копируется три раза, вместо троекратного вызова функции. Удаление лишних вызовов функции в цикле увеличивает быстродействие примерно в три раза.

Будьте внимательны. Время обработки будет увеличиваться пропорционально объему изображений или их количеству.

Внимание! Код демонстрации надо загрузить на сервер. На локальном компьютере он работать не будет.