标签:
// shim layer with setTimeout fallback
// credit Erik M?ller and http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
(function() {
var lastTime = 0;
var vendors = [‘webkit‘, ‘moz‘];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+‘RequestAnimationFrame‘];
window.cancelAnimationFrame =
window[vendors[x]+‘CancelAnimationFrame‘] || window[vendors[x]+‘CancelRequestAnimationFrame‘];
}
if (!window.requestAnimationFrame){
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
if (!window.cancelAnimationFrame){
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}
}());
angular.module(‘angular-svg-round-progress‘, []);
‘use strict‘;
angular.module(‘angular-svg-round-progress‘).constant(‘roundProgressConfig‘, {
max: 50,
semi: false,
radius: 100,
color: "#45ccce",
bgcolor: "#eaeaea",
stroke: 15,
iterations: 50,
animation: "easeOutCubic"
});
‘use strict‘;
angular.module(‘angular-svg-round-progress‘).service(‘roundProgressService‘, [function(){
var service = {};
// credits to http://modernizr.com/ for the feature test
service.isSupported = !!(document.createElementNS && document.createElementNS(‘http://www.w3.org/2000/svg‘, "svg").createSVGRect);
// utility function
var polarToCartesian = function(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;
return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
};
// credit to http://stackoverflow.com/questions/5736398/how-to-calculate-the-svg-path-for-an-arc-of-a-circle
service.updateState = function(value, total, R, ring, size, isSemicircle) {
if(!size) return ring;
var value = value >= total ? total - 0.00001 : value,
type = isSemicircle ? 180 : 359.9999,
perc = total === 0 ? 0 : (value / total) * type,
x = size/2,
start = polarToCartesian(x, x, R, perc), // in this case x and y are the same
end = polarToCartesian(x, x, R, 0),
// arcSweep = endAngle - startAngle <= 180 ? "0" : "1",
arcSweep = (perc <= 180 ? "0" : "1"),
d = [
"M", start.x, start.y,
"A", R, R, 0, arcSweep, 0, end.x, end.y
].join(" ");
return ring.attr(‘d‘, d);
};
// Easing functions by Robert Penner
// Source: http://www.robertpenner.com/easing/
// License: http://www.robertpenner.com/easing_terms_of_use.html
service.animations = {
// t: Current iteration
// b: Start value
// c: Change in value
// d: Total iterations
linearEase: function(t, b, c, d) {
return c * t / d + b;
},
easeInQuad: function (t, b, c, d) {
return c*(t/=d)*t + b;
},
easeOutQuad: function (t, b, c, d) {
return -c *(t/=d)*(t-2) + b;
},
easeInOutQuad: function (t, b, c, d) {
if ((t/=d/2) < 1) return c/2*t*t + b;
return -c/2 * ((--t)*(t-2) - 1) + b;
},
easeInCubic: function (t, b, c, d) {
return c*(t/=d)*t*t + b;
},
easeOutCubic: function (t, b, c, d) {
return c*((t=t/d-1)*t*t + 1) + b;
},
easeInOutCubic: function (t, b, c, d) {
if ((t/=d/2) < 1) return c/2*t*t*t + b;
return c/2*((t-=2)*t*t + 2) + b;
},
easeInQuart: function (t, b, c, d) {
return c*(t/=d)*t*t*t + b;
},
easeOutQuart: function (t, b, c, d) {
return -c * ((t=t/d-1)*t*t*t - 1) + b;
},
easeInOutQuart: function (t, b, c, d) {
if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
return -c/2 * ((t-=2)*t*t*t - 2) + b;
},
easeInQuint: function (t, b, c, d) {
return c*(t/=d)*t*t*t*t + b;
},
easeOutQuint: function (t, b, c, d) {
return c*((t=t/d-1)*t*t*t*t + 1) + b;
},
easeInOutQuint: function (t, b, c, d) {
if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
return c/2*((t-=2)*t*t*t*t + 2) + b;
},
easeInSine: function (t, b, c, d) {
return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
},
easeOutSine: function (t, b, c, d) {
return c * Math.sin(t/d * (Math.PI/2)) + b;
},
easeInOutSine: function (t, b, c, d) {
return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
},
easeInExpo: function (t, b, c, d) {
return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
},
easeOutExpo: function (t, b, c, d) {
return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
},
easeInOutExpo: function (t, b, c, d) {
if (t==0) return b;
if (t==d) return b+c;
if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
},
easeInCirc: function (t, b, c, d) {
return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
},
easeOutCirc: function (t, b, c, d) {
return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
},
easeInOutCirc: function (t, b, c, d) {
if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
},
easeInElastic: function (t, b, c, d) {
var s=1.70158;var p=0;var a=c;
if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
if (a < Math.abs(c)) { a=c; var s=p/4; }
else var s = p/(2*Math.PI) * Math.asin (c/a);
return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
},
easeOutElastic: function (t, b, c, d) {
var s=1.70158;var p=0;var a=c;
if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
if (a < Math.abs(c)) { a=c; var s=p/4; }
else var s = p/(2*Math.PI) * Math.asin (c/a);
return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
},
easeInOutElastic: function (t, b, c, d) {
var s=1.70158;var p=0;var a=c;
if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
if (a < Math.abs(c)) { a=c; var s=p/4; }
else var s = p/(2*Math.PI) * Math.asin (c/a);
if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
},
easeInBack: function (t, b, c, d, s) {
if (s == undefined) s = 1.70158;
return c*(t/=d)*t*((s+1)*t - s) + b;
},
easeOutBack: function (t, b, c, d, s) {
if (s == undefined) s = 1.70158;
return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
},
easeInOutBack: function (t, b, c, d, s) {
if (s == undefined) s = 1.70158;
if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
},
easeInBounce: function (t, b, c, d) {
return c - service.animations.easeOutBounce (d-t, 0, c, d) + b;
},
easeOutBounce: function (t, b, c, d) {
if ((t/=d) < (1/2.75)) {
return c*(7.5625*t*t) + b;
} else if (t < (2/2.75)) {
return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
} else if (t < (2.5/2.75)) {
return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
} else {
return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
}
},
easeInOutBounce: function (t, b, c, d) {
if (t < d/2) return service.animations.easeInBounce (t*2, 0, c, d) * .5 + b;
return service.animations.easeOutBounce (t*2-d, 0, c, d) * .5 + c*.5 + b;
}
};
return service;
}]);
‘use strict‘;
angular.module(‘angular-svg-round-progress‘)
.directive(‘roundProgress‘, [‘roundProgressService‘, ‘roundProgressConfig‘, function(service, roundProgressConfig){
if(!service.isSupported){
return {
// placeholder element to keep the structure
restrict: ‘EA‘,
template:‘<div class="round-progress"></div>‘,
replace: true
};
};
return {
restrict: "EA",
scope:{
current: "=",
max: "=",
semi: "=",
radius: "@",
color: "@",
bgcolor: "@",
stroke: "@",
iterations: "@",
animation: "@"
},
link: function (scope, element, attrs) {
var ring = element.find(‘path‘),
background = element.find(‘circle‘),
options = angular.copy(roundProgressConfig),
size,
resetValue;
var renderCircle = function(){
var isSemicircle = options.semi,
radius = parseInt(options.radius),
stroke = parseInt(options.stroke);
size = radius*2 + stroke*2;
element.css({
"width": size + "px",
"height": (isSemicircle ? size/2 : size) + "px",
"overflow": "hidden" // on some browsers the background overflows, if in semicircle mode
});
ring.attr({
"stroke": options.color,
"stroke-width": stroke,
"transform": isSemicircle ? (‘translate(‘+ 0 +‘,‘+ size +‘) rotate(-90)‘) : ‘‘
});
background.attr({
"cx": radius,
"cy": radius,
"transform": "translate("+ stroke +", "+ stroke +")",
"r": radius,
"stroke": options.bgcolor,
"stroke-width": stroke
});
};
var renderState = function (newValue, oldValue){
if(!angular.isDefined(newValue)){
return false;
};
if(newValue < 0){
resetValue = oldValue;
return scope.current = 0;
};
if(newValue > options.max){
resetValue = oldValue;
return scope.current = options.max;
};
var max = options.max,
radius = options.radius,
isSemicircle = options.semi,
easingAnimation = service.animations[options.animation],
start = oldValue === newValue ? 0 : (oldValue || 0), // fixes the initial animation
val = newValue - start,
currentIteration = 0,
totalIterations = parseInt(options.iterations);
if(angular.isNumber(resetValue)){
// the reset value fixes problems with animation, caused when limiting the scope.current
start = resetValue;
val = newValue - resetValue;
resetValue = null;
};
(function animation(){
service.updateState(
easingAnimation(currentIteration, start, val, totalIterations),
max,
radius,
ring,
size,
isSemicircle);
if(currentIteration < totalIterations){
requestAnimationFrame(animation);
currentIteration++;
};
})();
};
scope.$watchCollection(‘[current, max, semi, radius, color, bgcolor, stroke, iterations]‘, function(newValue, oldValue, scope){
// pretty much the same as angular.extend,
// but this skips undefined values and internal angular keys
angular.forEach(scope, function(value, key){
// note the scope !== value is because `this` is part of the scope
if(key.indexOf(‘$‘) && scope !== value && angular.isDefined(value)){
options[key] = value;
};
});
renderCircle();
renderState(newValue[0], oldValue[0]);
});
},
replace:true,
template:[
‘<svg class="round-progress" xmlns="http://www.w3.org/2000/svg">‘,
‘<circle fill="none"/>‘,
‘<path fill="none"/>‘,
‘</svg>‘
].join(‘\n‘)
};
}]);
标签:
原文地址:http://my.oschina.net/u/1457074/blog/373345