由於最近課比較少,因此在codepen上逛的時間比較多,藉此能夠學習一些優秀的做品,昨天看到了一個很炫的星空,先給你們看看效果。css
源碼出奇的短,總共不過一百餘行,代碼的邏輯也寫的淺顯易懂,主要思路就是不一樣軌道的星星繞着中心點旋轉,其次就是半徑越大的星星在視覺上距離咱們越近,由於中心點是最遠點,因此最遠點應該旋轉的速率最快,越清晰,更大。讀這段代碼的時候,並無花費不少時間,初讀的時候仍是停留在邏輯層面。前端
// Thanks @jackrugile for the performance tip! https://codepen.io/jackrugile/pen/BjBGoM // Cache gradientcanvas
咱們再引用一下注釋下面的代碼緩存
var canvas2 = document.createElement('canvas'),
ctx2 = canvas2.getContext('2d');
canvas2.width = 100;
canvas2.height = 100;
var half = canvas2.width/2,
gradient2 = ctx2.createRadialGradient(half, half, 0, half, half, half);
gradient2.addColorStop(0.025, '#fff');
gradient2.addColorStop(0.1, 'hsl(' + hue + ', 61%, 33%)');
gradient2.addColorStop(0.25, 'hsl(' + hue + ', 64%, 6%)');
gradient2.addColorStop(1, 'transparent');
ctx2.fillStyle = gradient2;
ctx2.beginPath();
ctx2.arc(half, half, half, 0, Math.PI * 2);
ctx2.fill();
複製代碼
這段代碼的意思是在新的canvas 裏畫漸變,對應的是天上的星星。結合做者的註釋,目的就是將不變的元素放在一個離屏的canvas裏,而後在主canvas裏經過drawImage裏引用,以此減小繪製。也是性能調優的一個策略,其實對稍微有點經驗的同窗來講,這也是很普通的技巧了,這裏特意拿出來,也是但願能給新同窗一點建議。dom
我相信大多數前端愛好者都是和我同樣,本碩都是計算機,對色彩沒有理解,往深處分析了一下做者的代碼,有不少頗有意思的trick,你能感覺到做者頗有意思的想象力。性能
星星是會閃爍的,怎麼突出星星的閃爍呢? canvas裏 有shadowBlur的屬性,相似css裏的box-shadow,固然能夠用這種方法來突出閃爍,可是這樣的效果並很差!做者的方法很巧妙。做者的思路是用徑向漸變,放上代碼。學習
gradient2 = ctx2.createRadialGradient(half, half, 0, half, half, half);
gradient2.addColorStop(0.025, '#fff');
gradient2.addColorStop(0.1, 'hsl(' + hue + ', 61%, 33%)');
gradient2.addColorStop(0.25, 'hsl(' + hue + ', 64%, 6%)');
gradient2.addColorStop(1, 'transparent');
複製代碼
我的以爲這段代碼真是神來之筆,這裏還有一個點,就是做者對body背景色的設置動畫
body {
background: #060e1b;
overflow: hidden;
}
複製代碼
這裏把 #060e1b 轉化成hsl(217, 64%, 6%) 包括後面做者fillRect清屏的時候,填充色也是選擇 hsl(217, 64%, 6%)。這個顏色正是漸變色的第三種顏色。this
咱們如今來分析做者爲何要分別選取這漸變的四種顏色呢? 從上往下分別是spa
#fff 白色
hsl(217, 61%, 33%) 墨藍 夜裏的天空
hsl(217, 61%, 6%) 更墨的藍 由於亮度減小了
rgba(0,0,0,0) //注意注意,原來transparent裏的色值是 rgba(0,0,0,0);
複製代碼
第一種顏色白色很好理解,是星星的光,第二種顏色是明亮的背景色,第三種由於光少了,因此暗了,最後逐漸變深。 不少人會說最後的rgba(0,0,0,0)有什麼用?
這裏要結合後面部分的代碼來看
ctx.globalCompositeOperation = 'source-over';
ctx.globalAlpha = 0.8;
ctx.fillStyle = 'hsla(' + hue + ', 64%, 6%, 1)';
ctx.fillRect(0, 0, w, h)
ctx.globalCompositeOperation = 'lighter';
複製代碼
這樣就茅塞對開了,做者用了hsla(' + hue + ', 64%, 6%, 1) 平鋪背景後,用了globalCompositeOperation = 'lighter' 讓星星和背景的顏色融合,這樣最後因爲transparent 就徹底融入了背景。
而在 hsl(217, 61%, 6%) -> rgba(0,0,0,0) 的變化呢?
咱們把 hsl(217, 61%, 6%) 轉換成rgb爲 rgb(6, 14, 25) 這個和 rgba(0,0,0) 很接近呀,肉眼看不出來呀。
咱們放上 #fff -> rgba(0,0,0,0) 的過渡圖。
大體是變深色,而後變淺,由於最後是透明嗎,這裏就是對應底色了。因此咱們能夠得出 hsl(217, 61%, 6%) -> rgba(0,0,0,0) 的變化,就是深一點的背景色->背景色的變化,由於兩種顏色相近,真是區別不大。
做者在繪製開頭用了 ctx.globalCompositeOperation = 'source-over'; 來避免星星過多,過亮,用了 ctx.globalAlpha = 0.8 來平鋪背景色,讓有星星的幀,會有一點餘光透過去,好像星星變暗了,都是很棒的想法。
因此之後咱們要作閃爍的物體能夠參照上面的方法,好比煙火,激光之類的
受到啓發後,本身下午就寫了一個demo,仍是先上效果圖吧。
這裏發光的方案都是來自前面的方案,嘿嘿,做者感受蠻不錯的,有一種**‘黑黑的天空低垂,亮亮的繁星相隨’**的感受,好了給你們分析一下個人一些trick吧。這裏把一些不錯的的點給你們分享一下,由於這裏元素比較多,確定不能按照前面的代碼組織方式了。
個人組織方式
var Render = {
startCount: 100,
starList: [],
cacheCanvas: {}
init: () => {},
drawFigure: () => {}
}
var Star = () => {};
Star.prototype.draw = () => {}
複製代碼
其中 Render控制屏幕中的整個動畫,init 方法用於生成星星,草,路燈等。drawFigure用於作動畫,cancheCanvas 用於緩存不變的物體,好比星星等。
給你們看看我畫星星的方法吧,你們就明白了個人方案了,個人星星是橫向移動的,因此要考慮星星飛出屏幕的狀況,一旦飛出屏幕,要再補上星星。
生成星星
對應init方法
for (var i = 0; i < this.startCount; i++) {
this.starList.push(new Star(random(w), random(0, h), this.radius));
}
複製代碼
繪製星星
對應drawFigure方法
ctx.globalCompositeOperation = 'source-over';
ctx.globalAlpha = 0.8;
ctx.fillStyle = 'hsla(' + hue + ', 64%, 6%, 1)';
ctx.fillRect(0, 0, w, h);
ctx.globalCompositeOperation = 'lighter';
for (var i = 0; i < this.starList.length; i++) {
if (this.starList[i].draw()) { //星星超出邊界
this.starList.splice(i, 1);
this.starList.push(new Star(random(w), random(h), this.radius, 1));
}
}
複製代碼
星星的移動
對應star的draw方法
this.x = this.x + 0.5 * Math.random() * Math.random();
var twinkle = random(10);
if (twinkle === 1 && this.alpha < 0) {
this.alpha += 0.05;
}
if (twinkle === 2 && this.alpha > 1) {
this.alpha -= 0.05;
}
ctx.globalAlpha = this.alpha;
ctx.drawImage(Render.cacheCanvas.star, this.x - this.radius / 2, this.y - this.radius / 2, this.radius, this.radius);
return this.x > w || this.y > h ? true : false
複製代碼
動畫裏的草是貝塞爾曲線繪製的,這個沒有訣竅,只能本身一點點調,咱們要讓小草隨風搖擺這裏的訣竅是把畫布旋轉到小草的根部,而後旋轉畫布,貼出代碼。
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.theta);
ctx.globalCompositeOperation = 'source-over';
複製代碼
至於檯燈和月亮就是本身一點點畫,一點點調了,沒有捷徑。canvas就是一塊畫布,你能夠在上面發揮你的無盡想象力。課餘多逛逛codepen,學習一下別人優秀的做品,提升本身。