mirror of
https://github.com/donl/meteor-ionic.git
synced 2026-05-26 22:06:41 -06:00
450 lines
10 KiB
JavaScript
450 lines
10 KiB
JavaScript
|
|
Template.ionSpinner.helpers({
|
|
classes: function() {
|
|
classes = [];
|
|
if (this.class) {
|
|
var customClasses = this.class.split(' ');
|
|
_(customClasses).each(function(customClass) {
|
|
classes.push(customClass);
|
|
});
|
|
}
|
|
return classes.join(' ');
|
|
},
|
|
|
|
icon: function() {
|
|
iconName = "spinner-" + (this.icon || 'ios');
|
|
|
|
return iconName;
|
|
}
|
|
});
|
|
|
|
// the relevant code for getting the spinner element and assigning the
|
|
// spinner names is in the init function at the bottom of this file.
|
|
// Almost all of the rest of the code is from the ionic version.
|
|
|
|
Template.ionSpinner.rendered = function() {
|
|
|
|
|
|
var TRANSLATE32 = 'translate(32,32)';
|
|
var STROKE_OPACITY = 'stroke-opacity';
|
|
var ROUND = 'round';
|
|
var INDEFINITE = 'indefinite';
|
|
var DURATION = '750ms';
|
|
var NONE = 'none';
|
|
var SHORTCUTS = {
|
|
a: 'animate',
|
|
an: 'attributeName',
|
|
at: 'animateTransform',
|
|
c: 'circle',
|
|
da: 'stroke-dasharray',
|
|
os: 'stroke-dashoffset',
|
|
f: 'fill',
|
|
lc: 'stroke-linecap',
|
|
rc: 'repeatCount',
|
|
sw: 'stroke-width',
|
|
t: 'transform',
|
|
v: 'values'
|
|
};
|
|
|
|
var SPIN_ANIMATION = {
|
|
v: '0,32,32;360,32,32',
|
|
an: 'transform',
|
|
type: 'rotate',
|
|
rc: INDEFINITE,
|
|
dur: DURATION
|
|
};
|
|
|
|
//get icon name and element from blaze template
|
|
|
|
var iconElement = this.firstNode;
|
|
this.data = this.data || {};
|
|
iconName = this.data.icon || 'ios';
|
|
|
|
|
|
function createSvgElement(tagName, data, parent, spinnerName) {
|
|
var ele = document.createElement(SHORTCUTS[tagName] || tagName);
|
|
var k, x, y;
|
|
for (k in data) {
|
|
|
|
if (Array.isArray(data[k])) {
|
|
for (x = 0; x < data[k].length; x++) {
|
|
if (data[k][x].fn) {
|
|
for (y = 0; y < data[k][x].t; y++) {
|
|
createSvgElement(k, data[k][x].fn(y, spinnerName), ele, spinnerName);
|
|
}
|
|
} else {
|
|
createSvgElement(k, data[k][x], ele, spinnerName);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
setSvgAttribute(ele, k, data[k]);
|
|
}
|
|
}
|
|
|
|
parent.appendChild(ele);
|
|
}
|
|
|
|
function setSvgAttribute(ele, k, v) {
|
|
ele.setAttribute(SHORTCUTS[k] || k, v);
|
|
}
|
|
|
|
function animationValues(strValues, i) {
|
|
var values = strValues.split(';');
|
|
var back = values.slice(i);
|
|
var front = values.slice(0, values.length - back.length);
|
|
values = back.concat(front).reverse();
|
|
return values.join(';') + ';' + values[0];
|
|
}
|
|
|
|
var IOS_SPINNER = {
|
|
sw: 4,
|
|
lc: ROUND,
|
|
line: [{
|
|
fn: function(i, spinnerName) {
|
|
return {
|
|
y1: spinnerName == 'ios' ? 17 : 12,
|
|
y2: spinnerName == 'ios' ? 29 : 20,
|
|
t: TRANSLATE32 + ' rotate(' + (30 * i + (i < 6 ? 180 : -180)) + ')',
|
|
a: [{
|
|
fn: function() {
|
|
return {
|
|
an: STROKE_OPACITY,
|
|
dur: DURATION,
|
|
v: animationValues('0;.1;.15;.25;.35;.45;.55;.65;.7;.85;1', i),
|
|
rc: INDEFINITE
|
|
};
|
|
},
|
|
t: 1
|
|
}]
|
|
};
|
|
},
|
|
t: 12
|
|
}]
|
|
};
|
|
|
|
var spinners = {
|
|
|
|
android: {
|
|
c: [{
|
|
sw: 6,
|
|
da: 128,
|
|
os: 82,
|
|
r: 26,
|
|
cx: 32,
|
|
cy: 32,
|
|
f: NONE
|
|
}]
|
|
},
|
|
|
|
ios: IOS_SPINNER,
|
|
|
|
'ios-small': IOS_SPINNER,
|
|
|
|
bubbles: {
|
|
sw: 0,
|
|
c: [{
|
|
fn: function(i) {
|
|
return {
|
|
cx: 24 * Math.cos(2 * Math.PI * i / 8),
|
|
cy: 24 * Math.sin(2 * Math.PI * i / 8),
|
|
t: TRANSLATE32,
|
|
a: [{
|
|
fn: function() {
|
|
return {
|
|
an: 'r',
|
|
dur: DURATION,
|
|
v: animationValues('1;2;3;4;5;6;7;8', i),
|
|
rc: INDEFINITE
|
|
};
|
|
},
|
|
t: 1
|
|
}]
|
|
};
|
|
},
|
|
t: 8
|
|
}]
|
|
},
|
|
|
|
circles: {
|
|
|
|
c: [{
|
|
fn: function(i) {
|
|
return {
|
|
r: 5,
|
|
cx: 24 * Math.cos(2 * Math.PI * i / 8),
|
|
cy: 24 * Math.sin(2 * Math.PI * i / 8),
|
|
t: TRANSLATE32,
|
|
sw: 0,
|
|
a: [{
|
|
fn: function() {
|
|
return {
|
|
an: 'fill-opacity',
|
|
dur: DURATION,
|
|
v: animationValues('.3;.3;.3;.4;.7;.85;.9;1', i),
|
|
rc: INDEFINITE
|
|
};
|
|
},
|
|
t: 1
|
|
}]
|
|
};
|
|
},
|
|
t: 8
|
|
}]
|
|
},
|
|
|
|
crescent: {
|
|
c: [{
|
|
sw: 4,
|
|
da: 128,
|
|
os: 82,
|
|
r: 26,
|
|
cx: 32,
|
|
cy: 32,
|
|
f: NONE,
|
|
at: [SPIN_ANIMATION]
|
|
}]
|
|
},
|
|
|
|
dots: {
|
|
|
|
c: [{
|
|
fn: function(i) {
|
|
return {
|
|
cx: 16 + (16 * i),
|
|
cy: 32,
|
|
sw: 0,
|
|
a: [{
|
|
fn: function() {
|
|
return {
|
|
an: 'fill-opacity',
|
|
dur: DURATION,
|
|
v: animationValues('.5;.6;.8;1;.8;.6;.5', i),
|
|
rc: INDEFINITE
|
|
};
|
|
},
|
|
t: 1
|
|
}, {
|
|
fn: function() {
|
|
return {
|
|
an: 'r',
|
|
dur: DURATION,
|
|
v: animationValues('4;5;6;5;4;3;3', i),
|
|
rc: INDEFINITE
|
|
};
|
|
},
|
|
t: 1
|
|
}]
|
|
};
|
|
},
|
|
t: 3
|
|
}]
|
|
},
|
|
|
|
lines: {
|
|
sw: 7,
|
|
lc: ROUND,
|
|
line: [{
|
|
fn: function(i) {
|
|
return {
|
|
x1: 10 + (i * 14),
|
|
x2: 10 + (i * 14),
|
|
a: [{
|
|
fn: function() {
|
|
return {
|
|
an: 'y1',
|
|
dur: DURATION,
|
|
v: animationValues('16;18;28;18;16', i),
|
|
rc: INDEFINITE
|
|
};
|
|
},
|
|
t: 1
|
|
}, {
|
|
fn: function() {
|
|
return {
|
|
an: 'y2',
|
|
dur: DURATION,
|
|
v: animationValues('48;44;36;46;48', i),
|
|
rc: INDEFINITE
|
|
};
|
|
},
|
|
t: 1
|
|
}, {
|
|
fn: function() {
|
|
return {
|
|
an: STROKE_OPACITY,
|
|
dur: DURATION,
|
|
v: animationValues('1;.8;.5;.4;1', i),
|
|
rc: INDEFINITE
|
|
};
|
|
},
|
|
t: 1
|
|
}]
|
|
};
|
|
},
|
|
t: 4
|
|
}]
|
|
},
|
|
|
|
ripple: {
|
|
f: NONE,
|
|
'fill-rule': 'evenodd',
|
|
sw: 3,
|
|
circle: [{
|
|
fn: function(i) {
|
|
return {
|
|
cx: 32,
|
|
cy: 32,
|
|
a: [{
|
|
fn: function() {
|
|
return {
|
|
an: 'r',
|
|
begin: (i * -1) + 's',
|
|
dur: '2s',
|
|
v: '0;24',
|
|
keyTimes: '0;1',
|
|
keySplines: '0.1,0.2,0.3,1',
|
|
calcMode: 'spline',
|
|
rc: INDEFINITE
|
|
};
|
|
},
|
|
t: 1
|
|
}, {
|
|
fn: function() {
|
|
return {
|
|
an: STROKE_OPACITY,
|
|
begin: (i * -1) + 's',
|
|
dur: '2s',
|
|
v: '.2;1;.2;0',
|
|
rc: INDEFINITE
|
|
};
|
|
},
|
|
t: 1
|
|
}]
|
|
};
|
|
},
|
|
t: 2
|
|
}]
|
|
},
|
|
|
|
spiral: {
|
|
defs: [{
|
|
linearGradient: [{
|
|
id: 'sGD',
|
|
gradientUnits: 'userSpaceOnUse',
|
|
x1: 55,
|
|
y1: 46,
|
|
x2: 2,
|
|
y2: 46,
|
|
stop: [{
|
|
offset: 0.1,
|
|
class: 'stop1'
|
|
}, {
|
|
offset: 1,
|
|
class: 'stop2'
|
|
}]
|
|
}]
|
|
}],
|
|
g: [{
|
|
sw: 4,
|
|
lc: ROUND,
|
|
f: NONE,
|
|
path: [{
|
|
stroke: 'url(#sGD)',
|
|
d: 'M4,32 c0,15,12,28,28,28c8,0,16-4,21-9'
|
|
}, {
|
|
d: 'M60,32 C60,16,47.464,4,32,4S4,16,4,32'
|
|
}],
|
|
at: [SPIN_ANIMATION]
|
|
}]
|
|
}
|
|
|
|
};
|
|
|
|
var animations = {
|
|
|
|
android: function(ele) {
|
|
|
|
var rIndex = 0;
|
|
var rotateCircle = 0;
|
|
var startTime;
|
|
var svgEle = ele.querySelector('g');
|
|
var circleEle = ele.querySelector('circle');
|
|
|
|
function run() {
|
|
var v = easeInOutCubic(Date.now() - startTime, 650);
|
|
var scaleX = 1;
|
|
var translateX = 0;
|
|
var dasharray = (188 - (58 * v));
|
|
var dashoffset = (182 - (182 * v));
|
|
|
|
if (rIndex % 2) {
|
|
scaleX = -1;
|
|
translateX = -64;
|
|
dasharray = (128 - (-58 * v));
|
|
dashoffset = (182 * v);
|
|
}
|
|
|
|
var rotateLine = [0, -101, -90, -11, -180, 79, -270, -191][rIndex];
|
|
|
|
setSvgAttribute(circleEle, 'da', Math.max(Math.min(dasharray, 188), 128));
|
|
setSvgAttribute(circleEle, 'os', Math.max(Math.min(dashoffset, 182), 0));
|
|
setSvgAttribute(circleEle, 't', 'scale(' + scaleX + ',1) translate(' + translateX + ',0) rotate(' + rotateLine + ',32,32)');
|
|
|
|
rotateCircle += 4.1;
|
|
if (rotateCircle > 359) rotateCircle = 0;
|
|
setSvgAttribute(svgEle, 't', 'rotate(' + rotateCircle + ',32,32)');
|
|
|
|
if (v >= 1) {
|
|
rIndex++;
|
|
if (rIndex > 7) rIndex = 0;
|
|
startTime = Date.now();
|
|
}
|
|
|
|
window.requestAnimationFrame(run);
|
|
}
|
|
|
|
return function() {
|
|
startTime = Date.now();
|
|
run();
|
|
};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
function easeInOutCubic(t, c) {
|
|
t /= c / 2;
|
|
if (t < 1) return 1 / 2 * t * t * t;
|
|
t -= 2;
|
|
return 1 / 2 * (t * t * t + 2);
|
|
}
|
|
|
|
init();
|
|
|
|
function init() {
|
|
|
|
var spinnerName = iconName;
|
|
var $element = $(iconElement);
|
|
var container = iconElement;
|
|
createSvgElement('svg', {
|
|
viewBox: '0 0 64 64',
|
|
g: [spinners[spinnerName]]
|
|
}, container, spinnerName);
|
|
|
|
// Specifically for animations to work,
|
|
// Android 4.3 and below requires the element to be
|
|
// added as an html string, rather than dynmically
|
|
// building up the svg element and appending it.
|
|
$element.html(container.innerHTML);
|
|
|
|
start(spinnerName, $element);
|
|
|
|
};
|
|
|
|
function start(spinnerName, ele) {
|
|
animations[spinnerName] && animations[spinnerName](ele[0])();
|
|
};
|
|
|
|
|
|
}
|