Canvas星空效果(JS面向对象)

概述

更多Canvas实例可以看GitHub,不定时更新:https://github.com/xiangshuo1992/canvas-demo
这里写图片描述
这个Demo主要有以下几点可以讨论:
1.HTML5 canvas的基础API,如 context.beginPath();
2.获取屏幕大小,并响应窗口大小变化
3.JS面向对象

先看效果 Canvas星空效果

代码实现

HTML

<canvas id="canvas"></canvas>

CSS

#canvas {
     position: absolute;
     left: 0;
     top: 0;
     background-color: #000;
 }

JS

<script>
    /** 
     * canvas 创建星空
     */

    // 定义变量
    let canvas,
        context,
        screenW,
        screenH,
        stars = [];

    // 定义常量
    const FPS = 50,
        numStars = 2000;

    window.onload = function () {
        //获取canvas
        canvas = document.getElementById('canvas');
        // 设置画布大小
        render();
        //获取canvas执行上下文
        context = canvas.getContext('2d');
        // ===========组件应用层============
        //创建星星
        for (let i = 0; i < numStars; i++) {
            let x = Math.round(Math.random() * screenW);
            let y = Math.round(Math.random() * screenH);
            let length = 1 + Math.random() * 2;
            let opacity = Math.random();

            // 创建星星实例
            let star = new Star(x, y, length, opacity);
            stars.push(star);
        }

        // 星星闪动
        setInterval(animate, 1000 / FPS);
    }

    // ============组件定制层==============
    /**
     * Star
     * 
     * @param int x
     * @param int y
     * @param int length
     * @param float opacity
     */

    // 星星构造函数
    function Star(x, y, length, opacity) {
        this.x = parseInt(x);
        this.y = parseInt(y);
        this.length = parseInt(length);
        this.opacity = opacity;
        this.factor = 1;
        this.increment = Math.random() * 0.03;
    }

    //对象原型方法
    /**
     * 画星星
     * 
     * @param context
     */
    Star.prototype.draw = function (context) {
        context.rotate(Math.PI * 1 / 10);

        //save the context
        context.save();
        //move into the middle of the canvas,just make room
        context.translate(this.x, this.y);
        //change the opacity
        if (this.opacity > 1) {
            this.factor = -1;
        } else if (this.opacity <= 0) {
            this.factor = 1;

            // 更新一次星星位置
            this.x = Math.round(Math.random() * screenW);
            this.y = Math.round(Math.random() * screenH);
        }

        // factor 控制方向,淡入或淡出,每次重绘,星星的透明度都在变化
        this.opacity += this.increment * this.factor;

        context.beginPath();
        //画线
        for (var i = 5; i > 0; i--) {
            context.lineTo(0, this.length);
            context.translate(0, this.length);
            context.rotate(Math.PI * 2 / 10);
            context.lineTo(0, -this.length);
            context.translate(0, -this.length);
            context.rotate(-(Math.PI * 6 / 10));
        }

        context.lineTo(0, this.length);
        context.closePath();

        context.fillStyle = 'rgba(255,255,200, ' + this.opacity + ')';
        context.shadowBlur = 5;
        context.shadowColor = '#ffff33';
        context.fill();

        context.restore();
    }

    /**
     * 获取窗口大小信息
     */
    function getScreenInfo() {
        //获取窗口宽度
        if (window.innerWidth) {
            winWidth = window.innerWidth;
        } else if ((document.body) && (document.body.clientWidth)) {
            winWidth = document.body.clientWidth;
        }

        //获取窗口高度
        if (window.innerHeight) {
            winHeight = window.innerHeight;
        } else if ((document.body) && (document.body.clientHeight)) {
            winHeight = document.body.clientHeight;
        }

        //通过深入Document内部对body进行检测,获取窗口大小
        if (document.documentElement &&
            document.documentElement.clientHeight &&
            document.documentElement.clientWidth) {
            winHeight = document.documentElement.clientHeight;
            winWidth = document.documentElement.clientWidth;
        }

        // 将上述方法简化
        // screenW = window.innerWidth ||
        //     document.body.clientWidth ||
        //     document.documentElement.clientWidth;

        // screenH = window.innerHeight ||
        //     document.body.clientHeight ||
        //     document.documentElement.clientHeight;

        return {
            'winWidth': winWidth,
            'winHeight': winHeight
        }
    }

    /**
     * canvas设置,修复窗口变化,画布大小不变的问题
     */
    function render() {
        //获取屏幕大小
        screenW = getScreenInfo().winWidth;
        screenH = getScreenInfo().winHeight;

        // 设置canvas
        // canvas.setAttribute('width', screenW);
        // canvas.setAttribute('height', screenH);

        canvas.width = screenW;
        canvas.height = screenH;

        window.addEventListener('resize', render);
    }

    /**
     * 星星闪动函数
     */
    function animate() {
        context.clearRect(0, 0, screenW, screenH);
        for (let i = 0; i < stars.length; i++) {
            stars[i].draw(context);
        }
    }
</script>

HTML5 Canvas基础API(只列举用到的)

 //获取canvas
 canvas = document.getElementById('canvas');
 //获取canvas执行上下文
 context = canvas.getContext('2d');
 //用于保存当前绘图环境
 context.save();
 //用户恢复最近一次的绘图环境
 context.restore();
 //开始一段新的路径绘图
 context.beginPath();
 //结束当前路径绘图
 context.closePath();
 //绘制起点到(x,y)点的直线
 context.lineTo(x, y);
 //当前绘图环境位移,水平X,垂直y
 context.translate(x, y);
 //当前绘图环境旋转angle度(弧度制)degree * Math.PI / 180
 context.rotate(angle);
 //设置或返回用于填充绘画的颜色、渐变或模式
 context.fillStyle;
 //填充当前绘图(路径)
 context.fill()
 //设置或返回用于阴影的模糊级别
 context.shadowBlur
 //设置或返回用于阴影的颜色
 context.shadowColor

获取屏幕大小并监听

监听窗口/文档大小变化事件,保证canvas铺满屏幕

function render() {
    //获取屏幕大小
    screenW = window.innerWidth ||
        document.body.clientWidth ||
        document.documentElement.clientWidth;

    screenH = window.innerHeight ||
        document.body.clientHeight ||
        document.documentElement.clientHeight;

    // 设置canvas大小
    // canvas.setAttribute('width', screenW);
    // canvas.setAttribute('height', screenH);

    canvas.width = screenW;
    canvas.height = screenH;

    window.addEventListener('resize', render);
}

JS面向对象写法

//构造函数(类)
function Star(config){this.config = config;}
//给类添加方法,JS用原型实现
Star.prototype.draw = function () { /*do something*/}
//实例化一个Star对象
let star = new Star(config)

当然这个对象写的不是很好,应该可以拆分出更细的一些操作放到原型上。

这里我把对象当组件来看,其实面向对象可能是组件化的一个过程。我们将面向对象的写法理解成组件化的过程可以这样理解:

============组件定制层==============
创建对象——>创建组件
对象属性——>组件配置属性
对象方法——>组件方法

============组件应用层==============
实例化对象——>实例化组件

之所以给组件分层,是因为除了基本的应用和定制层,一般组件还会有组件核心(基础)层
=========组件核心(基础)层==========
jQuery/Vue/…

ES6

const/let

// 定义变量
let canvas,
    context,
    screenW,
    screenH,
    stars = [];

// 定义常量
const FPS = 50,
    numStars = 2000;

箭头函数

//ES6定义函数
let fn = (param)=> { /*do something*/ }
//相当于
var fn = function(param){ /*do something*/ }

总结

纸上得来终觉浅,绝知此事要躬行!——《冬夜读书示子聿》陆游

猜你喜欢

转载自blog.csdn.net/u013778905/article/details/79978440