一个基于svg的圆形loading动画

时间:2022-11-20 17:18:35

前言

很多时候大家都要做一些loading动画,现在给大家带来的是用svg画出来的loading动画,稍微封装就可以使用了。

代码

<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2015/9/16
Time: 16:01
To change this template use File | Settings | File Templates.
--%>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>一个基于svg的loading控件。</title>
<script type="text/javascript" src="/static/lib/jquery-1.11.0.min.js"></script>
<script type="text/javascript" src="/static/vendor/laytpl/laytpl.js"></script>
</head>
<body>
<h2>原型。</h2>
<svg width="200" height="200">
<ellipse rx="90" ry="90" cx="100" cy="100" stroke="#f2f2f2" fill="none" stroke-width="10"></ellipse>
<path fill="none" stroke="#3daf2c" stroke-width="10" d="M100,10 A90,90 0 1 1 10,90"></path>
</svg>
<h3>控件模样。</h3>
<div id="container">

</div>
<script type="text/javascript">
function SVGLoading(_opts){
var settings={
strokeWidth:10 //边框宽度。
,strokeNormalColor:"#f2f2f2" //普通状态下边框颜色。
,strokeActivityColor:"#3daf2c" //激活状态下边框颜色。
,radius:80 //该圆形loading框的半径。
,percent:47 //当前默认显示的百分比。
,container:""
};

var appData={
width:0
,height:0
,rx:0
,ry:0
,cx:0
,cy:0
,stroke1:""
,stroke2:""
,strokeWidth:0
,d:""
};
var _d_data={
move_point:{x:0,y:0}
,radiusPoint:{x:0,y:0}
};


var _tpl_html='<svg width="{{d.width}}" height="{{d.height}}"><ellipse rx="{{d.rx}}" ry="{{d.ry}}" cx="{{d.cx}}" cy="{{d.cy}}" stroke="{{d.stroke1}}" fill="none" stroke-width="{{d.strokeWidth}}"></ellipse><path ui="path" fill="none" stroke="{{d.stroke2}}" stroke-width="{{d.strokeWidth}}" d="{{d.d}}"></path></svg>';

var tpl=laytpl(_tpl_html);
var _root="";
var _el_path="";
var app={
init:function(){
$.extend(settings,_opts);
var _me=this;
_me.initData();
_me.initView();
}
//--计算原始的尺寸及其他信息。
,initData:function(){
var me=this;
appData.width=settings.radius*2;
appData.height=settings.radius*2;
appData.strokeWidth=settings.strokeWidth;
appData.rx=parseInt((settings.radius-settings.strokeWidth));
appData.ry=appData.rx;
appData.cx=parseInt(settings.radius);
appData.cy=appData.cx;
appData.stroke1=settings.strokeNormalColor;
appData.stroke2=settings.strokeActivityColor;
_d_data.move_point={
x:appData.cx
,y:appData.cy-appData.ry
};
_d_data.radiusPoint={
x:appData.cx
,y:appData.cy
};
}
,initView:function(){
var me=this;
_root=$(settings.container);
appData.d=me.caculateD(settings.percent);
var html1=tpl.render(appData);
_root.html(html1);
_el_path=_root.find('[ui="path"]')[0];
}
//--计算 路径的d。
,caculateD:function(percent){

var me=this;
var _is_big_arc=false;
var _realpercent=percent;
if(_realpercent<0){
_realpercent=0;
}
else if(_realpercent>100){
_realpercent=100;
}
if(_realpercent>50){
_is_big_arc=true;
}
var _endPoint=me.caculatePointByPercent(percent);

var _bigArc=0;
if(_is_big_arc){
_bigArc=1;
}

var _str="M"+_d_data.move_point.x+","+_d_data.move_point.y+" A"+appData.rx+","+appData.rx+" 0 "+_bigArc+" 1 "+_endPoint.x+","+_endPoint.y+"";

return _str;


}
//--计算 路径的d。
,caculateDbyAngle:function(angle){

var me=this;
var _is_big_arc=false;
var _angle=360+angle;
_angle=_angle%360;

if(_angle>180){
_is_big_arc=true;
}
var _endPoint=me.caculatePointByAngle(_angle);

var _bigArc=0;
if(_is_big_arc){
_bigArc=1;
}

var _str="M"+_d_data.move_point.x+","+_d_data.move_point.y+" A"+appData.rx+","+appData.rx+" 0 "+_bigArc+" 1 "+_endPoint.x+","+_endPoint.y+"";

return _str;


}
//--计算当前percent的终点。
,caculatePointByPercent:function(percent){
var _res={x:0,y:0};
/**
圆点坐标:(x0,y0)
半径:r
角度:a0

则圆上任一点为:(x1,y1)
x1 = x0 + r * cos(ao * 3.14 /180 )
y1 = y0 + r * sin(ao * 3.14 /180 )
* */



var Angle0=(percent/100)*360;
Angle0=(360+Angle0-90)%360;
_res.x= _d_data.radiusPoint.x+appData.rx*Math.cos(Angle0*Math.PI/180);
_res.y= _d_data.radiusPoint.y+appData.rx*Math.sin(Angle0*Math.PI/180);

return _res;
}
,caculatePointByAngle:function(angle){
var _res={x:0,y:0};
/**
圆点坐标:(x0,y0)
半径:r
角度:a0

则圆上任一点为:(x1,y1)
x1 = x0 + r * cos(ao * 3.14 /180 )
y1 = y0 + r * sin(ao * 3.14 /180 )
* */



//处理一下角度问
/**
* 为什么要这样处理?
* 因为我们看上去认为的角度跟实际上圆角的角度有90度的差距。
* 例如对于零度来说,在我们的圆形是 | 一条垂直的竖线就是零度了,但对于实际计算这个已经是902、度了。
* **/

var Angle0=angle;
Angle0=360+angle-90;
Angle0=Angle0%360;

_res.x= _d_data.radiusPoint.x+appData.rx*Math.cos(Angle0*Math.PI/180);
_res.y= _d_data.radiusPoint.y+appData.rx*Math.sin(Angle0*Math.PI/180);
//--注意,这个得到的坐标是以正常的坐标系,即,左下角x,从左到右为x,从下到上为y,现在这个不是,现在的页面的坐标系是从上到下才是y轴,y轴要处理一下。


return _res;
}
,setPercent:function(percent){
var me=this;
var _d_str=me.caculateD(percent);
//_el_path.d=_d_str;
$(_el_path).attr("d",_d_str);
}
,setAngle:function(angle){
var me=this;
var _d_str=me.caculateDbyAngle(angle);
//_el_path.d=_d_str;
$(_el_path).attr("d",_d_str);
}
};


app.init();

var returnObject={
setPercent:function(percent){
app.setPercent(percent);
}
,setAngle:function(angle){
app.setAngle(angle);
}

};

return returnObject;
};
var _loading={};
function InitSVGLoading(){
_loading=SVGLoading({
container:$("#container")
});
};
InitSVGLoading();
var _current_percent=0;
setInterval(function(){
_loading.setPercent(_current_percent);
_current_percent=_current_percent+0.1;
_current_percent=_current_percent%100;

},10);
</script>
</body>
</html>

jquery.js和laytpl.js请在网上下载。

效果

一个基于svg的圆形loading动画

一个基于svg的圆形loading动画

兼容性

大家别执着于兼容性了,ie6-9都恐怕没办法运行,但是,ios,安卓【假如不是古董级别】,chrome,safari,firefox都可以运行,作为一名开发html5的前端,这个兼容性还不够么。