d
k
p
l
u
s

canvas动画3:交互

canvas动画3

时隔很久,本人终于又写博客了(重度拖延症),把之前留下的canvas交互动画讲一讲。

电脑上的交互,指的是鼠标和键盘,我们今天主要用的是鼠标。

既然是鼠标的话,就要获取鼠标的各种事件,这次以mousemove做示例。

我们先定义一个鼠标对象,然后添加mousemove事件:

var mouse = {
    x: undefined,
    y: undefined
}
//这样的话控制台就会跟随我们的鼠标移动输出相应的坐标
window.addEventListener("mousemove",function (event) {
    mouse.x = event.x;
    mouse.y = event.y;
    console.log(mouse);
});

我们声明一个初始化函数init(),用于把制造圆的过程封装:

function init() {
    circleArray = []
    for (var i = 0; i < 800; i++) {
        var x = Math.random()*window.innerWidth;
        var y = Math.random()*window.innerHeight;
        var dx = (Math.random()-0.5)*2;
        var dy = (Math.random()-0.5)*2;
        var radius = Math.random()*3 +1;
        circleArray.push(new Circle(x, y, dx, dy, radius));
    }
}
init();

这样的话,按照上一篇文章的做法,我们的canvas会出现一些问题。所以,需要给Circle对象update()里的属性都加上this

function Circle(x, y, dx, dy, radius) {
    this.x = x;
    this.y = y;
    this.dx = dx;
    this.dy = dy;
    this.radius = radius;

    this.draw = function() {
        ctx.beginPath();
        ctx.strokeStyle = "#000";
        ctx.arc(this.x,this.y,this.radius,Math.PI/180*0,Math.PI/180*360,false);
        ctx.stroke();
        ctx.fill();
    }
    this.update = function() {
        //圆触碰边界时反弹,偏移值为负
        if (this.x + this.radius > innerWidth || this.x - this.radius < 0 ) {
            this.dx = -this.dx;
        }
        if (this.y + this.radius > innerHeight || this.y - this.radius < 0 ) {
            this.dy = -this.dy;
        }
        //刷新绘制时圆的偏移运动
        this.x += this.dx;
        this.y += this.dy;
        //根据更新的值进行绘制
        this.draw();

    }
}

接下来我们就要用mousemove于动画进行交互了,我们假定圆心在鼠标坐标周围50px以内的时候圆会增大,这段代码应该写在update()里:

if (mouse.x - this.x < 50 && mouse.x - this.x >-50 && mouse.y - this.y < 50 && mouse.y - this.y >-50) {
    // if (this.radius < maxRadius) {
        this.radius += 1;
    // }
}
我们设置了10个圆,把鼠标移上去的时候会看到在控制范围内的圆会不断变大,不会停下来,所以我在前面就设置了一个圆半径的最大值,以免它一直增大,然后把注释的内容去掉,圆就不会无限增大了:

但是有一个问题,圆放大了以后不会缩小,那么我们就让它在离开圆50px半径范围后缩小:

if (mouse.x - this.x < 50 && mouse.x - this.x >-50 && mouse.y - this.y < 50 && mouse.y - this.y >-50) {
    if (this.radius < maxRadius) {
        this.radius += 1;
    }
//其他的所有圆半径不断减小
}else{
    this.radius -= 1;
}

这时候又有新问题产生了,画面一片空白,因为圆心不在鼠标固定范围内的圆全都变小了,甚至半径为负!显然简单的else是不成立的,还是得加个条件:

if (mouse.x - this.x < 50 && mouse.x - this.x >-50 && mouse.y - this.y < 50 && mouse.y - this.y >-50) {
    if (this.radius < maxRadius) {
        this.radius += 1;
    }
//其他的所有圆半径减小到最小值
}else if (this.radius > this.minRadius) {
    this.radius -= 1;
}

这里出现了一个新值:minRadius,我加在了Circle对象里this.minRadius = radius;,以原本的初始值作为它的最小值。好了,现在基本效果已经成型了:

接下来就是颜色的问题了,只要懂得canvas的基本api,修改颜色完全就是小儿科。我们设置一个数组,用于存放颜色值。

var colorArray = [
    '#58D68D',
    '#E67F22',
    '#3598DB',
    '#E84C3D',
    '#9A59B5',
    '#27AE61',
    '#D25400',
    '#BEC3C7',
    '#297FB8'
]

然后在Circle对象里加上一个bg属性:this.bg = colorArray[Math.floor(Math.random()*colorArray.length)];,再往Circle的绘制函数添上一句ctx.fillStyle = this.bg;,然后ctx.fill();,多彩运动的圆圈canvas就做完了。

这是一个运用mousemove事件做的canvas交互动画,有兴趣的可以尝试其他事件(制作游戏用的键盘事件以及其他鼠标事件),或者思考如何给球加重力,如何检测碰撞事件,canvas的世界并不只有这么一点,相关资料的话,给大家推荐本书《canvas开发详解》。

本文的最终js代码如下:

/**
 * 
 * @authors dkplus (dkplus@qq.com)
 * @date    2017-10-01 20:37:26
 * @version $1.0$
 */
/**
 * 获取canvas对象,设置宽度高度自适应
 * @type {[type]}
 */
var canvas = document.querySelector("#canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

var ctx = canvas.getContext("2d");
/**
 * 屏幕鼠标坐标
 * @type {Object}
 */
var mouse = {
    x: undefined,
    y: undefined
}
/**
 * @param  {鼠标移动事件,回调函数,赋值给鼠标坐标}
 * @return {[type]}
 */
window.addEventListener("mousemove",function (event) {
    mouse.x = event.x;
    mouse.y = event.y;
    // console.log(mouse);
});
/**
 * @param  {重新设置窗口大小,使canvas宽高自适应屏幕}
 * @return {[type]}
 */
window.addEventListener("resize",function () {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    //初始化canvas
    init();
})
//绘制圆的最大半径
var maxRadius = 40;
// var minRadius = 2;

//圆的颜色数组
var colorArray = [
    '#58D68D',
    '#E67F22',
    '#3598DB',
    '#E84C3D',
    '#9A59B5',
    '#27AE61',
    '#D25400',
    '#BEC3C7',
    '#297FB8'
]
/**
 * @param {x圆中心的x坐标}
 * @param {y圆中心的y坐标}
 * @param {dx圆运动的x偏移量}
 * @param {dy圆运动的y偏移量}
 * @param {radius圆的半径}
 * minRadius圆的最小半径
 * bg圆的背景颜色
 * draw绘制函数
 * update圆运动偏移
 */
function Circle(x, y, dx, dy, radius) {
    this.x = x;
    this.y = y;
    this.dx = dx;
    this.dy = dy;
    this.radius = radius;
    this.minRadius = radius;
    this.bg = colorArray[Math.floor(Math.random()*colorArray.length)];

    this.draw = function() {
        ctx.beginPath();
        ctx.strokeStyle = "#777";
        ctx.fillStyle = this.bg;
        ctx.arc(this.x,this.y,this.radius,Math.PI/180*0,Math.PI/180*360,false);
        // ctx.stroke();
        ctx.fill();
    }
    this.update = function() {
        //圆触碰边界时反弹,偏移值为负
        if (this.x + this.radius > innerWidth || this.x - this.radius < 0 ) {
            this.dx = -this.dx;
        }
        if (this.y + this.radius > innerHeight || this.y - this.radius < 0 ) {
            this.dy = -this.dy;
        }
        //刷新绘制时圆的偏移运动
        this.x += this.dx;
        this.y += this.dy;
        //鼠标半径50像素范围内的圆,它们的半径逐步增加到最大值
        if (mouse.x - this.x < 50 && mouse.x - this.x >-50 && mouse.y - this.y < 50 && mouse.y - this.y >-50) {
            if (this.radius < maxRadius) {
                this.radius += 1;
            }
        //其他的所有圆半径减小到最小值
        }else if (this.radius > this.minRadius) {
            this.radius -= 1;
        }
        //根据更新的值进行绘制
        this.draw();

    }
}
//圆的对象数组
var circleArray = [];
/**
 * 初始化函数,制造800个随机坐标、偏移速度和半径的圆,加入到对象数组
 * @return {[type]}
 */
function init() {
    circleArray = []
    for (var i = 0; i < 800; i++) {
        var x = Math.random()*window.innerWidth;
        var y = Math.random()*window.innerHeight;
        var dx = (Math.random()-0.5)*2;
        var dy = (Math.random()-0.5)*2;
        var radius = Math.random()*3 +1;
        circleArray.push(new Circle(x, y, dx, dy, radius));
    }
}
init();
/**
 * 动画函数
 * @return {[type]}
 */
function animate() {
    //更新前清楚画布
    ctx.clearRect(0,0,window.innerWidth,window.innerHeight);
    requestAnimationFrame(animate);
    //每个圆都调用update()方法
    for (var i = 0; i < circleArray.length; i++) {
        circleArray[i].update();
    }

}
animate();
posted @ 2017-11-23 22:55  dkplus  阅读(4160)  评论(21编辑  收藏  举报