成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

用canvas畫一輪明月,夜空與流星

VioletJack / 2319人閱讀

摘要:今天是中秋節(jié),于是突發(fā)奇想,欸不如用來畫一畫月亮吧。徑向漸變這是月亮的類,主要用到了里的徑向漸變效果。然后整體傾角度,并且填充時(shí)用上一個(gè)徑向漸變,就可以相當(dāng)完美的達(dá)到流行尾巴那樣漸行漸遠(yuǎn)漸模糊的樣子。

今天是中秋節(jié),于是突發(fā)奇想,欸不如用canvas來畫一畫月亮吧。

于是一副用canvas畫出的星空就這樣誕生了。

Demo

在這里我用了ES6語法,星星,月亮和流星都多帶帶寫成了一個(gè)module。

于是我把js一共分成這四個(gè)文件:main.js, Moon.js, Stars.js和Meteor.js,后面三個(gè)各自export出一個(gè)類。

源碼

為了方便,用了gulp做自動(dòng)化的工具。

main.js
import Stars    from "./Stars"
import Moon     from "./Moon"
import Meteor   from "./Meteor"

let canvas = document.getElementById("canvas"),
    ctx = canvas.getContext("2d"),
    width = window.innerWidth,
    height = window.innerHeight,
    //實(shí)例化月亮和星星。流星是隨機(jī)時(shí)間生成,所以只初始化數(shù)組
    moon = new Moon(ctx, width, height),
    stars = new Stars(ctx, width, height, 200),
    meteors = [],
    count = 0

canvas.width = width
canvas.height = height

//流星生成函數(shù)
const meteorGenerator = ()=> {
    //x位置偏移,以免經(jīng)過月亮
    let x = Math.random() * width + 800
    meteors.push(new Meteor(ctx, x, height))

    //每隔隨機(jī)時(shí)間,生成新流星
    setTimeout(()=> {
        meteorGenerator()
    }, Math.random() * 2000)
}

//每一幀動(dòng)畫生成函數(shù)
const frame = ()=> {
    //每隔10幀星星閃爍一次,節(jié)省計(jì)算資源
    count++
    count % 10 == 0 && stars.blink()

    moon.draw()
    stars.draw()

    meteors.forEach((meteor, index, arr)=> {
        //如果流星離開視野之內(nèi),銷毀流星實(shí)例,回收內(nèi)存
        if (meteor.flow()) {
            meteor.draw()
        } else {
            arr.splice(index, 1)
        }
    })
    requestAnimationFrame(frame)
}

meteorGenerator()
frame()

開頭分別引入了另外三個(gè)module,分別是星星,月亮和流星。

接著初始化了月亮和星星,但由于流星是不定時(shí)隨機(jī)生成的,所以初始化一個(gè)數(shù)組用來保存接下來生成的流星。

在每一幀中,分別調(diào)用moon,star和meteor的draw函數(shù),用來畫出每一幀,特別的,因?yàn)樾切切枰W爍,流星需要移動(dòng),所以在draw之前對(duì)半徑和坐標(biāo)進(jìn)行處理。如果流星跑出了canvas外,就從數(shù)組中清除相應(yīng)的流星,從而解除引用和回收內(nèi)存。

Moon.js
export default class Moon {
    constructor(ctx, width, height) {
        this.ctx = ctx
        this.width = width
        this.height = height
    }

    draw() {
        let ctx = this.ctx,
            gradient = ctx.createRadialGradient(
            200, 200, 80, 200, 200, 800)
        //徑向漸變
        gradient.addColorStop(0, "rgb(255,255,255)")
        gradient.addColorStop(0.01, "rgb(70,70,80)")
        gradient.addColorStop(0.2, "rgb(40,40,50)")
        gradient.addColorStop(0.4, "rgb(20,20,30)")
        gradient.addColorStop(1, "rgb(0,0,10)")
        ctx.save()
        ctx.fillStyle = gradient
        ctx.fillRect(0, 0, this.width, this.height)
        ctx.restore()
    }
}

這是月亮的類,主要用到了canvas里的徑向漸變效果。為了達(dá)到和諧的程度,我試了好久T_T...

Stars.js
export default class Stars {
    constructor(ctx, width, height, amount) {
        this.ctx = ctx
        this.width = width
        this.height = height
        this.stars = this.getStars(amount)
    }

    getStars(amount) {
        let stars = []
        while (amount--) {
            stars.push({
                x: Math.random() * this.width,
                y: Math.random() * this.height,
                r: Math.random() + 0.2
            })
        }
        return stars
    }

    draw() {
        let ctx = this.ctx
        ctx.save()
        ctx.fillStyle = "white"
        this.stars.forEach(star=> {
            ctx.beginPath()
            ctx.arc(star.x, star.y, star.r, 0, 2 * Math.PI)
            ctx.fill()
        })
        ctx.restore()
    }

    //閃爍,星星半徑每隔10幀隨機(jī)變大或變小
    blink() {
        this.stars = this.stars.map(star=> {
            let sign = Math.random() > 0.5 ? 1 : -1
            star.r += sign * 0.2
            if (star.r < 0) {
                star.r = -star.r
            } else if (star.r > 1) {
                star.r -= 0.2
            }
            return star
        })

    }
}

星星的集合。因?yàn)椴恢劣诮o每一個(gè)星星都寫成多帶帶的對(duì)象,于是就寫了一個(gè)星星的集合類,所有的星星都保存在實(shí)例的stars中。其中的blink函數(shù)用來隨機(jī)改變每一個(gè)星星的半徑大小,從而產(chǎn)生閃爍的效果。

Meteor.js
export default class Meteor {
    constructor(ctx, x, h) {
        this.ctx = ctx
        this.x = x
        this.y = 0
        this.h = h
        this.vx = -(4 + Math.random() * 4)
        this.vy = -this.vx
        this.len = Math.random() * 300 + 500
    }

    flow() {
        //判定流星出界
        if (this.x < -this.len || this.y > this.h + this.len) {
            return false
        }
        this.x += this.vx
        this.y += this.vy
        return true
    }

    draw() {
        let ctx = this.ctx,
            //徑向漸變,從流星頭尾圓心,半徑越大,透明度越高
            gra = ctx.createRadialGradient(
                this.x, this.y, 0, this.x, this.y, this.len)

        const PI = Math.PI
        gra.addColorStop(0, "rgba(255,255,255,1)")
        gra.addColorStop(1, "rgba(0,0,0,0)")
        ctx.save()
        ctx.fillStyle = gra
        ctx.beginPath()
        //流星頭,二分之一圓
        ctx.arc(this.x, this.y, 1, PI / 4, 5 * PI / 4)
        //繪制流星尾,三角形
        ctx.lineTo(this.x + this.len, this.y - this.len)
        ctx.closePath()
        ctx.fill()
        ctx.restore()
    }
}

流星就比較有意思啦。猜猜每一個(gè)流星是怎么畫的?

實(shí)際上每一個(gè)流星的輪廓由一個(gè)半圓和一個(gè)三角形組成,類似于一個(gè)不倒翁。然后整體傾角45度,并且填充時(shí)用上一個(gè)徑向漸變,就可以相當(dāng)完美的達(dá)到流行尾巴那樣漸行漸遠(yuǎn)漸模糊的樣子。

對(duì),就是這么干凈利落~

最后看了一下CPU和GPU的占用,還好,優(yōu)化的還比較到位,我那渣族手機(jī)都能跑的很流暢...

今天是中秋節(jié),可惜我這下雨了...沒月亮可看...

不過我有了這個(gè)月亮。

“但愿人長久,千里共嬋娟”,千里之外的朋友,看到同一輪“明月”,也是緣分吧~

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/87906.html

相關(guān)文章

  • 撩妹技能 get,教你 canvas 一場流星

    摘要:現(xiàn)在就一起來做一場流星雨,用程序員的野路子浪漫一下。要畫一場流星雨,首先,自然我們要會(huì)畫一顆流星。畫一顆流星是的,的卻是沒這個(gè),但是不代表我們畫不出來。而我們每一幀要保留的就是,上一幀透明度的流星,覆蓋畫布黑色矩形我們不能顯示。 開始 妹子都喜歡流星,如果她說不喜歡,那她一定是一個(gè)假妹子。 現(xiàn)在就一起來做一場流星雨,用程序員的野路子浪漫一下。 要畫一場流星雨,首先,自然我們要會(huì)畫一顆流...

    cc17 評(píng)論0 收藏0
  • 一個(gè)Vue+Canvas的酷炫后臺(tái)管理

    摘要:又一個(gè)酷炫的后臺(tái)管理,依然前后端分離用打開,還沒適配移動(dòng)端。如果覺得還行,歡迎項(xiàng)目地址項(xiàng)目后臺(tái)地址我的博客地址好了,溜了溜了。。。 又一個(gè)Vue+Cnavas酷炫的后臺(tái)管理,依然前后端分離(用PC打開,還沒適配移動(dòng)端)。 項(xiàng)目地址: https://github.com/hzzly/canv...demo地址: http://hjingren.cn/curriculum...賬號(hào):hz...

    harriszh 評(píng)論0 收藏0
  • Codepen 每日精選(2018-3-31)

    摘要:按下右側(cè)的點(diǎn)擊預(yù)覽按鈕可以在當(dāng)前頁面預(yù)覽,點(diǎn)擊鏈接可以打開原始頁面。 按下右側(cè)的點(diǎn)擊預(yù)覽按鈕可以在當(dāng)前頁面預(yù)覽,點(diǎn)擊鏈接可以打開原始頁面。 制作像素畫的畫板https://codepen.io/abeatrize/... 純 css 畫的晚上的風(fēng)車https://codepen.io/miocene/fu... 純 css 畫的可愛貓頭鷹https://codepen.io/mali_...

    馬龍駒 評(píng)論0 收藏0
  • Codepen 每日精選(2018-3-31)

    摘要:按下右側(cè)的點(diǎn)擊預(yù)覽按鈕可以在當(dāng)前頁面預(yù)覽,點(diǎn)擊鏈接可以打開原始頁面。 按下右側(cè)的點(diǎn)擊預(yù)覽按鈕可以在當(dāng)前頁面預(yù)覽,點(diǎn)擊鏈接可以打開原始頁面。 制作像素畫的畫板https://codepen.io/abeatrize/... 純 css 畫的晚上的風(fēng)車https://codepen.io/miocene/fu... 純 css 畫的可愛貓頭鷹https://codepen.io/mali_...

    PascalXie 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<