博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
canvas 鼠标点击出现烟花效果
阅读量:5900 次
发布时间:2019-06-19

本文共 7475 字,大约阅读时间需要 24 分钟。

鼠标点击出现烟花效果

主要想法:

  • 鼠标点击事件触发圆点出现在鼠标处

  • 圆点大小,颜色,数量随机

  • 有一个小白圈做为轨迹,不断改变半径变大变淡消失

  • 圆点向外移动,自身变小,消失。随着移动的距离远,移动速度跟着变

需要处理的是,从鼠标点击处可以确定圆点的x,y轴,但是动去哪,怎么动是一个问题,

所以先确定圆点的目标坐标,再从圆点的原始坐标(即鼠标点击处)向目标坐标移动,并且x,y 成比例 去移动才不会在x,y移动距离不相等的情况下 不平衡

随机生成圆点目标坐标的函数代码:

let endpos = (x, y) => {  let angle = random(0, 360) * Math.PI / 180,    value = random(20, 150),    radius = [-1, 1][random(0, 1)] * value;  return {    x: x + radius * Math.cos(angle),    y: y + radius * Math.sin(angle)  }}

因为需要大量的随机数,所以封装一个生成随机数函数

let random = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;

圆点的移动函数,我们需要的移动是从原始坐标向目标坐标由快而慢。

生成比例分成3段。那就是原始坐标到第一段坐标为第一段,第一段坐标到第二段坐标为第二段,第二段坐标到目标坐标为第三段。如果当前坐标是处于第一段内,则速度越快,以此类推

现在两种情况,一种是目标坐标大于原始坐标,那么,第一段就为最接近原始坐标的那一段(Math.max(current, ff) == current ? (Math.max(current, mm) == current ? s : m) : f),第二种情况是目标坐标小于原始坐标,那么就反过来,第一段为离原始坐标最远的那一段。

//根据不同距离段设置前行的步伐,分为3个阶段,离出发点近的那一段为速度最快,中间为速度一般,最远为速度最慢//区分目标点小于出发点的情况//ratio为两点之间的距离的行走比例,比例数值越大,行走越慢  moveFun(start, end, current) {    let s = random(26, 35),      m = random(20, 25),      f = random(15, 20),      ff = start.x + ~~((end.x - start.x) / 3),      mm = ff + ~~((end.x - start.x) / 3),      ratio = end.x >= start.x ? (Math.max(current, ff) == current ? (Math.max(current, mm) == current ? s : m) : f) : (Math.max(current, ff) == current ? f : (Math.max(current, mm) == current ? m : s)),      mp = {        x: end.x - start.x,        y: end.y - start.y      };    return {      x: Math.abs(mp.x / ratio),      y: Math.abs(mp.y / ratio)    }  }

每一个小圆点做为一个个体,自带移动函数,和移动的目标坐标。每次Animation时,圆点进行重绘更新最新的坐标

小圆点的代码:

class Circle {  constructor(x, y) {    this.r = random(9, 13)    this.opos = {}    this.x = this.opos.x = x    this.y = this.opos.y = y    this.colors = ['#FF1461', '#18FF92', '#5A87FF', '#FBF38C']    this.color = this.colors[random(0, this.colors.length)];    this.tpos = endpos(x, y)  }  creatCircle(ctx) {    ctx.beginPath()    ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI)    ctx.closePath()    ctx.fillStyle = this.color    ctx.fill()  }  //根据不同距离段设置前行的步伐,分为3个阶段,离出发点近的那一段为速度最快,中间为速度一般,最远为速度最慢  //区分目标点小于出发点的情况  //ratio为两点之间的距离的行走比例,比例数值越大,行走越慢  moveFun(start, end, current) {    let s = random(26, 35),      m = random(20, 25),      f = random(15, 20),      ff = start.x + ~~((end.x - start.x) / 3),      mm = ff + ~~((end.x - start.x) / 3),      ratio = end.x >= start.x ? (Math.max(current, ff) == current ? (Math.max(current, mm) == current ? s : m) : f) : (Math.max(current, ff) == current ? f : (Math.max(current, mm) == current ? m : s)),      mp = {        x: end.x - start.x,        y: end.y - start.y      };    return {      x: Math.abs(mp.x / ratio),      y: Math.abs(mp.y / ratio)    }  }  //根据计算出来的移动值去移动  //如果目标坐标大于原始坐标则向右移动,最大不能超过目标坐标,反之向左移动最小不能小于目标坐标  move() {    var movepos = this.moveFun(this.opos, this.tpos, this.x);    this.x = (this.opos.x > this.tpos.x) ? Math.max(this.x - movepos.x, this.tpos.x) : Math.min(this.x + movepos.x, this.tpos.x)    this.y = this.opos.y > this.tpos.y ? Math.max(this.y - movepos.y, this.tpos.y) : Math.min(this.y + movepos.y, this.tpos.y)    this.r = Math.max(Math.abs((this.r - Math.random() / 1.2).toFixed(2)), 0)  }}

大圆则是从鼠标点击处创建的一个圆,并不断改变其半径向外扩展,并且越来越透明,当它已经很大并且很透明时意味着我们的动画要结束了,所以以这个为标准,停止动画,并且清空屏幕

大圆代码:

class BigCircle {  constructor(x, y) {    this.bR = random(16, 32)    this.overR = random(60, 100)    this.x = x    this.y = y    this.op = 1  }  creatBigCircle(ctx) {    ctx.beginPath()    ctx.arc(this.x, this.y, this.bR, 0, 2 * Math.PI)    ctx.closePath()    ctx.strokeStyle = 'rgba(128, 128, 128, ' + this.op + ')'    ctx.stroke()  }  changeR() {    this.bR = Math.min(this.bR += random(1, 4), this.overR);    this.op = Math.max((this.op - Math.random() / 12).toFixed(2), 0)  }  //检查是否运行完毕,以大圆为标准清空屏幕  complete() {    return this.bR >= this.overR && this.op <= 0;  }}

全部代码:

//canvas鼠标点击烟花特效let endpos = (x, y) => {  let angle = random(0, 360) * Math.PI / 180,    value = random(20, 150),    radius = [-1, 1][random(0, 1)] * value;  return {    x: x + radius * Math.cos(angle),    y: y + radius * Math.sin(angle)  }}let random = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;class Circle {  constructor(x, y) {    this.r = random(9, 13)    this.opos = {}    this.x = this.opos.x = x    this.y = this.opos.y = y    this.colors = ['#FF1461', '#18FF92', '#5A87FF', '#FBF38C']    this.color = this.colors[random(0, this.colors.length)];    this.tpos = endpos(x, y)  }  creatCircle(ctx) {    ctx.beginPath()    ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI)    ctx.closePath()    ctx.fillStyle = this.color    ctx.fill()  }  //根据不同距离段设置前行的步伐,分为3个阶段,离出发点近的那一段为速度最快,中间为速度一般,最远为速度最慢  //区分目标点小于出发点的情况  //ratio为两点之间的距离的行走比例,比例数值越大,行走越慢  moveFun(start, end, current) {      let s = random(26, 35),        m = random(20, 25),        f = random(15, 20),        ff = start.x + ~~((end.x - start.x) / 3),        mm = ff + ~~((end.x - start.x) / 3),        ratio = end.x >= start.x ? (Math.max(current, ff) == current ? (Math.max(current, mm) == current ? s : m) : f) : (Math.max(current, ff) == current ? f : (Math.max(current, mm) == current ? m : s)),        mp = {          x: end.x - start.x,          y: end.y - start.y        };      return {        x: Math.abs(mp.x / ratio),        y: Math.abs(mp.y / ratio)      }    }        //根据计算出来的移动值去移动    //如果目标坐标大于原始坐标则向右移动,最大不能超过目标坐标,反之向左移动最小不能小于目标坐标  move() {    var movepos = this.moveFun(this.opos, this.tpos, this.x);    this.x = (this.opos.x > this.tpos.x) ? Math.max(this.x - movepos.x, this.tpos.x) : Math.min(this.x + movepos.x, this.tpos.x)    this.y = this.opos.y > this.tpos.y ? Math.max(this.y - movepos.y, this.tpos.y) : Math.min(this.y + movepos.y, this.tpos.y)    this.r = Math.max(Math.abs((this.r - Math.random() / 1.2).toFixed(2)), 0)  }}class BigCircle {  constructor(x, y) {    this.bR = random(16, 32)    this.overR = random(60, 100)    this.x = x    this.y = y    this.op = 1  }  creatBigCircle(ctx) {    ctx.beginPath()    ctx.arc(this.x, this.y, this.bR, 0, 2 * Math.PI)    ctx.closePath()    ctx.strokeStyle = 'rgba(128, 128, 128, ' + this.op + ')'    ctx.stroke()  }  changeR() {    this.bR = Math.min(this.bR += random(1, 4), this.overR);    this.op = Math.max((this.op - Math.random() / 12).toFixed(2), 0)  }  //检查是否运行完毕,以大圆为标准清空屏幕  complete() {    return this.bR >= this.overR && this.op <= 0;  }}window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;window.clearRequestTimeout = window.cancelAnimationFrame || window.mozCancelRequestAnimationFrame || window.webkitCancelRequestAnimationFrame || window.msCancelRequestAnimationFrame;let c = document.getElementById("fireworks"),  w = c.width = c.offsetWidth,  h = c.height = c.offsetHeight,  ctx = c.getContext("2d"),  nums = 40,  circles = [],  bCircle = null,  animationId = false;let int = function(x, y) {  circles = []  if (animationId) clearRequestTimeout(animationId)  for (let i = nums; i-- > 0;) {    circles.push(new Circle(x, y))  }  bCircle = new BigCircle(x, y)  creat()}let creat = function() {  ctx.clearRect(0, 0, w, h);  circles.forEach(function(v) {    v.move();    v.creatCircle(ctx)  })  bCircle.changeR()  bCircle.creatBigCircle(ctx)  animationId = requestAnimationFrame(creat)  if (bCircle.complete()) {    //以大圆为标准,清空屏幕停止动画    ctx.clearRect(0, 0, w, h);    clearRequestTimeout(animationId)  }}c.onclick = function(e) {  e = e || window.event;  int(e.clientX, e.clientY)}

html为

转载地址:http://qiesx.baihongyu.com/

你可能感兴趣的文章
PHP队列的实现
查看>>
单点登录加验证码例子
查看>>
[T-SQL]从变量与数据类型说起
查看>>
occActiveX - ActiveX with OpenCASCADE
查看>>
BeanUtils\DBUtils
查看>>
python模块--os模块
查看>>
Java 数组在内存中的结构
查看>>
《关爱码农成长计划》第一期报告
查看>>
学习进度表 04
查看>>
谈谈javascript中的prototype与继承
查看>>
时序约束优先级_Vivado工程经验与各种时序约束技巧分享
查看>>
minio 并发数_MinIO 参数解析与限制
查看>>
flash back mysql_mysqlbinlog flashback 使用最佳实践
查看>>
mysql存储引擎模式_MySQL存储引擎
查看>>
python类 del_全面了解Python类的内置方法
查看>>
java jni 原理_使用JNI技术实现Java和C++的交互
查看>>
java 重写system.out_重写System.out.println(String x)方法
查看>>
配置ORACLE 11g绿色版客户端和PLSQL远程连接环境
查看>>
ASP.NET中 DataList(数据列表)的使用前台绑定
查看>>
Linux学习之CentOS(八)--Linux系统的分区概念
查看>>