canvas-缤纷纸片

简介: 第一次用canvas绘图,其实难度是挺大的,基于js和一些数学知识,还有参考了网上很多的例子,最终完成了demo。

前言

第一次用canvas绘图,其实难度是挺大的,基于js和一些数学知识,还有参考了网上很多的例子,最终完成了demo。

效果如下:

![paper.gif-909.1kB][1] [1]: http://static.zybuluo.com/juanmao/bn8f0lluesbzqadn5tidi14y/paper.gif

调用代码



<html>
    <head>
        <meta charset="utf-8">
        <title>缤纷纸片</title>
        <style>
            body{
                background:url("img/background.jpg") no-repeat top;
            }
        </style>
    </head>
    <body>
        <div id="app"></div>
        <script src="./index.js"></script>
        <script>
             var a = new Paper({
                    param:{
                        width: 1024,//背景图的宽
                        height: 1344, //背景图的高
                    }
                })

        </script>
    </body>
    
</html>


源码讲解

好了,接下来讲解一下简单的实现原理 首先,先定义一些我们会用到的变量,和2个主要的对象。


/**
 * 设计思路:2个主要方法,Paper(),Process();
 * Paper()方法主要用于
 * 1.创建canvas实例,build();
 * 2.渲染canvas实例,render();
 * 
 * Process()方法主要是用于:计算进程,控制动画的状态。 
 * 我之前写过2种方式去绘制纸片,
 * 以前的是每一次都重新绘制纸片的样式,现在我把每一个纸片的样式都提前绘制好,
 * 放在一个sprites的数组里,以后的每一次渲染都不会重新绘制单个纸片了,只是回去改变这个纸片的位置和旋转角度
 */
 class Paper{
     constructor(){
        //定义一些默认的属性,后面会给出口子去修改
        this.CONST ={
            SPRITE_WIDTH: 120, //纸片宽
            SPRITE_HEIGHT: 120, //纸片高
            PAPER_LENGTH: 5,//纸片数量
            DURATION: 8000, 
            TRANSLATE_RATE: 50, //横行平移系数
            COLORS: [ //纸片的色彩值
            "#EF5350","#EC407A","#AB47BC","#7E57C2",
            "#5C6BC0","#42A5F5","#29B6F6","#26C6DA", 
            "#26A69A", "#66BB6A", "#9CCC65", "#D4E157", 
            "#FFEE58", "#FFCA28", "#FFA726", "#FF7043", 
            "#8D6E63", "#BDBDBD", "#78909C"]
        }
     }
 }


接下来把一些要用的变量全部定义好


class Paper{
      constructor({params}){
         // {...}
        //定义出需要用到的一些基础变量,还有传进来的一些参数
        //定义父元素,最基础canvas宽高,纸片数量,定位时y的范围,间隔时常,旋转角度,旋转速度
        const { elm,width,height,length,yRange,duration,rotationRange,speedRange} = params
        this.parent = document.getElementById(elm) || document.body; 
         //删除已有的canvas
        if(document.getElementsByTagName("canvas").length >0){
            this.canvas = null;
            this.parent.removeChild(parent.childNodes[0])
        }
        this.canvas = document.createElement("canvas"); 
        this.ctx = this.canvas.getContext("2d");
        this.width = width || this.parent.offsetWidth;
        this.height = height || this.parent.offsetHeight;
        this.length = length || this.CONST.PAPER_LENGTH;
        this.yRange = yRange || this.height * 2;
        //创建progress实例,将Progress的属性继承到Paper中的progress属性上。
        this.progress = new Progress({
            duration: duration||this.CONST.DURATION,
            isLoop: true
          });
        //旋转角度
        this.rotationRange = typeof rotationRange === "number" ? rotationRange : 0;
        //旋转速度
        this.speedRange = typeof speedRange === "number" ? speedRange : 1;
        //单个纸片canvas集合
        this.sprites = [];
        //设置最大canvas的样式
        this.canvas.style.cssText = ["display: block", "position: absolute", "top: 0",              "left: 0", "pointer-events: none"].join(";");
        //在页面上渲染出来
        this.parent.append(this.canvas);
      }  
    }

开始定义Paper里2个主要的方法:build(),render()


build(){
    for(let i=0; i<this.length;++i){ //循环要创建的纸片数量
            //生成每一个纸片的每一个小的cnavas
            let canvas = document.createElement("canvas"),
                ctx = canvas.getContext("2d");

            canvas.width = this.CONST.SPRITE_WIDTH; //定义的常量纸片的宽
            canvas.height = this.CONST.SPRITE_HEIGHT;//定义的常量纸片的高
            //定义基本的位置
            canvas.position = {
                initX: Math.random() * this.width,
                initY: -canvas.height - Math.random() * this.yRange
              };
        
            canvas.rotation = this.rotationRange / 2 - Math.random() * this.rotationRange; 
            canvas.speed = this.speedRange / 2 + Math.random() * (this.speedRange / 2);
            ctx.save();
            //随机的填充颜色
            ctx.fillStyle = this.CONST.COLORS[Math.random() * this.CONST.COLORS.length | 0];                 //随机数判断:圆形<1 ,四边形<2,剩下的生成圆形
            let random = Math.random()*3
            let random = 2
            if(random <1){ 
                ctx.arc(10, 10, 10, 0,Math.PI*2);
            }else if(random < 2){
                ctx.fillRect(0, 0, canvas.width, canvas.height);
            }else{
                ctx.moveTo(0,0);
                ctx.lineTo(0,20);
                ctx.lineTo(20,20);
                ctx.closePath()
            }
            ctx.fill();
            ctx.restore();
            this.sprites.push(canvas);
        }
}


render(){
    //核心代码
     for(let i = 0; i < this.length; ++i){
            this.ctx.save();
            /**
             * 纸片的初始位置x + 纸片旋转 * 常量平移*进程
             */
            this.ctx.translate(
                this.sprites[i].position.initX + this.sprites[i].rotation * this.CONST.TRANSLATE_RATE * progress, //添加到水平坐标(x)上的值
                this.sprites[i].position.initY + progress * (this.height + this.yRange));//添加到垂直坐标(y)上的值。
            this.ctx.rotate(this.sprites[i].rotation); //方法旋转当前的绘图。
            this.ctx.drawImage(
                this.sprites[i], //图像,画布或视频
                    -this.CONST.SPRITE_WIDTH * Math.abs(Math.sin(progress * Math.PI * 2 * this.sprites[i].speed)) / 2, //在画布上放置图像的 x 坐标位置。
                    //雪碧图的width * 
                    -this.CONST.SPRITE_HEIGHT / 2,//在画布上放置图像的 y 坐标位置。
                    this.CONST.SPRITE_WIDTH * Math.abs(Math.sin(progress * Math.PI * 2 * this.sprites[i].speed)), //可选。要使用的图像的宽度(伸展或缩小图像)
                    this.CONST.SPRITE_HEIGHT); //可选。要使用的图像的高度(伸展或缩小图像)。
            this.ctx.restore();
        }
}


接下来我们要定义另外一个主要的对象Progress


   class Progress{
     constructor(param){
         //定义默认时常,是否重复动画
        const {duration,isLoop} = param
        this.timestamp = null;
        this.duration = duration || 1000;
        this.progress = 0;
        this.delta = 0;
        this.progress = 0;
        this.isLoop = !!isLoop;
     }
 }


这个对象里有3个核心的方法


//重置时间戳
rest(){
    this.timestamp = null;
}
复制代码//记录重新开始的时间戳
start(now){
    this.timestamp = now;
}
复制代码tick(now){
    if (this.timestamp) {
        this.delta = now - this.timestamp;
        this.progress = Math.min(this.delta / this.duration, 1); //取最小值

        if (this.progress >= 1 && this.isLoop) {
             this.start(now);
        }
        return this.progress;
    } else {
        return 0;
    }
}

至此,已贴出了部分的核心代码,稍晚我会将全部的代码贴到我的github上,喜欢的小伙伴可以帮忙点个star~有错误的写法还需要小伙伴多多指出!谢谢~


分割线 更新于2018/6/29

最新更新 我已把这个项目弄在了npm上,大家可以去下载下来看到源码,也可以在项目中去调用。



    npm i bling-paper



原文发布时间为:2018年06月26日
原文作者: 我母鸡啊!
本文来源: 掘金  如需转载请联系原作者
相关文章
|
移动开发 前端开发 JavaScript
让自己也能使用Canvas
<canvas> 是 HTML5 新增的元素,可使用JavaScript脚本来绘制图形。例如:画图,合成照片,创建动画甚至实时视频处理与渲染。
让自己也能使用Canvas
|
14天前
|
XML 移动开发 前端开发
Canvas和SVG:你应该选择哪一个?
Canvas和SVG:你应该选择哪一个?
21 2
|
4月前
|
移动开发 前端开发 JavaScript
canvas详解00-认识canvas
canvas详解00-认识canvas
35 1
canvas详解00-认识canvas
|
12月前
|
存储 XML 前端开发
神奇的 Canvas
canvas是为了解决页面只能显示静态图片而出现的一种可以使用JavaScript绘制的HTML标签,它可以接受两个参数width和height(原来有三个,还有一个moz-opaque控制透明度,已经废弃了)
79 0
|
前端开发
用canvas画七巧板 -- 练习canvas
用canvas画七巧板 -- 练习canvas
92 0
|
前端开发
canvas做动画
canvas做动画
165 0
canvas做动画
|
移动开发 前端开发 小程序
Canvas 2D详解
Canvas 2D详解
Canvas 2D详解
|
前端开发 数据可视化 定位技术
canvas绘制飞线效果
canvas绘制飞线效果
canvas绘制飞线效果
fbh
|
前端开发 HTML5 移动开发
分享一个canvas代码2
学习HTML5 Canvas这一篇文章就够了 HTML5 Canvas粒子效果文字动画特效DEMO演示 展现地址:http://csdn.
fbh
842 0
fbh
|
Web App开发 前端开发
分享一个canvas代码
首先需要已入jquery 然后直接运行 function project3D(x,y,z,vars){var p,d;x-=vars.
fbh
1020 0