h5 canvas学习之绘制圆形波浪进度条
之前做android原生开发,现在公司又让搞搞h5,所有就开始学习js的相关知识,canvas是h5的一个重要元素(当然原生的Canvas要好用的多)。都是绘制图形来制作控件。当然了,画图的思想没太大变化,主要是API的不同以及语言区别,需要排坑。希望帮到才入坑的萌新。废话不多说,效果图:
现在的流程是:画圆、画波浪、画文字、然后就是进度的设置和获取。以及各样式的设置和获取。最后就是封装在一个js文件中。
1 画圆
画图形的条件是上下文要存在
var myCanvas = document.getElementById(id);
var ctx = myCanvas.getContext("2d");
if(ctx) {
//画图
}
画圆API
arc(x, y, radius, startAngle, endAngle, anticlockwise)
画一个以(x,y)为圆心的以radius为半径的圆弧(圆),从startAngle开始到endAngle(弧度,弧度=(Math.PI/180)*角度)结束,按照anticlockwise给定的方向(默认为顺时针)来生成。关键代码
c.beginPath();
c.arc(X, Y, radius, 0, Math.PI * 2, true);
c.closePath();
c.stroke();
c.clip();
stroke()就是绘制空心的形状,clip就是裁剪画布,当前是什么形状,之后绘制的图形都只能现在在裁剪的画布上,这里裁剪掉圆之外的图形,
2 画波浪
波浪就是曲线,所以画曲线可以使用贝塞尔曲线就很方便了。
quadraticCurveTo(cp1x, cp1y, x, y)
绘制二次贝塞尔曲线,cp1x,cp1y为一个控制点,x,y为结束点。
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
绘制三次贝塞尔曲线,cp1x,cp1y为控制点一,cp2x,cp2y为控制点二,x,y为结束点。
详细请移步贝塞尔曲线。
静态的曲线有了之后再在x轴上不断的移动就形成了大波浪的样子。移动一次要重新绘制一次。
至于一个圆形内显示几个波,改变下波长即可
关键代码
c.moveTo(mWaveDx - 2 * mWaveLength, mWaveDy);
for(var j = -2; j <= 4; j++)
{
if(j % 2 == 0)
{ y = mWaveDy + mWaveheight;
}
else {
y = mWaveDy - mWaveheight;
}
c.quadraticCurveTo(mWaveDx + mWaveLength * (2 * j - 1) / 2, y, mWaveDx + mWaveLength * j, mWaveDy);
}
c.lineTo(w, h);
c.lineTo(0, h);
c.closePath();
c.fill();
mWaveDx 就是用来让波浪飞,mWaveDy就是进度的控制。fill()就是填充
3 画文字
关键代码
c.fillStyle = obj.mTextColor;
c.font = "bold " + obj.mTextSize + "px Microsoft Yahei";
c.textBaseline = "middle";
var info = obj.mProgress + "%";
c.fillText(info, X - c.measureText(info).width / 2, Y, 100);
绘制文字的方法就是fillText(),参数 (文字 x坐标 y坐标,可选的最大宽度)。
这里需要注意的是要把文字绘制在圆心(好看点,你非要写在其他地方也可以)。c.measureText(info).width这个方法是测量所绘制文字的宽度的,这样确定x的坐标,y坐标直接这只基线居中即可c.textBaseline = "middle";基线就是文字以那条线作为基准定位。可选的值包括:top, hanging, middle, alphabetic, ideographic, bottom。默认值是 alphabetic。图示(图片侵权的话联系我)
这样的话基本的图形就绘制号了,现在就可以添加动画了。
4 添加波浪动画。
if(window.requestAnimationFrame)
{ if(obj.anim)
{ cancelAnimationFrame(obj.anim);
}
var id = window.requestAnimationFrame(function() {
//波浪移动 mWaveDx += mWaveSpeed;
if(mWaveDx >= 2 * mWaveLength)
{ mWaveDx = 0;
}
c.clearRect(0, 0, w, h);
draw(obj);
});
obj.anim = id;
}
else { if(obj.anim)
{ clearTimeout(obj.anim);
}
var id = window.setTimeout(function()
{ //波浪移动 mWaveDx += mWaveSpeed;
if(mWaveDx >= 2 * mWaveLength) { mWaveDx = 0;
}
c.clearRect(0, 0, w, h); draw(obj);
}, 20);
obj.anim = id;
}
没什么难度,就是改变x坐标的值然后重绘,方法clearRect就是清除一个矩形区域的图形,requestAnimationFrame方法是专门用来绘制图形的,这个方法要实现循环的话需要像setTimeout那样在函数内部再次调用setTimeout。不过这里调用之后形成递归,无需那样做。简单来说就是不管改变x坐标,清除画布,重新绘制。这样波浪就动起来了。
5 进度控制
这个只需要改变波浪的y轴坐标就行了。
if(pro == 0) {
mWaveDy = h;
} else if(pro == obj.mMaxValue)
{ mWaveDy = 0; }
else if(pro <= obj.mBorderwidth)
{ //进度小于线宽 圆的线过宽会遮住波浪 所以上移一点
mWaveDy = h - 2 * obj.mBorderwidth;
}
else if(pro >= obj.mMaxValue - obj.mBorderwidth)
{
//避免遮住 下移一点
mWaveDy = h - (pro / obj.mMaxValue) * h + 2 * obj.mBorderwidth;
}
else { mWaveDy = h - (pro / obj.mMaxValue) * h;
}
需要注意的是如果圆的线宽设置了大于1,波浪的高度需要相应的做处理,不然进度太低(比如1)波浪会显示不出,进度太高(比如98),就完全占满圆形了。
6 封装成一个js。
封装涉及到js的面向对象设计,大家可以看看JS高级程序设计。
完整的代码js学习