canvas基础学习(四)
今天逛天猫时,看见优衣库店铺首页有个这个飘雪效果,顿时觉得好酷炫,立马从里面copy代码进行学习。
之前我也做过一些canvas特效,往往在canvas全屏时,canvas下层的div就无法进行dom的事件操作,点击之类的就失灵了。之前我的做法要么就是在canvas上加入点击事件,穿透到下层,或者把下层的div通过z-index属性放在canvas的上层。这种办法都显得死板或者展现效果很差。看了这个页面发现了css3的解决办法
.snow-canvas {
display: block;
width: 100%;
height: 100%;
top:;
left:;
position: fixed;
pointer-events: none;
}
就是通过pointer-events设置为none,可以让事件自动到下层去,不过坏处也有,就是通过F12开发者工具不容易找到canvas这个元素。不禁再次感慨CSS3的强大。
下面是把页面的JS copy出来的做的demo
html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
*{
padding: 0;
margin: 0;
}
.main {
display: block;
width: 100%;
height: 2000px;
top: 0;
left: 0;
background-color: red;
}
.snow-canvas {
display: block;
width: 100%;
height: 100%;
top: 0;
left: 0;
position: fixed;
pointer-events: none;
}
</style>
</head>
<body>
<div class="main"></div>
<canvas class="snow-canvas" speed="1" interaction="false" size="2" count="80" opacity="0.00001" start-color="rgba(253,252,251,1)" end-color="rgba(251,252,253,0.3)" wind-power="0" image="false" width="1272" height="150"></canvas>
<canvas class="snow-canvas" speed="3" interaction="true" size="6" count="30" start-color="rgba(253,252,251,1)" end-color="rgba(251,252,253,0.3)" opacity="0.00001" wind-power="2" image="false" width="1272" height="150"></canvas>
<canvas class="snow-canvas" speed="3" interaction="true" size="12" count="20" wind-power="-5" image="img/snow.png" width="1272" height="150"></canvas>
</body>
<script type="text/javascript" src="js/zepto.min.js" ></script>
<script type="text/javascript" src="js/main1.js" ></script>
<script>
$(function() {
$(".snow-canvas").snow();
$(".main").click(function() {
alert(111)
});
});
</script> </html>
main1.js
(function($) {
var $window = window,
$timeout = setTimeout;
var supportCanvas = function() {
var eCan = document.createElement("canvas");
return (typeof eCan.getContext) == "function";
};
window.Snow = function(element, settings) {
(function() {
var lastTime = 0;
var vendors = ['webkit', 'moz'];
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || // name has changed in Webkit
window[vendors[x] + 'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = function(callback, element) {
var timeToCall = 14; //freezes in safari for windows ,and mac to , so i change time to call with 14;
var id = window.setTimeout(function() {
callback(timeToCall);
}, timeToCall);
return id;
};
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}
}());
this.settings = settings,
this.flakes = [],
this.flakeCount = settings.count,
this.mx = -100,
this.my = -100,
this.init(element)
};
Snow.prototype.init = function(element) {
this.canvas = element.get(0), this.ctx = this.canvas.getContext("2d"), this.canvas.width = $window.innerWidth, this.canvas.height = $window.innerHeight, this.flakes = [];
for (var i = 0; i < this.flakeCount; i++) {
var x = Math.floor(Math.random() * this.canvas.width),
y = Math.floor(Math.random() * this.canvas.height),
size = Math.floor(100 * Math.random()) % this.settings.size + 2,
speed = Math.floor(100 * Math.random()) % this.settings.speed + Math.random() * size / 10 + .5,
opacity = .5 * Math.random() + this.settings.opacity;
this.flakes.push({
speed: speed,
velY: speed,
velX: 0,
x: x,
y: y,
size: size,
stepSize: Math.random() / 30,
step: 0,
angle: 180,
opacity: opacity
})
}
1 == this.settings.interaction && this.canvas.addEventListener("mousemove", function(e) {
this.mx = e.clientX, this.my = e.client
});
var thiz = this;
$($window).resize(function() {
thiz.ctx.clearRect(0, 0, thiz.canvas.width, thiz.canvas.height), thiz.canvas.width = $window.innerWidth, thiz.canvas.height = $window.innerHeight
});
if (typeof this.settings.image === "string") {
this.image = $("<img src='" + this.settings.image + "' style='display: none'>");
};
this.snow();
}, Snow.prototype.snow = function() {
var thiz = this,
render = function() {
thiz.ctx.clearRect(0, 0, thiz.canvas.width, thiz.canvas.height);
for (var i = 0; i < thiz.flakeCount; i++) {
var flake = thiz.flakes[i],
x = thiz.mx,
y = thiz.my,
minDist = 100,
x2 = flake.x,
y2 = flake.y,
dist = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y));
if (minDist > dist) {
var force = minDist / (dist * dist),
xcomp = (x - x2) / dist,
ycomp = (y - y2) / dist,
deltaV = force / 2;
flake.velX -= deltaV * xcomp, flake.velY -= deltaV * ycomp
} else
switch (flake.velX *= .98, flake.velY <= flake.speed && (flake.velY = flake.speed), thiz.settings.windPower) {
case !1:
flake.velX += Math.cos(flake.step += .05) * flake.stepSize;
break;
case 0:
flake.velX += Math.cos(flake.step += .05) * flake.stepSize;
break;
default:
flake.velX += .01 + thiz.settings.windPower / 100
}
if (flake.y += flake.velY, flake.x += flake.velX, (flake.y >= thiz.canvas.height || flake.y <= 0) && thiz.resetFlake(flake), (flake.x >= thiz.canvas.width || flake.x <= 0) && thiz.resetFlake(flake), 0 == thiz.settings.image) {
var grd = thiz.ctx.createRadialGradient(flake.x, flake.y, 0, flake.x, flake.y, flake.size - 1);
grd.addColorStop(0, thiz.settings.startColor), grd.addColorStop(1, thiz.settings.endColor), thiz.ctx.fillStyle = grd, thiz.ctx.beginPath(), thiz.ctx.arc(flake.x, flake.y, flake.size, 0, 2 * Math.PI), thiz.ctx.fill()
} else
thiz.ctx.drawImage(thiz.image.get(0), flake.x, flake.y, 2 * flake.size, 2 * flake.size)
}
$window.cancelAnimationFrame(render), $window.requestAnimationFrame(render)
};
render()
}, Snow.prototype.resetFlake = function(flake) {
if (0 == this.settings.windPower || 0 == this.settings.windPower)
flake.x = Math.floor(Math.random() * this.canvas.width), flake.y = 0;
else if (this.settings.windPower > 0) {
var xarray = Array(Math.floor(Math.random() * this.canvas.width), 0),
yarray = Array(0, Math.floor(Math.random() * this.canvas.height)),
allarray = Array(xarray, yarray),
selected_array = allarray[Math.floor(Math.random() * allarray.length)];
flake.x = selected_array[0], flake.y = selected_array[1]
} else {
var xarray = Array(Math.floor(Math.random() * this.canvas.width), 0),
yarray = Array(this.canvas.width, Math.floor(Math.random() * this.canvas.height)),
allarray = Array(xarray, yarray),
selected_array = allarray[Math.floor(Math.random() * allarray.length)];
flake.x = selected_array[0], flake.y = selected_array[1]
}
flake.size = Math.floor(100 * Math.random()) % this.settings.size + 2,
flake.speed = Math.floor(100 * Math.random()) % this.settings.speed + Math.random() * flake.size / 10 + .5,
flake.velY = flake.speed, flake.velX = 0, flake.opacity = .5 * Math.random() + this.settings.opacity
};
$.fn.snow = function() {
var userCanvas = supportCanvas();
userCanvas && $(this).each(function(i, e) {
var scope = {};
$.each(e.attributes, function(index, key) {
scope[$.camelCase(key.name)] = Number(Number(key.value)) ? Number(key.value) : key.value
});
if (typeof scope.image === "string" && scope.image === "false") {
scope.image = false
};
new Snow($(e), {
speed: 1 || 0,
interaction: scope.interaction || !0,
size: scope.size || 2,
count: scope.count || 200,
opacity: scope.opacity || 1,
startColor: scope.startColor || "rgba(255,255,255,1)",
endColor: scope.endColor || "rgba(255,255,255,0)",
windPower: scope.windPower || 0,
image: scope.image || !1
});
});
if (!userCanvas) {
var setting = {};
$(this).each(function(i, e) {
setting["image"] = $(e).attr("image") || "./imgs/snow.png";
$(this).remove();
createSnow("", 40);
});
};
}; function k(a, b, c) {
if (a.addEventListener) a.addEventListener(b, c, false);
else a.attachEvent && a.attachEvent("on" + b, c)
} function g(a) {
if (typeof window.onload != "function") window.onload = a;
else {
var b = window.onload;
window.onload = function() {
b();
a()
}
}
} function h() {
var a = {};
for (type in {
Top: "",
Left: ""
}) {
var b = type == "Top" ? "Y" : "X";
if (typeof window["page" + b + "Offset"] != "undefined")
a[type.toLowerCase()] = window["page" + b + "Offset"];
else {
b = document.documentElement.clientHeight ? document.documentElement : document.body;
a[type.toLowerCase()] = b["scroll" + type]
}
}
return a
} function l() {
var a = document.body,
b;
if (window.innerHeight) b = window.innerHeight;
else if (a.parentElement.clientHeight) b = a.parentElement.clientHeight;
else if (a && a.clientHeight) b = a.clientHeight;
return b
};
var j = true;
var f = true;
var m = null;
var c = [];
var createSnow = function(a, b) {
clearInterval(m);
c = [];
m = setInterval(function() {
f && b > c.length && Math.random() < b * 0.0025 && c.push(new i(a));
!f && !c.length && clearInterval(m);
for (var e = h().top, n = l(), d = c.length - 1; d >= 0; d--)
if (c[d])
if (c[d].top < e || c[d].top + c[d].size + 1 > e + n) {
c[d].remove();
c[d] = null;
c.splice(d, 1)
} else {
c[d].move();
c[d].draw()
}
}, 40);
k(window, "scroll",
function() {
for (var e = c.length - 1; e >= 0; e--) c[e].draw()
})
};
var removeSnow = function() {
clearInterval(m);
do {
c.pop().remove();
} while (c.length);
};
//雪花的构造函数;
function i(a) {
this.parent = document.body;
this.createEl(this.parent, a);
this.size = Math.random() * 20 + 20;
this.el.style.width = Math.round(this.size) + "px";
this.el.style.height = Math.round(this.size) + "px";
this.maxLeft = document.body.offsetWidth - this.size;
this.maxTop = document.body.offsetHeight - this.size;
this.left = Math.random() * this.maxLeft;
this.top = h().top + 1;
this.angle = 1.4 + 0.8 * Math.random();
this.minAngle = 1.4;
this.maxAngle = 1.6;
this.angleDelta = 0.01 * Math.random();
this.speed = 2 + Math.random()
}
i.prototype = {
createEl: function(a, b) {
this.el = document.createElement("img");
this.el.classname = "nicesnowclass";
this.el.setAttribute("src", b || "./imgs/snow.png");
this.el.style.position = "absolute";
this.el.style.display = "block";
this.el.style.zIndex = "99999";
this.parent.appendChild(this.el)
},
move: function() {
if (this.angle < this.minAngle || this.angle > this.maxAngle)
this.angleDelta = -this.angleDelta;
this.angle += this.angleDelta;
this.left += this.speed * Math.cos(this.angle * Math.PI);
this.top -= this.speed * Math.sin(this.angle * Math.PI);
if (this.left < 0) this.left = this.maxLeft;
else if (this.left > this.maxLeft) this.left = 0
},
draw: function() {
this.el.style.top = Math.round(this.top) + "px";
this.el.style.left = Math.round(this.left) + "px"
},
remove: function() {
this.parent.removeChild(this.el);
this.parent = this.el = null
}
};
})(Zepto);
效果图为
雪花的图片为
这个代码主要是用于PC,代码上做了很多的兼容操作,无论是动画时间戳、页面对canvas的支持、css等等。我个人是做移动端的开发,这段代码有很多浏览器兼容处理对我并不是很需要,并且移动端更加专注于代码代码执行速度和内存的使用,这段代码算法比较复杂,而且它有个问题是当页面有多个canvas时,他建立多个Snow对象,每一个Snow对象都会开启一个时间戳函数,如下图,这个在移动端是比较影响性能的,我们更加希望一个时间戳里完成多个Snow对象的操作。
所以我把main1.js剔除了一些代码,然后略微改动下,如下代码
(function($ , window) {
var snows = [];
var supportCanvas = function() {
return (typeof document.createElement("canvas").getContext) == "function";
};
function Snow(element, settings) {
this.settings = settings,this.flakes = [],this.flakeCount = settings.count,
this.mx = -100,this.my = -100,this.init(element);
};
Snow.prototype.init = function(element) {
this.canvas = element[0], this.ctx = this.canvas.getContext("2d"), this.canvas.width = window.innerWidth, this.canvas.height = window.innerHeight, this.flakes = [];
for (var i = 0; i < this.flakeCount; i++) {
var x = Math.floor(Math.random() * this.canvas.width),
y = Math.floor(Math.random() * this.canvas.height),
size = Math.floor(100 * Math.random()) % this.settings.size + 2,
speed = Math.floor(100 * Math.random()) % this.settings.speed + Math.random() * size / 10 + .5,
opacity = .5 * Math.random() + this.settings.opacity;
this.flakes.push({
speed: speed,
velY: speed,
velX: 0,
x: x,
y: y,
size: size,
stepSize: Math.random() / 1000,
step: 0,
angle: 180,
opacity: opacity
})
}
var thiz = this;
$(window).resize(function() {
thiz.ctx.clearRect(0, 0, thiz.canvas.width, thiz.canvas.height), thiz.canvas.width = window.innerWidth, thiz.canvas.height = window.innerHeight
});
if (typeof this.settings.image === "string") {
this.image = $("<img src='" + this.settings.image + "' style='display: none'>");
};
snows.push(this);
}, Snow.prototype.resetFlake = function(flake) {
if (0 == this.settings.windPower || 0 == this.settings.windPower)
flake.x = Math.floor(Math.random() * this.canvas.width), flake.y = 0;
else if (this.settings.windPower > 0) {
var xarray = Array(Math.floor(Math.random() * this.canvas.width), 0),
yarray = Array(0, Math.floor(Math.random() * this.canvas.height)),
allarray = Array(xarray, yarray),
selected_array = allarray[Math.floor(Math.random() * allarray.length)];
flake.x = selected_array[0], flake.y = selected_array[1]
} else {
var xarray = Array(Math.floor(Math.random() * this.canvas.width), 0),
yarray = Array(this.canvas.width, Math.floor(Math.random() * this.canvas.height)),
allarray = Array(xarray, yarray),
selected_array = allarray[Math.floor(Math.random() * allarray.length)];
flake.x = selected_array[0], flake.y = selected_array[1]
}
flake.size = Math.floor(100 * Math.random()) % this.settings.size + 2,
flake.speed = Math.floor(100 * Math.random()) % this.settings.speed + Math.random() * flake.size / 10 + .5,
flake.velY = flake.speed, flake.velX = 0, flake.opacity = .5 * Math.random() + this.settings.opacity
};
function starSnow(){
var render = function() {
for(var index = 0 , thiz ; thiz = snows[index++];){
thiz.ctx.clearRect(0, 0, thiz.canvas.width, thiz.canvas.height);
for (var i = 0; i < thiz.flakeCount; i++) {
var flake = thiz.flakes[i];
switch (flake.velX *= .98, flake.velY <= flake.speed && (flake.velY = flake.speed), thiz.settings.windPower) {
case !1:
flake.velX += Math.cos(flake.step += .05) * flake.stepSize;
break;
case 0:
flake.velX += Math.cos(flake.step += .05) * flake.stepSize;
break;
default:
flake.velX += .01 + thiz.settings.windPower / 100
}
if (flake.y += flake.velY, flake.x += flake.velX, (flake.y >= thiz.canvas.height || flake.y <= 0) && thiz.resetFlake(flake), (flake.x >= thiz.canvas.width || flake.x <= 0) && thiz.resetFlake(flake), 0 == thiz.settings.image) {
var grd = thiz.ctx.createRadialGradient(flake.x, flake.y, 0, flake.x, flake.y, flake.size - 1);
grd.addColorStop(0, thiz.settings.startColor), grd.addColorStop(1, thiz.settings.endColor), thiz.ctx.fillStyle = grd, thiz.ctx.beginPath(), thiz.ctx.arc(flake.x, flake.y, flake.size, 0, 2 * Math.PI), thiz.ctx.fill()
} else
thiz.ctx.drawImage(thiz.image[0], flake.x, flake.y, 2 * flake.size, 2 * flake.size)
}
}
window.requestAnimationFrame(render);
};
render()
}
$.fn.snow = function() {
var userCanvas = supportCanvas();
userCanvas && $(this).each(function(i, e) {
var scope = {};
$.each(e.attributes, function(index, key) {
scope[$.camelCase(key.name)] = Number(Number(key.value)) ? Number(key.value) : key.value
});
if(scope.image === "false") scope.image = false;
new Snow($(e), {
speed: scope.speed || 1,
size: scope.size || 2,
count: scope.count || 200,
opacity: scope.opacity || 1,
startColor: scope.startColor || "rgba(255,255,255,1)",
endColor: scope.endColor || "rgba(255,255,255,0)",
windPower: scope.windPower || 0,
image: scope.image || !1
});
});
starSnow();
};
})(Zepto , window);
除了去掉一些兼容处理,其它的改动不大,就是多建立了个snows的数组,新建的Snow对象都会放大这个数组里面去,然后就是去掉了Snow的原型方法snow(),时间戳处理统一在startSnow()函数中处理,在函数内部遍历snows数组,改了后效果是一样的,不过在手机中卡顿比之前强了不少。
canvas基础学习(四)的更多相关文章
- Python基础学习四
Python基础学习四 1.内置函数 help()函数:用于查看内置函数的用途. help(abs) isinstance()函数:用于判断变量类型. isinstance(x,(int,float) ...
- canvas基础学习
/** * Created by ty on 2016/7/11. * canvas 基础 */ window.onload = function() { var canvas = document. ...
- canvas基础学习(二)
一.图像绘制 canvas绘制图像的方法是ctx.drawImage();该方法有三种使用方式 1.ctx.drawImage(img,x,y); img是指图像对象,x和y分别是这个图像左上角在ca ...
- HTML5 <canvas> 基础学习
HTML5 <canvas> 元素用于图形的绘制,通过脚本 (通常是JavaScript)来完成. <canvas> 标签只是图形容器,您必须使用脚本来绘制图形 创建一个画布( ...
- Mybatis基础学习(四)—关系映射
一.模型分析 user和orders user---->orders 一个用户可以创建多个订单,一对多. orders--->user 一个订单只由一个用户创建,一对一. orders ...
- canvas一周一练 -- canvas基础学习
从上个星期开始,耳朵就一直在生病,里面长了个疙瘩,肿的一碰就疼,不能吃饭不能嗨 (┳_┳)……在此提醒各位小伙伴,最近天气炎热,一定要注意防暑上火,病来如山倒呀~ 接下来我正在喝着5块一颗的药学习ca ...
- Node.js基础学习四之注册功能
前言:在Node.js学习(二)和(三)中介绍了如何在Node.js 中获取登录的用户名和密码与数据库进行验证并返回数据给客户端 需求:实现注册功能 为了区分登录和注册是两个不同的请求,在端口后面加上 ...
- Salesforce Sales Cloud 零基础学习(四) Chatter
Chatter是一个Salesforce实时协作应用程序,它允许你的用户一起工作.互相交谈和共享信息,不管用户角色或位置如何,连接.并激励用户在整个组织内高效工作. Chatter 让用户们在 Opp ...
- canvas基础学习(一)
一.概述 canvas它和其它的HTML5标签的使用基本一致,但是它相当于在浏览器中建立一个画布,可以再这个画布上画图.创建动画甚至是3D游戏.由于canvas要适配不同终端的分辨率,所以尽可能的在标 ...
随机推荐
- MVC,MVP和MVVM区别
复杂的软件必须有清晰合理的架构,否则无法开发和维护. MVC(Model-View-Controller)是最常见的软件架构之一,业界有着广泛应用.它本身很容易理解,但是要讲清楚,它与衍生的 MVP ...
- Spring_HelloWord
环境:IntelliJ 14 : jdk1.8 Spring操作步骤 1.新建项目---Spring Batch 2.IntelliJ会自动加载jar包 3.现在就可以在src目录下写Java类文 ...
- $用python处理Excel文档(2)——用xlsxwriter模块写xls/xlsx文档
Refer:<python自动化运维:技术与最佳实践> 更多用法参考xlsxwriter官方文档:http://xlsxwriter.readthedocs.io/ 本文主要总结一下如何使 ...
- Linux基本命令 帮助命令
命令名称:man 英文原意:manual 命令所在路径:/usr/bin/man 执行权限:所有用户 语法:man [命令或者配置文件] 功能描述:获取帮助信息 例如:man ls 查看ls命令的帮助 ...
- mysql利于cte进行分组统计并计算占比
CTE定义:一个公共表表达式(common table expression)是一个命名的临时结果集,它在一条单独的语句中有效,可以在语句中被引用多次. CTE基本语法: WITH cte1 [(co ...
- ubuntu没有声音解决办法
cd /usr/lib/dbus-1.0/ chmod +x dbus-daemon-launch-helper sudo gpasswd -a $USER audio sudo killall pu ...
- 摊铺机基本参数介绍(鼎盛天工WTD9501A)
柴油水冷发动机,马力强劲,功率储备系数大,低噪音.低污染,经济性好,低温起动性能好.微电子控制,分别实现刮板输送.螺旋供料左右独立驱动,可实现自动供料,保持熨平板前物料均匀,调平系统响应速度快,调平精 ...
- 20145230《Java程序设计》第5周学习总结
20145230 <Java程序设计>第5周学习总结 教材学习内容 本周主要学习的内容是关于异常处理的,感觉这部分内容对我们这种初学者 来说非常重要.举个例子,倘若你在编写一个Java程序 ...
- JMeter学习(十三)JMeter使用中遇到的问题:Jmeter Debug - "Unrecognized VM option '+HeapDumpOnOutOfMemoryError"
启动JMeter.bat的程序时,出现以下出错信息: Unrecognized VM option '+HeapDumpOnOutOfMemoryError' Could not create the ...
- 音乐下载api
青檬音乐 http://tingapi.ting.baidu.com/v1/restserver/ting?from=android&version=5.6.5.6&format=js ...