同学在公司遇到个需求,使用SVG画一个双向进度条(具体专业名词叫什么不清楚……),然后使用JS动态改变进度。之前一直都是用canvas画,没有过这方面经验,就尝试着画了一下,在此进行记录。下面是需求效果图:
0x01. 效果
-
下面这张图是需求的效果
需求效果 -
这张图是最后的代码实现的效果
最后实现效果
0x02. 在线工具起草
上来就自己起草干肯定非常费劲(最起码对我这种SVG新手来说是这样),所以偷懒了一下,用了在线SVG绘制工具,地址:https://svg.haowen100.com。
0x03. 分析与实现
绘制完成之后点击View
菜单,然后选择Souce
菜单项,即可看见绘制出的图形对应的代码
分析一下,整个进度条分为三部分,一部分是外面的黑色边框,第二部分是中间填充的进度条颜色,第三部分是周围零零碎碎的进度刻度等文字,其中第一部分黑色边框一旦设置位置大小之后就无需改变了,只需要改变进度条填充颜色部分的长度和X坐标即可,还有第三部分中的进度条上的刻度数字和刻度位置。
其中进度颜色填充部分的还分两块,一部分是从0%(青岛)那里开始到左边月100%的部分,下文称之为负进度,第二部分是从0%(青岛)到右边日100%的部分,下文称之为正进度。整个进度条的X坐标根据负进度的多少而定,而进度条的长度根据负进度和正进度的计算而定,我们首先计算出正进度和负进度的每1%的单位长度、负进度条100%时候的进度条长度,然后拿到整个进度条黑色边框的最左侧X坐标后进行计算:
进度条颜色填充的X坐标 = 黑色边框的X坐标 + 负进度的1%单位长度 * (100 - 负进度当前进度)
进度条颜色填充的长度 = 负进度条的进度 * 负进度条的1%单位长度 + 正进度条的进度 * 正进度条的1%单位长度
得到这两个数值之后,我们对界面中的控件属性进行赋值即可。接下来使用setInterval()
进行动态更新进度得到文章开头中的动画效果。
动画中还有一个效果就是当进度小于一定数值的时候 进度不动,这个很简单,就是用Math.min()
和Math.max()
进行处理一下即可,具体的可以看一下下面代码。
0x04. 代码
最后整理代码如下,就一个HTML文件,就不放Github地址了。代码中有注释,有不懂的同学可以留言
<!DOCTYPE html>
<html>
<head>
<title>大吉大利,今晚吃鸡</title>
<meta charset="utf-8">
</head>
<body>
<!-- 画布 定义画布宽高,看你用多宽多高就写多少-->
<svg width="700" height="400" xmlns="http://www.w3.org/2000/svg">
<!-- 边框矩形 -->
<rect id="borderView" height="40" width="600" y="80" x="50" stroke-width="1.5" stroke="#000" fill="#fff"/>
<!-- 进度填充矩形 -->
<rect id="progressView" height="40" width="387" y="80" x="100" stroke-opacity="null" stroke-width="1.5" stroke="#000" fill="#00bf5f"/>
<!-- 刻度 负:50-150 正:150-50-->
<!-- 负100% -->
<line stroke="#000" stroke-linecap="null" stroke-linejoin="null" id="kedus100" y2="119.59974" x2="50" y1="131" x1="50" stroke-opacity="null" stroke-width="1.5" fill="none"/>
<!-- 正0% -->
<line stroke-linecap="null" stroke-linejoin="null" id="kedup0" y2="131.17834" x2="150" y1="61" x1="150" stroke-opacity="null" stroke-width="1.5" stroke="#000" fill="none"/>
<!-- 正20% -->
<line stroke="#000" stroke-linecap="null" stroke-linejoin="null" id="kedup20" y2="120.59974" x2="250" y1="132" x1="250" stroke-opacity="null" stroke-width="1.5" fill="none"/>
<!-- 正40% -->
<line stroke="#000" stroke-linecap="null" stroke-linejoin="null" id="svg_10" y2="120.59974" x2="350" y1="132" x1="350" stroke-opacity="null" stroke-width="1.5" fill="none"/>
<!-- 正60% -->
<line stroke="#000" stroke-linecap="null" stroke-linejoin="null" id="svg_11" y2="120.59974" x2="450" y1="132" x1="450" stroke-opacity="null" stroke-width="1.5" fill="none"/>
<!-- 正80% -->
<line stroke="#000" stroke-linecap="null" stroke-linejoin="null" id="svg_12" y2="121.59974" x2="550" y1="133" x1="550" stroke-opacity="null" stroke-width="1.5" fill="none"/>
<!-- 正100% -->
<line stroke="#000" stroke-linecap="null" stroke-linejoin="null" id="kedup100" y2="119.59974" x2="650" y1="131" x1="650" stroke-opacity="null" stroke-width="1.5" fill="none"/>
<!-- 刻度数字 -->
<text xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="12" id="svg_7" y="145" x="40" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#000000">100%</text>
<text xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="12" id="svg_18" y="145" x="140" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#000000">0%</text>
<text xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="12" id="svg_19" y="145" x="240" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#000000">20%</text>
<text xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="12" id="svg_20" y="145" x="340" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#000000">40%</text>
<text xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="12" id="svg_21" y="145" x="440" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#000000">60%</text>
<text xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="12" id="svg_22" y="145" x="540" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#000000">80%</text>
<text xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="12" id="svg_7" y="145" x="640" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#000000">100%</text>
<text xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="14" id="subNumView" y="105" x="0" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#000000">90%</text>
<text xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="14" id="plusNumView" y="105" x="0" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#000000">60%</text>
<text xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="18" id="svg_13" y="55" x="45" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#000000">月</text>
<text xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="18" id="svg_14" y="55" x="640" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#000000">日</text>
<text xml:space="preserve" text-anchor="start" font-family="Helvetica, Arial, sans-serif" font-size="22" id="svg_15" y="50" x="128" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#000000">青岛</text>
</svg>
<script type="text/javascript">
function changeProgress(sub , plus){
var progressView = document.getElementById('progressView');
var subNumView = document.getElementById('subNumView');
var plusNumView = document.getElementById('plusNumView');
// 左边福进度条的最左边X坐标,即-100%进度时候的x坐标
var sub_start = 50;
// 整个负进度条占满100%的时候长度
var sub_width = 100;
// 左边的负数进度条每1%的像素长度
var sub_unit = sub_width / 100.0
// 整个正进度条占满100%的时候长度
var plus_width = 500;
// 右边的正数进度条每1%的像素长度
var plus_unit = plus_width / 100.0;
// 开始计算进度条控件属性
var progress_x = sub_start + (sub_width - sub) * sub_unit;
var progress_width = sub * sub_unit + plus * plus_unit;
var sub_num_x = Math.min(progress_x + 10 , 110);
var plus_num_x = Math.max(progress_x + progress_width - 40 , 190);
// 计算完毕。开始赋值应用
progressView.setAttribute('x' , progress_x);
progressView.setAttribute('width' , progress_width);
subNumView.setAttribute('x' , sub_num_x);
plusNumView.setAttribute('x' , plus_num_x);
subNumView.innerHTML = sub + '%';
plusNumView.innerHTML = plus + '%';
}
var progress = 0;
// 进度定时增加
var interval = setInterval(function(){
if (++ progress >= 100) {clearInterval(interval)}
changeProgress(progress,progress);
} , 100);
</script>
</body>
</html>
网友评论