Стильный jQuery прелоадер на SVG

Многие пользователи пренебрегают сайтами с медленной загрузкой. Мы расскажем как использовать SVG библиотеку Raphaël для создания красивого прелоадера, который будет удерживать внимание пользователей во время загрузки страниц.

Сложность

svg прелоадер

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

Прелоадер jQuery основан на Gaya Design's QueryLoader, использует библиотеку Raphaël для создания красивых, векторных фигур. В нашем уроке мы используем большие изображения от сервиса Flickr, чтобы показать предварительную загрузку в действии.

Вопрос скорости

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

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

Приступим к работе

<pМы будем создавать прелоадер с использованием SVG библиотеки - Raphaël. Будем использовать библиотеки QueryLoader от GayaDesign. Данный скрипт будет создавать полосу загрузки, так что первым делом необходимо удалить стили, которые поставляются в комплекте с QueryLoader.

1. Папки

В главной директории проекта находятся папки под названиями CSS и JS, а так же файл demo.html. Папка CSS - пустая, но в скором времени будет содержать файл style.css. Папка js содержит библиотеки JQuery и Raphaël; Это резервные библиотеки, они используется только для того, если не будет ответа от CDN.

папки проекта

2. Новый проект

Откройте файл demo.html. В теле документа у нас есть два элемента <section>: один с изображениями для jQuery прелоадера, в другом находится сам прелоадер. Изображения будут невидимыми, пока полностью не закончится их загрузка.

Прелоадер состоит из двух элементов, первый это - загрузчик, второй элемент это круг, который будет находится над загрузчиком. В конец документа добавим 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>

3. CSS

на данном этапе, мы добавим некоторые основные стили для нашего прелоадера.

#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;
}

4. Прелоадер

Теперь, что бы оживить нашу страницу, будем использовать 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() {

5. Параметры высоты

Для инициализации, в JQuery добавим функцию resize для регулировки высоты страницы, чтобы наш прелоадер jQuery отображался одинаково, при любом размере окна браузера. Иначе, при изменении размера окна, прелоадер может потеряться из виду.

...
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+)+(?:b\d*)?)/) == "MSIE 6.0,6.0") {
               
                return false;
        }
       
        if(QueryLoad.selectorPreload == 'body') {
                QueryLoader.spawnLoader();
                QueryLoader.getImages(QueryLoader.selectorPreload);
                QueryLoader.createPreloading();
        } else {
                $(document.ready(function) {
                        QueryLoader.spawnLoader();
...

6. Оптимизация

далее необходимо отредактировать плагин QueryLoader. Уберем часть кода, который находится на строке 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%"
        });
        // <<< Конец
},

7. Дополнительные эффекты

Адаптируем функцию doneLoad, для показа блока #gallery. Зададим значение block, для атрибута display . Также используем JQuery для анимации прозрачности элемента#loading и в конце сделаем элемент #loading - невидимым, прежде чем удалить его из DOM.

doneLoad: function() {
               
                clearTimeout(QueryLoader.ieTimeout);
                               
                //определение высоты
                if (QueryLoader.selectorPreload == "body") {
                        var height = $(window).height();
                } else {
                        var height = $(QueryLoader.selectorPreload).outerHeight();
                }
               
                // Шаг 7 добавить данный код
                $('#gallery').show();
                $('#loading').animate({'opacity': 0}, 1200, function() {
                        $(this).remove();
                })

8. Больше оптимизации

Удаляем код из оригинальной полосы загрузки, который мы показывали в 7 шаге. В окончательном варианте, анимация будет исчезать сама, в 7 шаге мы рассказали что в нашей галерее появляется и исчезает загрузчик. Адаптируем эту функцию в конце урока.

doneLoad: function() {
                Начало удаления...
                $('#gallery').show();
                $('#loading').animate({'opacity': 0}, 1200, function() {
                        $(this).remove();
                })
 
               
               
                // <<< Шаг 8 удалить данный код
                $(QueryLoader.loadBar).animate({
                        height: height + "px",
                        top: 0
                }, 500, "linear", function() {
                        $(QueryLoader.overlay).fadeOut(800);
                        $(QueryLoader.preloader).remove();
                });
                // <<< Конец
        }

9. Прогресс бар

Создадим вызов функции 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();
},

10. Больше функциональности

Добавляем функцию updateVal только для imgCallback. Если параметр initialise со значением true, то можно загружать круг, для продолжения анимации. Кроме того, если круг завершен, мы должны расширить его, потому что мы не можем использовать больше чем 360 градусов дуги.

updateVal: function(value, total, R, hand, id) {
    if (QueryLoader.initialise) {
                if(value == total) {
                        this.raph.clear();
                        // 2.1.1 - Завершение круга.
                        this.fakeCircle = this.raph.circle(110,110,105).attr({colour: '', "stroke-width": 10});
                } else {
                hand.animate({arc: [value, total, R]}, 0, ">");
            }
    }
},

11. Удаление HTML

Удаляем HTML код в оригинальном QueryLoader.

createPreloading: function() {
        QueryLoader.preloader = $("<div></div>").appendTo(QueryLoader.selectorPreload);
        $(QueryLoader.preloader).css({
                height:         "0px",
                width:          "0px",
                overflow:       "hidden"
        });

12. Вставляем Raphaël

Создадим два SVG элемента, также установим дополнительные переменные и атрибуты для 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},
 
        // Пользовательский атрибут
        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]]; // путь матрицы
            return {path: path, stroke: color};
        };
...

13. Пользовательские атрибуты

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

// Пользовательский атрибут
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};
};

14. Атрибуты цвета

Использование функции updateVal является ключом к созданию эффекта полного круга после того, как изображения будут загружены. Цвет вы можете изменить или поменять изображения, но при настройке убедитесь, что вы меняете все значения – одинаково, иначе в конечном итоге вы получите круги с разными цветами!

this.raph.customAttributes.colour = function() {
        return {stroke: 'rgb(29,79,107)'};
};

15. Секторы

Теперь определим сектор, но перед этим настроим путь и его дуги. При вызове 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);

16. Анимация

После каждого загруженного изображения, происходит вызов функции 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() { ...

17. Настройка

Теперь постепенно меняем прозрачность каждого круга до полного исчезновения и удаления с предварительной загрузки элементов в целом. На данный момент мы имеем готовый jQuery прелоадер, который будет работать в браузерах от 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();                              
        });
});
...

18. Сокращение элементов

Используя CSS transform, есть возможность масштабировать или "сжимать" элементы.

..
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();
});
});
 
}
...

19. Взлет

Добавление keyframe анимации и их определение означает, что мы можем также применить CSS transforms через 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); }
}
...

Перевод статьи Make a stylish preloader with SVG

Тэги: animatetransformpreloaderSVG

Вход

Уважаемый пользователь! Мы обнаружили, что вы используете AdBlock и вынуждены скрыть часть материалов на нашем сайте. Siteacademy существует и развивается за счет доходов от рекламы. Просим внести наш сайт в список исключений или отключить Блокировщик рекламы на нашем сайте.