【JavaScript】particle
这是js实现的粒子动画,有两种模式,分别是zoom和line,它们对应的效果不同,但是原理都相同,具体分析如下:
部分程序如下:
- var p = this;
- p.originParams = originParams;
- p.params = params;
- p.innerWidth = window.innerWidth;//页面视图区大小
- p.innerHeight = window.innerHeight;
- p.points = [];
- p.pageXY = {pageX:p.innerWidth/2,pageY:p.innerHeight/2};
- if(container[0] === '#') {
- p.container = container.split('#')[1];
- };
- //获取canvas元素
- p.canvas = document.getElementById(p.container);
- //创建context对象
- p.ctx = p.canvas.getContext('2d');
- //初始化
- p.init = function() {
- p.canvas.width = p.innerWidth;
- p.canvas.height = p.innerHeight;
- p.drawBackground();
- p.addOverlap();
- p.initDrawPoint();
- p.animation();
- p.mouseEvent();
- p.windowResize();
- };
- p.addOverlap=function(){
- p.overlap=document.createElement('div');
- p.overlap.style.width=p.innerWidth+'px';
- p.overlap.style.height=p.innerHeight+'px';
- p.overlap.style.position='absolute';
- p.overlap.style.top='0px';
- p.overlap.style.left='0px';
- p.overlap.style.zIndex='100';
- if(p.canvas.nextElementSibling){//??
- p.canvas.parentNode.insertBefore(p.overlap,p.canvas.nextElementSibling);//insertBefore接收要插入的节点和作为参考的节点
- }else{
- p.canvas.parentNode.appendChild(p.overlap);
- };
- };
- //粒子颜色
- p.color = function() {
- function random() {
- return Math.round(Math.random() * 255);
- };
- this.r = random();
- this.g = random();
- this.b = random();//分别调用三次取随机值
- this.a = random(1, 0.8);
- this.rgba = 'rgba(' + this.r + ',' + this.g + ',' + this.b + ',' + this.a + ')';
- return this;
- };
- //获取随机数
- p.random = function(max, min) {
- var min = arguments[1] || 0;
- return Math.floor(Math.random() * (max - min + 1) + min);
- };
- //绘制背景图
- p.drawBackground = function() {
- if(!p.canvas) return;
- p.ctx.fillStyle = '#000';
- p.ctx.fillRect(0, 0, p.innerWidth, p.innerHeight);
- };
- //粒子
- p.point = function() {//每个粒子包括颜色,坐标、半径
- this.color = new p.color();
- this.x = Math.random() * p.innerWidth;//随机坐标
- this.y = Math.random() * p.innerHeight;
- this.vx = p.random(10, -10) / 40;//步进,调用p.random
- this.vy = p.random(10, -10) / 40;
- this.r = p.random(3, 1);//半径,调用p.random,半径最大为3,最小为1,在这个范围内波动
- this.scale = 1;//放大倍数
- };
- //初始化点
- p.initDrawPoint = function() {
- for(var i = 0; i < p.params.point; i++) {//所有点
- var point = new p.point();
- p.points.push(point);
- p.ctx.beginPath();
- p.ctx.fillStyle = point.color.rgba;
- p.ctx.arc(point.x, point.y, point.r * point.scale, 0, Math.PI * 2, true);
- p.ctx.fill();
- };
- p.ctx.closePath();
- };
- //点点连线
- p.connect = function() {
- function lineColor(p1, p2) {
- var linear = p.ctx.createLinearGradient(p1.x, p1.y, p2.x, p2.y);//起点终点坐标
- linear.addColorStop(0, p1.color.rgba);//开始的颜色
- linear.addColorStop(1, p2.color.rgba);//结束的颜色
- return linear;
- };
- for(var i = 0; i < p.params.point; i++) {
- for(var j = 0; j < p.params.point; j++) {
- var p1 = p.points[i];
- var p2 = p.points[j];
- if(Math.abs(p2.x - p1.x) < p.params.minDis && Math.abs(p2.y - p1.y) < p.params.minDis) {//两点之间距离小于一定程度才连线
- p.ctx.beginPath();
- p.ctx.lineWidth = 0.2;
- p.ctx.strokeStyle = lineColor(p1, p2);//采用渐变,描边样式
- p.ctx.moveTo(p1.x, p1.y);
- p.ctx.lineTo(p2.x, p2.y);
- p.ctx.stroke();//描边,使用的是strokeStyle
- p.ctx.closePath();
- };
- };
- };
- };
- p.lineto = function() {//和鼠标位置有关
- function isInView(point) {
- return Math.abs(point.x - p.pageXY.pageX) < p.params.mouseDis && Math.abs(point.y - p.pageXY.pageY) < p.params.mouseDis;
- };
- (function line() {
- function lineColor(p1, p2) {
- var linear = p.ctx.createLinearGradient(p1.x, p1.y, p2.x, p2.y);
- linear.addColorStop(0, p1.color.rgba);
- linear.addColorStop(1, p2.color.rgba);
- return linear;
- };
- for(var i = 0; i < p.params.point; i++) {
- for(var j = 0; j < p.params.point; j++) {
- if(i != j) {
- var p1 = p.points[i];
- var p2 = p.points[j];
- if(isInView(p1) && isInView(p2)) {
- if(Math.abs(p2.x - p1.x) < p.params.minDis && Math.abs(p2.y - p1.y) < p.params.minDis) {
- p.ctx.beginPath();
- p.ctx.lineWidth = 0.2;
- p.ctx.strokeStyle = lineColor(p1, p2);
- p.ctx.moveTo(p1.x, p1.y);
- p.ctx.lineTo(p2.x, p2.y);
- p.ctx.stroke();
- p.ctx.closePath();
- };
- };
- };
- };
- };
- })();
- };
- //无限循环动画
- p.animation = function() {
- p.ctx.clearRect(0, 0, p.innerWidth, p.innerHeight);
- p.drawBackground();
- for(var i = 0; i < p.params.point; i++) {
- var point = p.points[i];
- if(point.x < 0 || point.x > p.innerWidth) {//当小圆球碰到矩形壁以后反弹
- point.vx = -point.vx;
- };
- if(point.y < 0 || point.y > p.innerHeight) {
- point.vy = -point.vy;
- };
- p.ctx.beginPath();
- p.ctx.fillStyle = point.color.rgba;
- point.x += point.vx; //小圆球不断移动
- point.y += point.vy;
- p.ctx.arc(point.x, point.y, point.r * point.scale, 0, Math.PI * 2, true);
- p.ctx.fill();
- };
- if(p.params.effect == 'zoom') {
- p.connect();//将小球与小球用线连接,鼠标移动事件定义在mouseEvent中
- } else if(p.params.effect == 'line') {
- p.lineto();//该函数与鼠标位置有关,通过鼠标事件传入鼠标位置,在该位置附近连线
- };
- requestAnimationFrame(p.animation);
- };
- //鼠标事件
- p.mouseEvent = function() {
- p.overlap.addEventListener('mousemove', function(e) {//鼠标指针移动时触发div中的事件
- var e = e || window.event;
- var pageX = (e.clientX + document.body.scrollLeft || e.pageX) - this.offsetLeft;//offsetLeft指div到边框??
- var pageY = (e.clientY + document.body.scrollTop || e.pageY) - this.offsetTop;
- if(p.params.effect == 'zoom'){
- for(var t = 0; t < p.params.point; t++) {
- var point = p.points[t];
- if(Math.abs(point.x - p.pageXY.pageX) < p.params.minDis && Math.abs(point.y - p.pageXY.pageY) < p.params.minDis) {//鼠标附近的点
- point.scale = 5;
- } else {
- point.scale = 1;
- };
- };
- };
- p.pageXY.pageX = pageX;
- p.pageXY.pageY = pageY;
- });
- p.overlap.addEventListener('mouseout', function(e) {//鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发
- if(p.params.effect == 'zoom'){//zoom鼠标移出div都变为原来的比例
- for(var i = 0; i < p.params.point; i++) {
- var point = p.points[i];
- if(point.scale != 1) {
- point.scale = 1;
- };
- };
- }else{
- p.pageXY.pageX=p.innerWidth/2;//line方式鼠标移出div自动定位到中心
- p.pageXY.pageY=p.innerHeight/2;
- };
- });
- };
- p.windowResize = function() {
- window.addEventListener('resize', p.init);
- };
- p.init();
- return p;
- };
- //兼容requestAnimFrame
- window.requestAnimationFrame = (function() {//requestAnimationFrame??
- return window.requestAnimationFrame ||
- window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- function(callback) {//前面三个都不支持则采用该函数
- window.setTimeout(callback, 1000 / 60);
- };
- })();
【JavaScript】particle的更多相关文章
- 【javascript】html5中使用canvas编写头像上传截取功能
[javascript]html5中使用canvas编写头像上传截取功能 本人对canvas很是喜欢,于是想仿照新浪微博头像上传功能(前端使用canvas) 本程序目前在谷歌浏览器和火狐浏览器测试可用 ...
- 【JavaScript】出现即使设置了ID也获取不到的可能原因与window.onload
有时候.在JavaScript中.即使设置了ID也有可能出现document.getElementById()获取不到的情况,然后你就開始想document是否写错之类的.事实上根本就不是你的代码的大 ...
- 【JavaScript】我的JavaScript技术总结第一篇——编程细节
遍历数组 for (var i=0, l=arr.length; i<l; i++) 这样写的一个好处就是让每次循环少一步获取数组对象长度的操作,数组长度越长,价值越明显. 判断变量的真假 if ...
- 【JavaScript】下大雪
引用[JavaScript]满天星的代码,稍作修改的结果: function drawStars() { for (i = 1; i < 100; ++i) { ctx.fillText(&qu ...
- 【JavaScript】JavaScript中的replaceAll
JavaScript中是没有replaceAll的.仅仅有replace,replace仅仅能替换字符中的第一个字符.并且这个replace里面不支持正則表達式,以达到replaceAll的目的. 只 ...
- 【JavaScript】Leetcode每日一题-在D天内送包裹的能力
[JavaScript]Leetcode每日一题-在D天内送包裹的能力 [题目描述] 传送带上的包裹必须在 D 天内从一个港口运送到另一个港口. 传送带上的第 i 个包裹的重量为 weights[i] ...
- 【JavaScript】Leetcode每日一题-青蛙过河
[JavaScript]Leetcode每日一题-青蛙过河 [题目描述] 一只青蛙想要过河. 假定河流被等分为若干个单元格,并且在每一个单元格内都有可能放有一块石子(也有可能没有). 青蛙可以跳上石子 ...
- 【JavaScript】Leetcode每日一题-平方数之和
[JavaScript]Leetcode每日一题-平方数之和 [题目描述] 给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a2 + b2 = c . 示例1: 输入:c = 5 ...
- 【JavaScript】Leetcode每日一题-二叉搜索树的范围和
[JavaScript]Leetcode每日一题-二叉搜索树的范围和 [题目描述] 给定二叉搜索树的根结点 root,返回值位于范围 [low, high] 之间的所有结点的值的和. 示例1: 输入: ...
随机推荐
- flask中的数据操作
flask中数据访问: pip install flask-sqlalemy 创建数据: 创建app的工厂 from flask import Flask from flask_sqlalchemy ...
- centos 网络很慢且无法远程登陆的解决办法
安装了centOS,但是发现网速实在是卡得几乎不能上网,连百度都打不开 后来想到偶然记得有一次看过一段话,说到关闭ipv6,测试来一下,果然有效,关闭来ipv6打开网速飞快. 关闭方法,在/etc/m ...
- 1.Java设计模式-工厂模式
1.简单工厂模式(Factory Method) 常用的工厂模式是静态工厂模式,利用static修饰方法,作为一种类似于常见的工具类Utils等辅助效果,一般情况下工厂类不需要实例化. //1.定义一 ...
- 【SSH网上商城项目实战07】Struts2和Json的整合
转自:https://blog.csdn.net/eson_15/article/details/51332758 上一节我们完成了DataGrid显示jason数据,但是没有和后台联系在一起,只是单 ...
- Django中用Jquery实现不刷新页面进行身份验证和计算器功能
1.下载jquery http://www.jq22.com/jquery-info122 下载解压之后加入工程中的static文件夹中 2.路由分发. """Djang ...
- 浅谈arguments与arguments的妙用
1.每个函数都有一个arguments属性,表示函数的实参集合,这里的实参是重点,就是执行函数时实际传入的参数的集合. 2.arguments不是数组而是一个对象,但它和数组很相似,所以通常称为类数组 ...
- JavaScript中的__proto__
实例中的__proto__ 箭头函数的__proto__ 需要注意的是箭头函数的__proto__并没有指向Function构造函数的的原型对象 MDN上的资料显示,箭头函数不绑定Arguments ...
- java中的==、equals()、hashCode()源码分析(转载)
在java编程或者面试中经常会遇到 == .equals()的比较.自己看了看源码,结合实际的编程总结一下. 1. == java中的==是比较两个对象在JVM中的地址.比较好理解.看下面的代码: ...
- 【javascript】javasrcipt设计模式之策略模式
策略模式支持在运行时由使用者选择合适的算法,对于使用者而言不用关心背后的具体事项,而使用者自动根据当前程序执行的上下文和配置,从已有的算法列表中选择出合适的算法来处理当前任务. 1.要解决的问题 2. ...
- 状态开关(ToggleButton)
状态开关(ToggleButton): 常用属性:isChecked(是否被选中,如true) 监听:1.监听方法:setOnCheckedChangeListener 2.监听器:CompoundB ...