完美 作者 完美 2016-09-01 12:56:43【3月前
写了篇0文章6人关注

Canvas特效之变幻线  17.2°

字数(92314) 阅读(51) 积分评论(6) 分类: Javascript

最近都在研究Canvas的一些东西,今天给大家分享一个干货!(主要讲思路,那些API自己去查资料)

(实际上没卵用,这个特效实用价值不是很大,但是我们要的就是炫!)
上一个Demo看看效果再说:

Canvas特效之变幻线

直接上代码:

首先讲一下原理:
就是画好几个点,然后这些点之间用线连接起来,然后再移动这些点,就会实现这样的效果。剩下的后面说!
以下内容过多,我把它折叠起来了,点击展开看!

 

 

 
  1. <canvas id="myCanvas"></canvas>

 

 

 
  1. //body样式外边距0不用说吧。都是老司机了!
  2. //然后因为获取到的页面宽是包含滚动条的宽度的,这样就会有滚动条出来,所以要溢出隐藏。
  3. <style type="text/css">
  4. body {
  5. overflow: hidden;
  6. background: #000;
  7. margin: 0;
  8. }
  9. </style>

 

 

 
  1. window.onload = function(){
  2. var canvas = document.querySelector("#myCanvas");//获取Canavs标签
  3. var context = canvas.getContext("2d");//获取Canvas的上下文绘图环境
  4. var winW = window.innerWidth;//获取页面宽
  5. var winH = window.innerHeight;//获取页面高
  6. canvas.width = winW;//赋值Canvas的宽度
  7. canvas.height = winH;//赋值Canvas的高度
  8. /*这里有个需要注意的地方,Canavs的宽高属性一定要直接点出来width,height来赋值。或者直接在标签属性里面固定宽高。
  9. 因为canvas是一张画布,就像一张图片那样,默认的图片大小事300*150。
  10. 但是我们在css样式中设置了canvas,其实设置的并不是canvas真正的宽高,它只是在canvas的宽高上等比例缩放了。
  11. 所以,画布的宽跟高,必须直接在canvas标签里面设置了。
  12. 这样一来,就直接改变了默认的画布宽跟高的值。*/

这里我写了个例子简单说明了一下:
Canvas宽高的问题

 
  1. //然后我们来画点
  2. var line = []; //点的信息
  3. var num = 10; //点的个数
  4. /*循环num把小点存进line数组。
  5. 数组的信息包括了他的坐标x和y,宽和高。
  6. 要让它动起来就需要给他一个运动系数,每次移动多少。
  7. 我们用随机数来生成。需要一个生成随机数的函数*/
  8. function rnd(n, m) {
  9. return Math.floor(Math.random() * (m - n) + n)
  10. };
  11. for(var i = 0; i < num; i++) {
  12. line[i] = {
  13. w: 0,//点的宽
  14. h: 0,//点的高
  15. x: rnd(0, winW), //点的X坐标
  16. y: rnd(0, winH), //点的Y坐标
  17. speedX: rnd(-5, 5), //X轴移动的速度,正数和负数,也就是往左往右
  18. speedY: rnd(-5, 5) //Y轴移动的速度,正数和负数,也就是往上往下
  19. };
  20. };
  21. //然后我们把它画出来,并且让它动起来,同时不能让它跑到屏幕外面所以我们要加个碰撞检测。
  22. /*碰撞检测的原理:
  23. 拿点的x坐标和页面最左边比较(也就是0点坐标),如果小于等于0,那点的x坐标就等于0。
  24. 拿点的x坐标和页面最右边比较(屏幕最右边,减去点的宽度,因为画点的时候是从坐标点开始,宽度是往右边走,高度往下边走,所以他右边的距离要加上宽度,那么相对的页面宽度就要减去小点的宽度。),如果大于等于,那就让x坐标等于最大值(页面宽-点的宽度)。
  25. y轴坐标同理。只不过换成了页面高度了。
  26. 然后如果x坐标=0也就是进判断了,那么意味着小点是往左边运动的,左边的话,移动速度就是负数对吧,那么乘以-1,负负得正。移动速度就变成正数了,这样小点就往右边跑了,同理,如果x坐标进了页面宽度最大的那个判断,意味着移动速度就是正数,乘以-1,正负得负,移动速度变成-数,正数+负数=正数-这个负数的绝对值。就变成往左边跑了。(我晕,讲数学也是醉了。希望我说的够明白。你们能看懂就好,不要晕菜啊。)*/
  27. //定义一个函数,负责画小点,还有一个循环num来画小点,顺便控制小点移动起来,就是坐标累加。
  28. //画点,参数p就是数组里面每个小点的信息
  29. function drawPoint(p) {
  30. context.fillStyle = '#fff';
  31. context.fillRect(p.x, p.y, p.w, p.h);
  32. context.strokeRect(p.x, p.y, p.w, p.h);
  33. }
  34. function drawobj(){
  35. for(var i = 0; i < num; i++) {
  36. context.clearRect(0, 0, winW, winH);//因为要用定时器来循环画小球,所以每次都要清空画布,重新画
  37. //传参进去
  38. drawPoint(line[i]);
  39. //坐标累加移动
  40. line[i].x += line[i].speedX;//坐标累加
  41. line[i].y += line[i].speedY;//坐标累加
  42. //碰撞检测
  43. if(line[i].x <= 0) {
  44. line[i].x = 0;
  45. line[i].speedX *= -1;
  46. }
  47. if(line[i].x >= winW-line[i].w) {
  48. line[i].x = winW-line[i].w;
  49. line[i].speedX *= -1;
  50. }
  51. if(line[i].y <= 0) {
  52. line[i].y = 0;
  53. line[i].speedY *= -1;
  54. }
  55. if(line[i].y >= winH-line[i].h) {
  56. line[i].y = winH-line[i].h;
  57. line[i].speedY *= -1;
  58. }
  59. };
  60. };
  61. //现在我们只要加个定时器这个小点就可以动起来了。
  62. setInterval(drawobj,1000/60);//这个时间自己定义,1000/60是大部分浏览器运行的最快速度
  63. }

这有个Demo:
Canvas特效之变幻线之画点


现在点已经画好了,并且让他都动起来了,那么就是连接了,把它们用线条连起来。它们动起来线条就会有交错。
那么既然是线条就要有始有终,不能始乱终弃对吧。我们找一个起点,就把第一个小点当作起点。

 

 
  1. context.beginPath();
  2. context.moveTo(line[0].x,line[0].y);//第一个小点下标0
  3. //然后剩下的就是按顺序来啦,for循环登场,这里有个小细节要注意,i从1开始,第一个小点没必要连接了
  4. for(var i = 1; i < num; i++) {
  5. context.lineTo(line[i].x,line[i].y);
  6. }
  7. //然后线条要设置一个颜色,选个比较好看的。
  8. context.strokeStyle = "rgba(255,0,144,1)";
  9. context.closePath();//要有始有终,闭合线条
  10. context.stroke();//这一步才能画出来,重要。这样就大功告成啦!
  11. //注意,以上代码都是写在第二步的那个for循环里面的。

这里有个栗子:
Canvas特效之变幻线之画线


到这里呢,我们的变幻线特效基本已经完成了,但是和完整版还差一点,这个就是阴影特效了。
说一下原理:其实就是轨迹的一个保留
其实阴影就是这个点变化的位置的一个保留,就是说把它位置的每一次变化都记录下来,然后每一次都连线,这样保留一次看不出来啥,保留的多了,就会形成一个阴影的效果。直接上代码:

 

 
  1. //需要定义一个全局变量来保存轨迹
  2. var oldPoint = [];//全局变量哦,不要写错。这个是用来存储每个点的变化轨迹的。
  3. var arr[];//这个用来存储每个点的坐标。
  4. for(var i = 0; i <num ; i++){
  5. arr.push({x:line[i].x , y:line[i].y});
  6. }
  7. oldPoint.push(arr);
  8. //然后小点的轨迹我们不可能全部保存下来,只需要保存最后几个运动轨迹就可以了,so
  9. while(oldPoint.length > 20 ){
  10. //这个数值自己定义,shift()是一个从前面开始删除的数组方法,比如[1,2,3].shift() 会变成 [2,3]
  11. oldPoint.shift();
  12. };

然后我们得到的数据是这样子的,一个二维数组
Canvas特效之变幻线

 
  1. //然后我们再次循环这些点来画线,二维数组用双重for循环
  2. for (var i = 0; i < oldPoint.length; i++) {
  3. context.beginPath();//开始
  4. context.moveTo(oldPoint[i][0].x,oldPoint[i][0].y);//起点
  5. for (var j = 1; j < num; j++) {
  6. context.lineTo(oldPoint[i][j].x,oldPoint[i][j].y);//每个点连接起来
  7. }
  8. context.closePath(); //闭合
  9. var opacity = i/oldPoint.length;//阴影就要有一种渐渐消失的感觉,可以用透明度来模拟,rgba的最后一个值。
  10. context.strokeStyle = "rgba(255,0,144,"+opacity+")";
  11. context.stroke();//画线,还没有完,别急。
  12. //注意,以上代码都是写在第二步的那个for循环里面的。
  13. }

 

优化响应式,就是移动端也要兼容,那么html代码需要加一个叫做视口的东东。

 

 
  1. <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />

相信做过移动端的同学肯定对这个不陌生吧,这个扯起来又是一大堆,本文重点不在这里。
还有就是在浏览器窗口改变大小的时候要用js动态改变canvas标签的宽高,还有改变碰撞检测的边界。

 
  1. window.onresize = function(){
  2. winW = window.innerWidth;
  3. winH = window.innerHeight;
  4. canvas.width = winW;
  5. canvas.height = winH;
  6. };

我们还可以在动画上面做一些优化

requestAnimationFrame这个不知道大家知道不。

在浏览器动画程序中,我们通常使用一个定时器来循环每隔几毫秒移动目标物体一次,来让它动起来。如今有一个好消息,浏览器开发商们决定:“嗨,为什么我们不在浏览器里提供这样一个API呢,这样一来我们可以为用户优化他们的动画。”所以,这个requestAnimationFrame()函数就是针对动画效果的API,你可以把它用在DOM上的风格变化或画布动画或WebGL中。

使用requestAnimationFrame有什么好处?

浏览器可以优化并行的动画动作,更合理的重新排列动作序列,并把能够合并的动作放在一个渲染周期内完成,从而呈现出更流畅的动画效果。比如,通过requestAnimationFrame(),JS动画能够和CSS动画/变换或SVG SMIL动画同步发生。另外,如果在一个浏览器标签页里运行一个动画,当这个标签页不可见时,浏览器会暂停它,这会减少CPU,内存的压力,节省电池电量。

各种浏览器对requestAnimationFrame的支持情况

谷歌浏览器,火狐浏览器,IE10+都实现了这个函数,即使你的浏览器很古老,上面的对requestAnimationFrame封装也能让这个方法在IE8/9上不出错。

怎么使用requestAnimationFrame()

我觉得requestAnimationFrame的使用就像回调函数一样,也像递归吧,一直循环调用。
首先写这么一段代码:

 
  1. window.requestAnimFrame = (function(){
  2. return window.requestAnimationFrame ||
  3. window.webkitRequestAnimationFrame ||
  4. window.mozRequestAnimationFrame ||
  5. function( callback ){
  6. window.setTimeout(callback, 1000 / 60);
  7. };
  8. })();
  9. //这是兼容写法,如果不支持就用setTimeout来动画。
  10. //然后再画线的方法里面加上:
  11. //画线
  12. function drawobj() {
  13. window.requestAnimationFrame(drawobj);
  14. *****************************以下代码隐藏*****************************
  15. }
  16. //然后调用函数
  17. drawobj();
  18. //是吧,函数执行的时候,动画执行,运行函数,动画执行***********************
  19. //完整例子见开头!如果觉得本文对你有用,记得点个赞再走!分享也可以!

 

 
 

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

¥ 打赏支持
发表

还可以输入1000个字

Ctrl+Enter 发表
(6)条评论