Эффект
фотозатвор портфолио с JQuery и Canvas
В сегодняшнем уроке мы будем использовать холст элемент
HTML5 для создания простого портфолио,
отображающий набор избранных фотографий с эффектом затвора камеры. Эта
функциональность придается за счет простого в использовании JQuery плагина,
который вы можете легко включить в любой свой сайт.
ДЕМО СКАЧАТЬ
Идея
Элемент холст это особая область, на которой можно рисовать
с JavaScript и применять всякие манипуляции в вашем образе. Тем не менее, существуют ограничения
на то, что может быть сделано с ним. Создание сложных в режиме реального
времени анимации является сложной задачей, так как вы должны перерисовать холст
на каждом кадре.
Это требует много вычислительной мощности, что веб-браузеры
просто не смогут обеспечить себе, и в
результате плавная анимация практически невозможна. Но есть способ обойти
это ограничение. После первоначальной загрузки страницы (когда кадры
генерируются), работа плагина заключается просто в пролистывании кадров.
Влияние выдержки
Сам затвор состоит из слегка изогнутых треугольных изображений. С каждого кадра,
отверстие становится меньше, пока они не сомкнуться.
HTML
Поскольку мы используем элемент холст, нам необходимо
определить документ как HTML5 с соответствующим типом документа.
index.html
<!DOCTYPE html>
<!-- Defining the document as HTML5 -->
<html>
<head>
<meta
http-equiv="Content-Type" content="text/html;
charset=utf-8" />
<title>"Shutter
Effect" with Canvas and jQuery | Tutorialzine Demo</title>
<link
rel="stylesheet" type="text/css"
href="assets/css/styles.css" />
<link
rel="stylesheet" type="text/css" href="assets/jquery.shutter/jquery.shutter.css"
/>
</head>
<body>
<div
id="top"></div>
<div
id="page">
<h1>Shutter Folio
Photography</h1>
<div id="container">
<ul>
<li><img
src="assets/img/photos/1.jpg" width="640"
height="400" /></li>
<li><img
src="assets/img/photos/2.jpg" width="640"
height="400" /></li>
<li><img
src="assets/img/photos/3.jpg" width="640"
height="400" /></li>
<li><img
src="assets/img/photos/4.jpg" width="640"
height="400" /></li>
</ul>
</div>
</div>
<script
src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js"></script>
<script
src="assets/jquery.shutter/jquery.shutter.js"></script>
<script src="assets/js/script.js"></script>
</body>
</html>
Таблицы стилей для страницы и плагина включены в головной
части, и файлы сценария непосредственно перед закрывающим тегом </body>. Содержание
<DIV> это
неупорядоченный список с четырьмя фотографиями, которые будут отображаться в
виде слайд-шоу. Если браузер пользователя не поддерживает элемент холст,
мы будем просто перелистывать этих изображения
без отображения эффекта затвора.
Когда плагин затвора определяется, он генерирует следующую HTML-разметку. В нашем примере, мы
вызываем его на # содержимому DIV, поэтому код ниже добавляется к нему.
HTML
<div
class="shutterAnimationHolder" style="width: 640px; height:
400px;">
<div class="film"
style="height: 15000px; width: 1000px;
margin-left: -500px; top: -300px;">
<canvas width="1000"
height="1000"></canvas>
<canvas width="1000"
height="1000"></canvas>
<canvas width="1000"
height="1000"></canvas>
<canvas width="1000" height="1000"></canvas>
<canvas width="1000"
height="1000"></canvas>
<canvas width="1000"
height="1000"></canvas>
<canvas width="1000"
height="1000"></canvas>
<canvas width="1000"
height="1000"></canvas>
<canvas width="1000"
height="1000"></canvas>
<canvas width="1000"
height="1000"></canvas>
<canvas width="1000"
height="1000"></canvas>
<canvas width="1000"
height="1000"></canvas>
<canvas width="1000"
height="1000"></canvas>
<canvas width="1000"
height="1000"></canvas>
<canvas width="1000"
height="1000"></canvas>
</div>
</div>
Каждый элемент холст имеет один кадр анимации затвора. Высота # пленки DIV быть достаточно большой, чтобы отобразить
один элемент холста над другим.
. ShutterAnimationHolder DIV должен быть установлен той же высоты, контейнера, в
котором она вставлена, и отображаться на неупорядоченном списке с фотографиями.
CSS
CSS, полномочия достаточно просты, так как большая часть
работы выполняется путем создания изображений холста. Тем не менее, они должны быть организованы в виде пленки и
анимированного образа, чтобы достичь гладкой анимации.
jquery.shutter.css
.shutterAnimationHolder
.film canvas{
display: block;
margin: 0 auto;
}
.shutterAnimationHolder
.film{
position:absolute;
left:50%;
top:0;
}
.shutterAnimationHolder{
position:absolute;
overflow:hidden;
top:0;
left:0;
z-index:1000;
}
Это три набора правил с префиксом shutterAnimationHolder класса, поэтому стили влияют
только на разметку, сгенерированной с помощью плагина. Вы можете
скопировать этот код на ваш основной стиль, для того, чтобы свести к минимуму
число запросов.
JQuery
Это наиболее интересная часть урока. Здесь мы создадим
плагин JQuery - tzShutter -
который прост в использовании и требует минимального изменения в веб-сайте
для того, чтобы его использовать.
Одним из важных аспектов развития этого плагина, является
обеспечение надлежащей поддержки для пользователей, чьи браузеры не понимают
холст тег (в основном все версии IE за исключением 9 и выше). Это можно легко сделать,
пропустив поколение холст в этом случае.
Также мы должны обеспечить способ для пользователей tzShutter, вызвать открытия и закрытия анимации. Мы
добьемся этого привязкой двух
пользовательских событий в содержании элемента -shutterOpen и shutterClose .
Кроме того, плагин будет предоставлять пользователям способ
подключения пользовательских функций с помощью функции обратного вызова, в
качестве параметров. Они выполняются в ключевых частях процесса анимации - когда элементы холст
генерируются, и когда затвор открыт или закрыт.
Ниже код плагина:
jquery.shutter.js
(function(){
// Creating a regular jQuery plugin:
$.fn.tzShutter = function(options){
// Checking for canvas support. Works
in all modern browsers:
var supportsCanvas = 'getContext' in document.createElement('canvas');
// Providing default values:
options = $.extend({
openCallback:function(){},
closeCallback:function(){},
loadCompleteCallback:function(){},
hideWhenOpened:true,
imgSrc:
'jquery.shutter/shutter.png'
},options);
var element = this;
if(!supportsCanvas){
// If there is no support for canvas,
bind the
// callack functions straight away
and exit:
element.bind('shutterOpen',options.openCallback)
.bind('shutterClose',options.closeCallback);
options.loadCompleteCallback();
return element;
}
window.setTimeout(function(){
var frames = {num:15, height:1000,
width:1000},
slices = {num:8, width: 416,
height:500, startDeg:30},
animation = {
width : element.width(),
height : element.height(),
offsetTop:
(frames.height-element.height())/2
},
// This will calculate the
rotate difference between the
// slices of the shutter.
(2*Math.PI equals 360 degrees in radians):
rotateStep =
2*Math.PI/slices.num,
rotateDeg = 30;
// Calculating the offset
slices.angleStep = ((90 -
slices.startDeg)/frames.num)*Math.PI/180;
// The shutter slice image:
var img = new Image();
// Defining the callback before
setting the source of the image:
img.onload = function(){
window.console &&
console.time && console.time("Generating Frames");
// The film div holds 15 canvas
elements (or frames).
var film = $('<div>',{
className: 'film',
css:{
height:
frames.num*frames.height,
width: frames.width,
marginLeft:
-frames.width/2, // Centering horizontally
top:
-animation.offsetTop
}
});
// The animation holder hides
the film with overflow:hidden,
// exposing only one frame at a
time.
var animationHolder =
$('<div>',{
className:
'shutterAnimationHolder',
css:{
width:animation.width,
height:animation.height
}
});
for(var
z=0;z<frames.num;z++){
// Creating 15 canvas
elements.
var canvas = document.createElement('canvas'),
c =
canvas.getContext("2d");
canvas.width=frames.width;
canvas.height=frames.height;
c.translate(frames.width/2,frames.height/2);
for(var i=0;i<slices.num;i++){
// For each canvas,
generate the different
// states of the
shutter by drawing the shutter
// slices with a
different rotation difference.
// Rotating the canvas
with the step, so we can
// paint the different
slices of the shutter.
c.rotate(-rotateStep);
// Saving the current
rotation settings, so we can easily revert
// back to them after
applying an additional rotation to the slice.
c.save();
// Moving the origin
point (around which we are rotating
// the canvas) to the
bottom-center of the shutter slice.
c.translate(0,frames.height/2);
// This rotation
determines how widely the shutter is opened.
c.rotate((frames.num-1-z)*slices.angleStep);
// An additional
offset, applied to the last five frames,
// so we get a smoother
animation:
var offset = 0;
if((frames.num-1-z)
<5){
offset =
(frames.num-1-z)*5;
}
// Drawing the shutter
image
c.drawImage(img,-slices.width/2,-(frames.height/2 + offset));
// Reverting back to
the saved settings above.
c.restore();
}
// Adding the canvas (or
frame) to the film div.
film.append(canvas);
}
// Appending the film to the
animation holder.
animationHolder.append(film);
if(options.hideWhenOpened){
animationHolder.hide();
}
element.css('position','relative').append(animationHolder);
var animating = false;
// Binding custom open and
close events, which trigger
// the shutter animations.
element.bind('shutterClose',function(){
if(animating) return false;
animating = true;
var count = 0;
var close = function(){
(function animate(){
if(count>=frames.num){
animating=false;
// Calling the
user provided callback.
options.closeCallback.call(element);
return false;
}
film.css('top',-frames.height*count - animation.offsetTop);
count++;
setTimeout(animate,20);
})();
}
if(options.hideWhenOpened){
animationHolder.fadeIn(60,close);
}
else close();
});
element.bind('shutterOpen',function(){
if(animating) return false;
animating = true;
var count = frames.num-1;
(function animate(){
if(count<0){
var hide =
function(){
animating=false;
// Calling the
user supplied callback:
options.openCallback.call(element);
};
if(options.hideWhenOpened){
animationHolder.fadeOut(60,hide);
}
else{
hide();
}
return false;
}
film.css('top',-frames.height*count - animation.offsetTop);
count--;
setTimeout(animate,20);
})();
});
// Writing the timing
information if the
// firebug/web development
console is opened:
window.console &&
console.timeEnd && console.timeEnd("Generating Frames");
options.loadCompleteCallback();
};
img.src = options.imgSrc;
},0);
return element;
};
})(jQuery);
Единственный недостаток этого метода, это то, что загружает процессор задача создания
элементов холст, когда он в загрузке страницы. Браузер может, перестанет
отвечать на запросы в течение короткого периода времени. В качестве
альтернативы вы можете использовать фактические изображения PNG вместо этого,
но это добавит более 1mb веса на страницы (по сравнению с 12 кб сейчас).
Теперь давайте посмотрим, как используется плагин.
script.js
$(document).ready(function(){
var container = $('#container'),
li = container.find('li');
// Using the tzShutter plugin. We are
giving the path
// to he shutter.png image (located in the
plugin folder), and two
// callback functions.
container.tzShutter({
imgSrc:
'assets/jquery.shutter/shutter.png',
closeCallback: function(){
// Cycling the visibility of the li
items to
// create a simple slideshow.
li.filter(':visible:first').hide();
if(li.filter(':visible').length ==
0){
li.show();
}
// Scheduling a shutter open in 0.1
seconds:
setTimeout(function(){container.trigger('shutterOpen')},100);
},
loadCompleteCallback:function(){
setInterval(function(){
container.trigger('shutterClose');
},4000);
container.trigger('shutterClose');
}
});
});
Когда плагин заканчивает генерацию элементов
холст, он запускает функцию loadCompleteCallback. Мы используем ее, чтобы запланировать анимацию затвора
каждые четыре секунды, в сопровождении с изменением видимого фото.
Вывод
Тег холст дает разработчикам широкий спектр возможностей и
позволяет им создавать новые и интересные пользовательские интерфейсы, анимации
и даже игр. Поделитесь своими мыслями в комментариях ниже.
ДЕМО СКАЧАТЬ
Источник
|