上篇原本應該就是最後一篇了,可是樓主總以爲沒有寫上一個簡單應用,不算是完整的學習系列。因此增長一篇關於動畫的應用,對一個開源動畫的介紹(很基礎,非樓主原創)。html
本篇介紹一個基於Canvas的發光加載動畫(這裏可下載源碼)。算是對以前系列的各個知識點的一個總結吧。 html5
咱們先看看最終的效果截圖:canvas
html文件引入該js,並加了一個背景黑色,大致以下這樣:數組
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>HTML5 Canvas發光Loading動畫DEMO演示</title> 6 <style> 7 body { 8 background: #000; 9 } 10 </style> 11 </head> 12 <body> 13 <canvas id="c"></canvas> 14 <script src="js/index.js"></script> 15 </body> 16 </html>
看效果圖能夠知道,咱們是要畫弧線,全部的動畫都是基於這個弧線來操做的,那咱們就要肯定該弧線的座標、半徑、弧度起始點等。數據結構
要讓其動起來,即旋轉起來,咱們須要旋轉速度(弧度),當前旋轉角度等。dom
咱們整理成以下變量:ide
1 var c = document.getElementById('c'), 2 ctx = c.getContext('2d'), 3 cw = c.width = 400, 4 ch = c.height = 300, 5 rand = function (a, b) { return ~~((Math.random() * (b - a + 1)) + a); },//獲取a到b之間的整數值 6 dToR = function (degrees) { return degrees * (Math.PI / 180); },//角度變弧度 7 circle = { 8 x: (cw / 2) + 5, 9 y: (ch / 2) + 22,//圓心座標 10 radius: 90,//半徑 11 speed: 2,//旋轉速度(角度) 12 rotation: 0,//當前角度 13 angleStart: 270,//圓弧起始弧度 14 angleEnd: 90,//結束弧度 15 hue: 220,//色調 16 thickness: 18,//邊緣粗細 17 blur: 25//模糊度 18 }, 19 particles = [],//亮點數組 20 particleMax = 100,//亮點個數
19-29行的變量示例中增長其餘效果時會用到,這裏能夠暫時忽略。函數
該弧線帶有一個漸變效果,咱們會用到的APIs有arc(),createLinearGradient()等,方法以下:oop
1 renderCircle = function () { 2 ctx.save();//保存當前做圖上下文 3 ctx.translate(circle.x, circle.y);//移動座標原點到圓心位置 4 5 ctx.beginPath(); 6 ctx.arc(0, 0, circle.radius, dToR(circle.angleStart), dToR(circle.angleEnd), true); 7 ctx.lineWidth = circle.thickness; 8 9 var gradient1 = ctx.createLinearGradient(0, -circle.radius, 0, circle.radius); 10 gradient1.addColorStop(0, 'hsla(' + circle.hue + ', 60%, 50%, .25)'); 11 gradient1.addColorStop(1, 'hsla(' + circle.hue + ', 60%, 50%, 0)'); 12 13 ctx.strokeStyle = gradient1;//弧線是漸變色 14 ctx.stroke(); 15 ctx.restore();//畫完弧線以後,畫其餘東西以前,先恢復做圖上下文 16 },
這裏就不截圖看效果了,就是一條漸變弧線。學習
這裏旋轉其實就很簡單了,只要不停地旋轉角度,在畫弧線以前調用旋轉API rotate()就能夠了。下邊是代碼:
1 updateCircle = function () { 2 if (circle.rotation < 360) { 3 circle.rotation += circle.speed; 4 } else { 5 circle.rotation = 0; 6 } 7 }
咱們能夠在畫弧線的方法中加入旋轉角度(renderCircle 方法第四行加上下邊這句便可):
ctx.rotate(dToR(circle.rotation));//旋轉角度,此處是動畫動起來的地方。
說到這裏,其實關於動畫的內容就寫的差很少了,只要一個定時器不停地調用這兩個方法就行了。
不過,要注意一點,每次從新畫圖以前咱們都要將canvas清空,咱們調用clearRect或者統一寫一個初始化方法便可,以下:
1 clear = function () { 2 ctx.globalCompositeOperation = 'destination-out'; 3 ctx.fillStyle = 'rgba(0, 0, 0, .1)'; 4 ctx.fillRect(0, 0, cw, ch); 5 ctx.globalCompositeOperation = 'lighter'; 6 }
定時器統一調用方法:
1 loop = function () { 2 clear(); 3 updateCircle(); 4 renderCircle(); 5 }
設置定時器:
setInterval(loop, 20);
如今的效果已經出來了:
剩下的就是給弧線增長效果了。
該示例中爲了更好地展現效果,設置了弧線邊緣,頭部發亮及小亮點顯隱等多個效果,園友可運行代碼查看效果。
完整的js代碼以下:
1 /* super inefficient right now, could be improved */ 2 3 //http://www.html5tricks.com/html5-canvas-shine-loading.html 4 5 var c = document.getElementById('c'), 6 ctx = c.getContext('2d'), 7 cw = c.width = 400, 8 ch = c.height = 300, 9 rand = function (a, b) { return ~~((Math.random() * (b - a + 1)) + a); },//獲取a到b之間的整數值 10 dToR = function (degrees) { return degrees * (Math.PI / 180); },//角度變弧度 11 circle = { 12 x: (cw / 2) + 5, 13 y: (ch / 2) + 22,//圓心座標 14 radius: 90,//半徑 15 speed: 2,//旋轉速度(角度) 16 rotation: 0,//當前角度 17 angleStart: 270,//圓弧起始弧度 18 angleEnd: 90,//結束弧度 19 hue: 220,//色調 20 thickness: 18,//邊緣粗細 21 blur: 25//模糊度 22 }, 23 particles = [],//亮點數組 24 particleMax = 100,//亮點個數 25 26 //更新旋轉角度 27 updateCircle = function () { 28 if (circle.rotation < 360) { 29 circle.rotation += circle.speed; 30 } else { 31 circle.rotation = 0; 32 } 33 }, 34 //畫弧線 35 renderCircle = function () { 36 ctx.save();//保存當前做圖上下文 37 ctx.translate(circle.x, circle.y);//移動座標原點到圓心位置 38 ctx.rotate(dToR(circle.rotation));//旋轉角度,此處是動畫動起來的地方。 39 ctx.beginPath(); 40 ctx.arc(0, 0, circle.radius, dToR(circle.angleStart), dToR(circle.angleEnd), true); 41 ctx.lineWidth = circle.thickness; 42 43 var gradient1 = ctx.createLinearGradient(0, -circle.radius, 0, circle.radius); 44 gradient1.addColorStop(0, 'hsla(' + circle.hue + ', 60%, 50%, .25)'); 45 gradient1.addColorStop(1, 'hsla(' + circle.hue + ', 60%, 50%, 0)'); 46 47 ctx.strokeStyle = gradient1;//弧線是漸變色 48 ctx.stroke(); 49 ctx.restore();//畫完弧線以後,畫其餘東西以前,先恢復做圖上下文 50 }, 51 //弧線邊緣效果 52 renderCircleBorder = function () { 53 ctx.save(); 54 ctx.translate(circle.x, circle.y); 55 ctx.rotate(dToR(circle.rotation)); 56 ctx.beginPath(); 57 ctx.arc(0, 0, circle.radius + (circle.thickness / 2), dToR(circle.angleStart), dToR(circle.angleEnd), true); 58 ctx.lineWidth = 2; 59 60 var gradient2 = ctx.createLinearGradient(0, -circle.radius, 0, circle.radius); 61 gradient2.addColorStop(0, 'hsla(' + circle.hue + ', 100%, 50%, 0)'); 62 gradient2.addColorStop(.1, 'hsla(' + circle.hue + ', 100%, 100%, .7)'); 63 gradient2.addColorStop(1, 'hsla(' + circle.hue + ', 100%, 50%, 0)'); 64 65 ctx.strokeStyle = gradient2; 66 ctx.stroke(); 67 ctx.restore(); 68 }, 69 //弧線頂點發亮 70 renderCircleFlare = function () { 71 ctx.save(); 72 ctx.translate(circle.x, circle.y); 73 ctx.rotate(dToR(circle.rotation + 185)); 74 ctx.scale(1, 1); 75 ctx.beginPath(); 76 ctx.arc(0, circle.radius, 30, 0, Math.PI * 2, false); 77 ctx.closePath(); 78 var gradient3 = ctx.createRadialGradient(0, circle.radius, 0, 0, circle.radius, 30); 79 gradient3.addColorStop(0, 'hsla(330, 50%, 50%, .35)'); 80 gradient3.addColorStop(1, 'hsla(330, 50%, 50%, 0)'); 81 ctx.fillStyle = gradient3; 82 ctx.fill(); 83 ctx.restore(); 84 }, 85 //發亮延伸 86 renderCircleFlare2 = function () { 87 ctx.save(); 88 ctx.translate(circle.x, circle.y); 89 ctx.rotate(dToR(circle.rotation + 165)); 90 ctx.scale(1.5, 1); 91 ctx.beginPath(); 92 ctx.arc(0, circle.radius, 25, 0, Math.PI * 2, false); 93 ctx.closePath(); 94 var gradient4 = ctx.createRadialGradient(0, circle.radius, 0, 0, circle.radius, 25); 95 gradient4.addColorStop(0, 'hsla(30, 100%, 50%, .2)'); 96 gradient4.addColorStop(1, 'hsla(30, 100%, 50%, 0)'); 97 ctx.fillStyle = gradient4; 98 ctx.fill(); 99 ctx.restore(); 100 }, 101 //建立亮點 102 createParticles = function () { 103 if (particles.length < particleMax) { 104 particles.push({ 105 x: (circle.x + circle.radius * Math.cos(dToR(circle.rotation - 85))) + (rand(0, circle.thickness * 2) - circle.thickness), 106 y: (circle.y + circle.radius * Math.sin(dToR(circle.rotation - 85))) + (rand(0, circle.thickness * 2) - circle.thickness), 107 vx: (rand(0, 100) - 50) / 1000, 108 vy: (rand(0, 100) - 50) / 1000, 109 radius: rand(1, 6) / 2, 110 alpha: rand(10, 20) / 100 111 }); 112 } 113 }, 114 //更新已有亮點的座標用於動態更隨展現 115 //同時下降透明度,刪除透明度太低(先建立的點調用該函數的次數最多,也就最容易變低)的亮點。 116 updateParticles = function () { 117 var i = particles.length; 118 while (i--) { 119 var p = particles[i]; 120 p.vx += (rand(0, 100) - 50) / 750; 121 p.vy += (rand(0, 100) - 50) / 750; 122 p.x += p.vx; 123 p.y += p.vy; 124 p.alpha -= .01; 125 126 if (p.alpha < .02) { 127 particles.splice(i, 1) 128 } 129 } 130 }, 131 renderParticles = function () { 132 var i = particles.length; 133 while (i--) { 134 var p = particles[i]; 135 ctx.beginPath(); 136 ctx.fillRect(p.x, p.y, p.radius, p.radius); 137 ctx.closePath(); 138 ctx.fillStyle = 'hsla(0, 0%, 100%, ' + p.alpha + ')'; 139 } 140 }, 141 clear = function () { 142 ctx.globalCompositeOperation = 'destination-out'; 143 ctx.fillStyle = 'rgba(0, 0, 0, .1)'; 144 ctx.fillRect(0, 0, cw, ch); 145 ctx.globalCompositeOperation = 'lighter'; 146 } 147 loop = function () { 148 clear(); 149 updateCircle(); 150 renderCircle(); 151 renderCircleBorder(); 152 renderCircleFlare(); 153 renderCircleFlare2(); 154 createParticles(); 155 updateParticles(); 156 renderParticles(); 157 } 158 159 160 ctx.shadowBlur = circle.blur; 161 ctx.shadowColor = 'hsla(' + circle.hue + ', 80%, 60%, 1)'; 162 ctx.lineCap = 'round'; 163 164 setInterval(loop, 20);
本篇沒有什麼內容,只是一個簡單應用。
其實在上篇狀態的保存和恢復中那個示例就是一個簡單動畫了。
其實HTML5中動畫也不算難,簡單說就是畫圖+定時刷新,因此重點仍是在HTML5 APIs的應用及與其餘現有技術的交叉使用。