- PVSM.RU - https://www.pvsm.ru -
Многие пользователи пренебрегают сайтами с медленной загрузкой. Ian Culshaw объясняет, как использовать SVG Raphaël библиотеку что бы создать прелоадер, который будет удерживать внимание пользователей во время загрузки страниц.

ДЕМО [1]
Исходные файлы [2]
В этом уроке я покажу вам, как удержать пользователя достаточно долго, пока загружаются изображения и сама страница.
Прелоадер основан на Gaya Design's QueryLoader и использует Raphaël библиотку для создания красивых, векторных фигур. В нашем уроке мы будем использовать большие изображения с Flickr, чтобы показать предварительную загрузку в действии.
Все сайты имеют потенциал, что бы стать одним из лучших, и этот потенциал определенно зависит от того, какой размер имеет ваш сайт.
Нам всем хоть раз доводилось ждать, пока загрузится прелоадер на каком либо сайте, но по крайней мере многие разработчики добавляют некие интерактивные показатели, для того что бы этот процесс не был столь утомительным. Если использовать только возможности HTML, то единственный интерактивный показатель это, процент загрузки в строке состояния или счетчик в адресной строке.
В этой статье мы научим вас, как привлечь внимание пользователей достаточно долго, чтобы дать вашему содержанию сайта, весь охват аудитории которого он заслуживает. Мы будем создавать прелоадер с использованием SVG библиотеки — Raphaël. Мы собираемся использовать существующие QueryLoader библиотеки из GayaDesign. Оригинальный сценарий создает полосу загрузки, которая отображается на экране, так что первым делом нам нужно удалить этот стиль, который поставляется в комплекте с QueryLoader для того что бы реализовать наши собственные стили.
В главной директории проекта находятся папки под названиями CSS и JS, и файл demo.html. Папка CSS — пустая, но в будущем будет содержать style.css. Папка js содержит JQuery и Raphaël; резервные библиотеки используется только для того если не отвечает CDN.

Откройте файл demo.html. В теле документа у нас есть два элемента section: один с нашими изображениями для прелоадера, в другом находится сам прелоадер. Изображения будут невидимы для пользователя, пока полностью не закончится их загрузка.
Прелоадер состоит из двух элементов, один из которых является наш загрузчик, другой элемент это круг, который мы разместим над загрузчиком. Нам не нужно редактировать demo.html так как весь наш код будет работать при помощи JavaScript.
<!doctype html>
<html class="no-js" lang="en">
<head>
<meta charset="utf-8">
<title></title>
<script src="//cdnjs.cloudflare.com/ajax/libs/modernizr/2.0.6/modernizr.min.js"></script>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<section id="loading">
<figure id="innerCircle" class="circle"></figure>
<div id="loader"></div>
</section>
<section id="gallery">
<img src="http://farm1.staticflickr.com/94/243962216_49afc8c9ba_o.jpg">
<img src="http://farm6.staticflickr.com/5283/5361320118_d193bf5639_b.jpg">
<img src="http://farm7.staticflickr.com/6090/6125129993_9e675f8ca0_o.jpg">
</section>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.0.1/raphael-min.js"></script>
<script>window.jQuery || document.write('<script src="js/jquery.js"></script>')</script>
<script>window.Raphael || document.write('<script src="js/raphael.js"></script>')</script><script type="text/javascript" src="js/queryloader.js"></script
<script defer type="text/javascript">
QueryLoader.init();
</script>
</body>
</html>
Здесь мы добавим некоторые основные стили для нашего прелоадера.
#loading {
position: absolute;
width: 100%;
height: 100%;
background: #fff;
}
#loading .circle {
width: 206px;
height: 206px;
position: absolute;
left: 50%;
top: 50%;
margin: -103px 0 0 -103px;
background: pink;
}
#loading #loader {
width: 220px;
height: 220px;
position: absolute;
left: 50%;
top: 50%;
margin: -110px 0 0 -110px;
background: transparent;
}
Теперь, что бы оживить нашу страницу, используем JavaScript. Откройте queryloader.js в папке js. Здесь мы добавим некоторые свойства, которые будут находиться в одном объекте в целях сокращения объема памяти.
var QueryLoader = {
overlay: "",
loadBar: "",
preloader: "",
items: new Array(),
doneStatus: 0,
doneNow: 0,
selectorPreload: "body",
logoImg: false,
logoCircle: false,
fakeCircle: false,
ieLoadFixTime: 2000,
ieTimeout: "",
initialise: true,
sec: 0,
raph: false,
init: function() {
Для инициализации, в JQuery мы добавим функцию resize для регулировки высоты страницы, чтобы наш прелоадер отображался одинаково, если пользователь изменяет размеры окна. Без этого, при изменении размера окна, прелоадер может потеряться из виду.
...
initialise: true,
sec:0,
raph: false,
init: function() {
$(window).resize(function() {
$('#loading').height($(window).height());
});
$('#loading').height($(window).height());
if (navigator.userAgent.match(/MSIE (d+(?:.d+)+(?:bd*)?)/) == "MSIE 6.0,6.0") {
// break if IE6
return false;
}
if(QueryLoad.selectorPreload == 'body') {
QueryLoader.spawnLoader();
QueryLoader.getImages(QueryLoader.selectorPreload);
QueryLoader.createPreloading();
} else {
$(document.ready(function) {
QueryLoader.spawnLoader();
...
Нам нужно отредактировать оригинальный сценарий QueryLoader. Нужно убрать код который вставляется в некоторые HTML-страницы, которые в дальнейшем мы будем использовать. Вы должны удалить этот код, он находится на строке 115 в файле queryloader.js.
spawnLoader: function() {
if (QueryLoader.selectorPreload == "body") {
var height = $(window).height();
var width = $(window).width();
var position = "fixed";
} else {
var height = $(QueryLoader.selectorPreload).outerHeight();
var width = $(QueryLoader.selectorPreload).outerWidth();
var position = "absolute";
}
var left = $(QueryLoader.selectorPreload).offset()['left'];
var top = $(QueryLoader.selectorPreload).offset()['top'];
// <<< Начало удаления
QueryLoader.overlay = $("<div></div>").appendTo($(QueryLoader.selectorPreload));
$(QueryLoader.overlay).addClass("QOverlay");
$(QueryLoader.overlay).css({
position: position,
top: top,
left: left,
width: width + "px",
height: height + "px"
});
QueryLoader.loadBar = $("<div></div>").appendTo($(QueryLoader.overlay));
$(QueryLoader.loadBar).addClass("QLoader");
$(QueryLoader.loadBar).css({
position: "relative",
top: "50%",
width: "0%"
});
// <<< Конец
},
Здесь мы адаптируем функцию doneLoad, для показа #gallery, для этого необходимо задать значение block, для атрибута display . Мы также используем JQuery для анимации прозрачности #loading, поэтому мы сделаем элемент #loading — невидимым, прежде чем удалить его с DOM.
doneLoad: function() {
//prevent IE from calling the fix
clearTimeout(QueryLoader.ieTimeout);
//determine the height of the preloader for the effect
if (QueryLoader.selectorPreload == "body") {
var height = $(window).height();
} else {
var height = $(QueryLoader.selectorPreload).outerHeight();
}
// Step 7 add this code
$('#gallery').show();
$('#loading').animate({'opacity': 0}, 1200, function() {
$(this).remove();
})
Далее мы удаляем код из оригинальной полосы загрузки, этот код мы показывали в шаге 7. В оригинале анимация будет исчезать сама, в шаге 7 мы рассказали что в нашей галерее появляется и исчезает загрузчик. Мы будем адаптировать эту функцию в конце урока.
doneLoad: function() {
...
$('#gallery').show();
$('#loading').animate({'opacity': 0}, 1200, function() {
$(this).remove();
})
// <<< Step 8 Remove this code
$(QueryLoader.loadBar).animate({
height: height + "px",
top: 0
}, 500, "linear", function() {
$(QueryLoader.overlay).fadeOut(800);
$(QueryLoader.preloader).remove();
});
// <<< End removal
}
Здесь мы используем вызов функции updateVal, которая будет обновлять наш SVG круг. QueryLoader.doneNow это количество изображений завершённых в течение загрузки страницы. 105 это радиус окружности, а this.sec путь Raphaël SVG.
imgCallback: function() {
QueryLoader.doneNow++;
QueryLoader.updateVal(QueryLoader.doneNow, this.items.length, 105, this.sec);
QueryLoader.animateLoader();
},
Здесь мы добавляем updateVal только для функции imgCallback. Если параметр initialise со значением true, то можно загружать круг, для продолжения анимации. Кроме того, если круг завершен, мы должны расширить его, потому что мы не можем использовать больше чем 360 градусов дуги.
updateVal: function(value, total, R, hand, id) {
if (QueryLoader.initialise) {
if(value == total) {
this.raph.clear();
// 2.1.1 - CIRCLE COMPLETION.
this.fakeCircle = this.raph.circle(110,110,105).attr({colour: '', "stroke-width": 10});
} else {
hand.animate({arc: [value, total, R]}, 0, ">");
}
}
},
Мы удаляем код HTML, который содержит оригинальный сценарий QueryLoader.
createPreloading: function() {
QueryLoader.preloader = $("<div></div>").appendTo(QueryLoader.selectorPreload);
$(QueryLoader.preloader).css({
height: "0px",
width: "0px",
overflow: "hidden"
});
Теперь мы создадим два SVG элемента, которые содержат в себе несколько элементов, присутствующих в нашем HTML. Мы установили некоторые переменные и атрибуты для SVG. Также #loader сделаем больше чем #innerCircle, это создаст иллюзию, что загрузчик дошел до границы.
createPreloading: function() {
var logoC = Raphael("innerCircle", 206,206);
$('#innerCircle').css('z-index', '31');
this.logoCircle = logoC.circle(103,103,103).attr({'stroke': 'rgb(125,208,163)', 'fill': 'url(wave.jpg)', "stroke-width": 0});
this.raph = Raphael("loader", 220, 220),
xy = 110,
R = 210,
this.initialise = true,
param = {stroke: "#000", "stroke-width": 10},
// Custom Attribute
this.raph.customAttributes.arc = function (value, total, R) {
var alpha = 360 / total * value,
a = (90 - alpha) * Math.PI / 180,
x = xy + R * Math.cos(a),
y = xy - R * Math.sin(a),
color = 'rgb(29,79,107)',
path;
path = [["M", xy, xy - R], ["A", R, R, 0, +(alpha > 180), 1, x, y]]; // MATRIX PATH
return {path: path, stroke: color};
};
...
Это сложный математический процесс, что в конечном итоге будет матрица, которую можно сделать в виде дуги. К счастью, только ключевые значения value, total и R (радиус); как определили ранее, это анимация updateVal. Цвет не имеет значение, его можно изменить на ваше усмотрение.
// Custom Attribute
this.raph.customAttributes.arc = function (value, total, R) {
var alpha = 360 / total * value,
a = (90 - alpha) * Math.PI / 180,
x = xy + R * Math.cos(a),
y = xy - R * Math.sin(a),
color = 'rgb(29,79,107)',
path;
if (total == value) {
path = [["M", xy, xy - R], ["A", R, R, 0, +(alpha > 180), 1, x, y]];
} else {
path = [["M", xy, xy - R], ["A", R, R, 0, +(alpha > 180), 1, x, y]];
}
return {path: path, stroke: color};
};
Использование функции updateVal является ключом к созданию эффекта полного круга после того, как изображения будут загружены. Цвет вы можете изменить или даже заменить изображение, но при настройке убедитесь, что вы измените все значения – одинаково, иначе в конечном итоге вы получите круги с разными цветами!
this.raph.customAttributes.colour = function() {
return {stroke: 'rgb(29,79,107)'};
};
После предыдущего кода мы определим сектор, но перед этим создадим путь и настроим его дуги (который будет вызывать нашу функцию дуги в шаге 13). Когда мы вызываем наш updateVal, мы устанавливаем количество загруженных изображений на 0.
var length = QueryLoader.items.length;
this.sec = this.raph.path().attr(param).attr({arc: [0, 60, R]});
QueryLoader.updateVal(0, length, 105, this.sec, 2);
После кождого загруженного изображения, вызывается animateLoader. Мы заменим большую логическую часть, поэтому я рекомендую просто переписать функцию. Функция измеряет сколько осталось не загруженных изображений и если опережаем на 99 процентов то происходит вызов doneLoad.
animateLoader: function() {
var perc = (100 / QueryLoader.doneStatus) * QueryLoader.doneNow;
var angle = (3.6 * perc);
QueryLoader.updateVal(QueryLoader.doneNow, this.items.length, 105, this.sec, 2);
if (perc > 99) {
QueryLoader.doneLoad();
}
},
doneLoad: function() { ...
Здесь мы постепенно изменим прозрачность каждого круга до полного исчезновения и удаления с предварительной загрузки элементов в целом. На данный момент мы имеем готовый прелоадер, который будет работать в браузерах IE7, однако ещё можно добавить индивидуальный эффект.
...
doneLoad: function {
...
var qLoad = this;
qLoad.sec.hide();
qLoad.logoCircle.stop().animate({opacity: 0}, 700);
qLoad.fakeCircle.stop().animate({opacity: 0}, 700, 'easeInOut');
$('#loading').css('min-height', 'auto').animate({top: ($(window).height()*-1) + 'px'}, '800', function() {
$(this).remove();
});
});
...
Используя CSS трансформации, мы можем масштабировать или «сжимать» элементы.
...
doneLoad: function() {
...
var qLoad = this;
qLoad.sec.hide();
qLoad.logoCircle.stop().animate({transform: "s0.6 0.6 103 103"}, '1000', "easeInOut");
qLoad.fakeCircle.stop().animate({transform: "s0.6 0.6 110 110"}, '1000', "easeInOut", function() {
qLoad.logoCircle.stop().animate({opacity: 0}, 700);
qLoad.fakeCircle.stop().animate({opacity: 0}, 700, 'easeInOut');
$('#loading').css('min-height', 'auto').animate({top: ($(window).height()*-1) + 'px'}, '800', function() {
$(this).remove();
});
});
}
...
Добавление ключевых кадров анимации и их определение означает, что мы можем также применить CSS трансформации через JavaScript, чтобы создать эффект взлета. Вуаля: у нас есть прекрасный прелоадер для нашей большой фотогалерии!
/* Keyframes */
@-webkit-keyframes fly-away {
0% { -webkit-transform: translate3d(0,0, 0); }
100% { -webkit-transform: translate3d(0,-900px, 0); }
}
@-moz-keyframes fly-away {
0% { -moz-transform: translate(0,0); }
100% { -moz-transform: translate(0,-900px); }
}
@-ms-keyframes fly-away {
0% { -ms-transform: translate(0,0); }
100% { -ms-transform: translate(0,-900px); }
}
...
ДЕМО [1]
Исходные файлы [2]
Автор: Lecaw
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/7814
Ссылки в тексте:
[1] ДЕМО: http://www.netmagazine.com/files/tutorials/demos/2012/05/make-a-stylish-preloader-with-svg/demo/demo.html
[2] Исходные файлы: http://lecaw.ru/cli/netmag-make-a-stylish-preloader-with-svg.zip
Нажмите здесь для печати.