Из этого туториала вы узнаете, как разработать простой загрузчик SVG для использования на мобильных веб-сайтах. Визуальные индикаторы, такие как счетчик, встроенный в это руководство, используются для обозначения фоновой активности и являются важной частью дизайна пользовательского интерфейса!
Предпосылки
В этом руководстве предполагается, что у вас уже есть базовые знания в области масштабируемой векторной графики (SVG), HTML, CSS, JavaScript и jQuery. Тем не менее, контент представлен в пошаговой манере, которая должна быть достаточно простой для отслеживания.
Как насчет Рафаэля? Мы будем использовать проект Raphaël для выполнения рисунка SVG в этом уроке. Цитировать с официального веб-сайта проекта Raphaël:
Raphaël использует Рекомендацию SVG W3C и VML в качестве основы для создания графики. Это означает, что каждый создаваемый вами графический объект также является объектом DOM, поэтому вы можете присоединить обработчики событий JavaScript или изменить их позже. Цель Raphaël — предоставить адаптер, который сделает рисование векторной графики совместимым и кросс-браузерным.
Чтобы использовать Raphaël в своем проекте, вам просто нужно выполнить следующие шаги:
- Импортируйте библиотеку на свою веб-страницу.
- Создайте объект Raphael, передавая идентификатор div, где будет нарисован ваш SVG, примерно так:
1var paper = Raphael(divID, width, height);
- Создайте нужные элементы в недавно созданном объекте Raphael, например:
1234// Creates circle at x = 50, y = 40, with radius 10var circle = paper.circle(50, 40, 10);// Sets the fill attribute of the circle to red (#f00)circle.attr(«fill», «#f00»);
Достаточно теории! Давайте начнем кодировать!
Шаг 1: Создание страницы с помощью HTML
Давайте начнем с создания нашей демонстрационной страницы в HTML. Это должно выглядеть следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
<!DOCTYPE html>
<html>
<head>
<meta charset=»utf-8″>
<meta name=»viewport» content=»width=device-width, initial-scale=1.0″>
<title>Loading Spinner Example</title>
<!— CSS —>
<link href=»spinner/spinner.css» rel=»stylesheet»>
</head>
<body>
<p>
<a id=»createSpinner» href=»»>Unleash</a> the power of the loading spinner.
</p>
<!— SPINNER —>
<div id=»spinnerFullScreen»>
<div id=»floater»>
<div id=»spinner»></div>
</div>
</div>
<!— Placed at the end of the document so the pages load faster and without blocking —>
<script src=»https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js»
type=»text/javascript»></script>
<script src=»https://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js»
type=»text/javascript»></script>
<script src=»spinner/spinner.js» type=»text/javascript»></script>
</body>
</html>
|
Наконец, но не в последнюю очередь, мы добавляем ссылку, по которой вы можете щелкнуть, чтобы «раскрутить» вращатель (т.е. запустить анимацию вращения).
<a id="createSpinner"> Раскройте </a> всю мощь загрузочного счетчика.
Шаг 2: CSS-стилизация
Теперь, когда у нас есть готовая разметка, нам нужно начать заполнение отсутствующего стиля.
С точки зрения CSS, внешний div (т. Е. Id = «spinnerFullScreen») должен быть черным и занимать весь экран поверх всех элементов, которые не принадлежат вращателю.
Два других элемента div (т.е. id = «floater» и id = «spinner») используют небольшой «хак» для правильного центрирования счетчика по центру экрана независимо от того, какой размер экрана или где установлена прокрутка. , Я не буду объяснять это в этом уроке, так как CSS относится только к «фиктивной» демонстрационной странице, а не к центральной цели этого урока.
В конце файл spinner.css должен выглядеть так:
#spinnerFullScreen { дисплей: нет; ширина: 100%; высота: 100%; положение: фиксированное; верх: 0px; слева: 0px; цвет фона: черный; непрозрачность: 0; z-индекс: 9999998; } #floater { дисплей: стол; ширина: 100%; высота: 100%; } #spinner { дисплей: таблица-ячейка; выравнивание по вертикали: среднее; выравнивание текста: по центру; Z-индекс: 9999999; }
Шаг 3: добавление поведения с помощью JavaScript
Теоретически, наш счетчик состоит из определенного числа секторов (8 на изображении), которые имеют длину («sectorLength») и ширину («sectorWidth»). Конечно, эти сектора также имеют расстояние до центра («centerRadius»).
Но разве это статично? А как насчет анимации? Что ж, анимация — это всего лишь маленькая хитрость: имея все непрозрачности секторов в диапазоне от 0,0 до 1,0, мы постоянно меняем непрозрачность каждого сектора, чтобы она равнялась непрозрачности следующего сектора. Смущенный? Скорее всего, он станет более прозрачным, когда вы увидите реализацию в JavaScript.
Чтобы создать библиотеку многократного использования, мы будем использовать объектно-ориентированную парадигму, реализованную в JavaScript. Библиотека построена на основе конструктора ( function Spinner(data)
) и двух отдельных функций:
- создать — используя переменные экземпляра, определенные в конструкторе, он создает бланк SVG и анимирует его.
- destroy — уничтожает блесну SVG и скрывает полноэкранный режим.
В ранее созданном файле spinner.js мы сначала создаем конструктор Spinner, позволяющий пользователю библиотеки устанавливать некоторые значения, такие как количество секторов, расстояние секторов до центра и т. Д.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
/**
* creates the object Spinner with data values or default values in the case they are missing
* @param data
* @constructor
*/
function Spinner(data) {
//number of sectors of the spinner — default = 12
this.sectorsCount = data.sectorsCount ||
//the distance from each sector to the center — default = 70
this.centerRadius = data.centerRadius ||
//the length/height of each sector — default = 120
this.sectorLength = data.sectorLength ||
//the width of each sector of the spinner — default = 25
this.sectorWidth = data.sectorWidth ||
//color of the spinner — default = white
this.color = data.color ||
//the opacity of the fullScreen
this.fullScreenOpacity = data.fullScreenOpacity;
//array of spinner sectors, each spinner is a svg path
this.sectors = [];
//array with the opacity of each sector
this.opacity = [];
//the raphael spinner object
this.spinnerObject = null;
//id of the timeout function for the rotating animation
this.spinnerTick = null;
}
|
Теперь перейдем к самому большому методу объекта spinner — методу create. Этот метод вызывается каждый раз, когда пользователь хочет показать счетчик. Обратите внимание на использование jQuery для выбора наших элементов. Вот куда приходят идентификаторы, о которых мы говорили выше:
1
2
3
4
5
6
7
8
9
|
Spinner.prototype.create = function() {
//shows the full screen spinner div
$(‘#spinnerFullScreen’).show();
//animates the opacity of the full screen div containing the spinner from 0 to 0.8
$(‘#spinnerFullScreen’).animate({
opacity: this.fullScreenOpacity
}, 1000, function() {
});
|
Продолжая метод create, мы делаем некоторые начальные вычисления, такие как общий размер счетчика, и подготавливаем объект Raphael для рисования сечений:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
//center point of the canvas/spinner/raphael object
var spinnerCenter = this.centerRadius + this.sectorLength + this.sectorWidth;
//angle difference/step between each sector
var beta = 2 * Math.PI / this.sectorsCount;
//params for each sector/path (stroke-color, stroke-width, stroke-linecap)
var pathParams = {
«stroke»: this.color,
«stroke-width»: this.sectorWidth,
«stroke-linecap»: «round»
};
/**
* creates the Raphael object with a width and a height
* equals to the double of the spinner center
* “spinner” is the id of the div where the elements will be drawn
*/
var paperSize = 2 * spinnerCenter;
this.spinnerObject = Raphael(‘spinner’, paperSize, paperSize);
|
Далее следует отрисовка цикла и построение массива с текущей непрозрачностью каждого сектора:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
//builds the sectors and the respective opacity
for (var i = 0; i < this.sectorsCount; i++) {
//angle of the current sector
var alpha = beta * i;
var cos = Math.cos(alpha);
var sin = Math.sin(alpha);
//opacity of the current sector
this.opacity[i] = 1 / this.sectorsCount * i;
/**
* builds each sector, which in reality is a SVG path
* note that Upper case letter means that the command is absolute,
* lower case means relative to the current position.
* (http://www.w3.org/TR/SVG/paths.html#PathData)
* we move the «cursor» to the center of the spinner
* and add the centerRadius to center to move to the beginning of each sector
* and draws a line with length = sectorLength to the final point
* (which takes into account the current drawing angle)
*/
this.sectors[i] = this.spinnerObject.path([
[«M», spinnerCenter + this.centerRadius * cos, spinnerCenter + this.centerRadius * sin],
[«l», this.sectorLength * cos, this.sectorLength * sin]
]).attr(pathParams);
}
|
Теперь, когда у нас построен и показан наш счетчик, нам нужно его анимировать. Это последняя часть метода create:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
/**
* does an animation step and calls itself again
* @param spinnerObject this param needs to be passed
* because of scope changes when called through setTimeout function
*/
(function animationStep(spinnerObject) {
//shifts to the right the opacity of the sectors
spinnerObject.opacity.unshift(spinnerObject.opacity.pop());
//updates the opacity of the sectors
for (var i = 0; i < spinnerObject.sectorsCount; i++) {
spinnerObject.sectors[i].attr(«opacity», spinnerObject.opacity[i]);
}
/**
* safari browser helper
* There is an inconvenient rendering bug in Safari (WebKit):
* sometimes the rendering should be forced.
* This method should help with dealing with this bug.
* source: http://raphaeljs.com/reference.html#Paper.safari
*/
spinnerObject.spinnerObject.safari();
/**
* calls the animation step again
* it’s called in each second, the number of sectors the spinner has.
* So the spinner gives a round each second, independently the number of sectors it has
* note: doesn’t work on IE passing parameter with the settimeout function 🙁
*/
spinnerObject.spinnerTick = setTimeout(animationStep, 1000 / spinnerObject.sectorsCount, spinnerObject);
})(this);
};//end of the create method
|
Наконец, метод уничтожения нашего блесны:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
/**
* destroys the spinner and hides the full screen div
*/
Spinner.prototype.destroy = function() {
//stops the animation function
clearTimeout(this.spinnerTick);
//removes the Raphael spinner object
this.spinnerObject.remove();
this.spinnerObject = null;
//animates the opacity of the div to 0 again and hides it (display:none) in the end
$(‘#spinnerFullScreen’).animate({
opacity: 0
}, 2000, function() {
$(‘#spinnerFullScreen’).hide();
});
};
|
Шаг 4: Раскройте силу!
С вращающимся кодом на месте теперь пришло время прикрепить событие к ссылке, чтобы, когда пользователь щелкает по нему, мы отображали счетчик с интервалом в 6 секунд. Лично я использую это для асинхронных запросов к серверу, и когда запрос закончен, я просто удаляю счетчик.
Обратите внимание, что этот код можно использовать только после загрузки всех библиотек, от которых зависит спиннер. Вы можете добавить этот код в конец файла spinner.js или в другой файл JavaScript, если хотите сохранить файл spinner.js независимым и повторно используемым для других проектов.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
$(document).ready(function() {
$(‘#createSpinner’).click(unleashSpinner);
});
function unleashSpinner() {
var data = {};
data.centerRadius = 35;
data.sectorLength = 50;
data.sectorsCount = 10;
data.sectorWidth = 20;
data.color = ‘white’;
data.fullScreenOpacity = 0.8;
var spinner = new Spinner(data);
spinner.create();
setTimeout(function(){spinner.destroy();}, 6000);
return false;
}
|
Мы можем использовать переменную счетчика столько раз, сколько захотим.
Заворачивать
Спиннер, продемонстрированный в этом руководстве, можно использовать на веб-страницах, предназначенных не только для мобильных устройств, но и для «обычных» веб-страниц. Я уже попробовал это с обоими методами, и это работало просто отлично!
Чтобы проверить свои знания, вы можете улучшить текущую реализацию блесны несколькими уникальными способами. Например, вы можете попробовать изменить формат / форму сечений, включить движение по часовой стрелке или против часовой стрелки или позволить разработчику выбрать любой идентификатор для счетчика, чтобы избежать столкновения идентификаторов.
Вот и все на этот раз. Я надеюсь, вам понравился этот урок!