函数节流的实际应用

之前在网上看过一些有关函数节流方面的东西,对于其实际的应用场景,说的比较多的是在窗口频繁的resize的时候,前几天在做项目的时候也遇到了一个需要用到函数节流的问题,场景是这样的,在一个主画布中(一个div)有许多的元素(textElement,photoElement,都是在一个canvas上面画的图),然后做需要一个镜像的效果。做这个镜像的效果不是很难,首先搞一个和主画布同等大小的隐藏的canvas(这个就是我们的实时截图了),将主画布内的所有元素按照各自的位置绘制到截图canvas上面,然后我们再操作截屏canvas的像素,生成我们需要的镜像边框,但是这中间有一个效率问题,我们需要得到实时的镜像,那么每次拖动都需要先生成截屏canvas,然后生成镜像边框,直接这样做,上去拖两下,然后就感觉好卡,然后我想到了函数节流,果断采取函数节流,虽然没有真正的实时了,但是卡顿的情况明显好了很多。

以下是没有用函数节流前的代码(代码有点乱,只是实现了效果):


<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>镜像demo</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<style type="text/css">
body{
background: #eee;
}
#main{
box-sizing: border-box;
background: #fff;
margin: 100px auto;
position: relative;
border: 1px dashed #f00;
}
#mirror-top{
position: absolute;
top: -51px;
left: -1px;
background: #fff;
}
#mirror-bottom{
position: absolute;
bottom: -51px;
left: -1px;
background: #fff;
}
#mirror-left{
position: absolute;
left: -51px;
top: -1px;
background: #fff;
}
#mirror-right{
position: absolute;
right: -51px;
top: -1px;
background: #fff;
}
canvas{
position: absolute;
}
#screenshot{
display: none;
}
</style>
</head>
<body>
<div id="main">
<canvas id="mirror-top" width="600" height="50"></canvas>
<canvas id="mirror-bottom" width="600" height="50"></canvas>
<canvas id="mirror-left" width="50" height="600"></canvas>
<canvas id="mirror-right" width="50" height="600"></canvas>
</div>
<canvas id="screenshot"></canvas>
<script type="text/javascript">
var params = [],
num = 5,
width = 600,
height = 600,
mirrorLength = 50,
main = document.getElementById("main"),
screenshot = document.getElementById("screenshot"),
scxt = screenshot.getContext("2d");
main.style.width = width + 'px';
main.style.height = height + 'px';
screenshot.width = width;
screenshot.height = height;
for(var i=0;i<num;i++){
var e = new Elem(),
ttop = ~~rand(50,width-50),
left = ~~rand(50,height-50)
ctx = e.getContext('2d');
e.id = "elem"+i;
e.style.top = ttop + 'px';
e.style.left = left + 'px';
e.width = 50;
e.height = 50;
ctx.fillStyle = randColor();
ctx.fillRect(0,0,50,50);
ctx.font="30px Verdana";
ctx.fillStyle = "#fff";
ctx.textAlign = "end";
ctx.textBaseLine = "Bottom";
ctx.fillText(i,30,30);
params.push({
x : left,
y : ttop
});
addEvents(e,i);
main.appendChild(e);
}
generateScreenShot();
function generateScreenShot(){
scxt.clearRect(0,0,width,height);
console.log(params.length)
for(var i=0,len=params.length;i<len;i++){
var item = params[i],
source = document.getElementById("elem"+i);
console.log("item",item.x,item.y);
(function(source,item){
scxt.drawImage(source,item.x,item.y,50,50);
})(source,item);
}
createMirror();
}
function imageDataVRevert(sourceData,newData){
for(var i=0,h=sourceData.height;i<h;i++){
for(j=0,w=sourceData.width;j<w;j++){
newData.data[i*w*4+j*4+0] = sourceData.data[(h-i)*w*4+j*4+0];
newData.data[i*w*4+j*4+1] = sourceData.data[(h-i)*w*4+j*4+1];
newData.data[i*w*4+j*4+2] = sourceData.data[(h-i)*w*4+j*4+2];
newData.data[i*w*4+j*4+3] = sourceData.data[(h-i)*w*4+j*4+3];
}
}
return newData;
}
function imageDataHRevert(sourceData,newData){
for(var i=0,h=sourceData.height;i<h;i++){
for(j=0,w=sourceData.width;j<w;j++){
newData.data[i*w*4+j*4+0] = sourceData.data[i*w*4+(w-j)*4+0];
newData.data[i*w*4+j*4+1] = sourceData.data[i*w*4+(w-j)*4+1];
newData.data[i*w*4+j*4+2] = sourceData.data[i*w*4+(w-j)*4+2];
newData.data[i*w*4+j*4+3] = sourceData.data[i*w*4+(w-j)*4+3];
}
}
return newData;
}
function Elem(){
return document.createElement("canvas");
}
function rand(min,max){
return Math.random() * (max-min) + min;
}
function randColor(){
return 'rgb('+(~~(Math.random()*255))+','+(~~(Math.random()*255))+','+(~~(Math.random()*255))+')';
}
function addEvents(elem,i){
elem.isMouseDown = false;
elem.onmousedown = function(event){
elem.isMouseDown = true;
elem.disX = event.pageX - parseFloat(elem.style.left);
elem.disY = event.pageY - parseFloat(elem.style.top);
elem.style.cursor = "move";
return false;
}
elem.onmousemove = function(event){
if(elem.isMouseDown){
moveX = ~~(event.pageX - elem.disX);
moveY = ~~(event.pageY - elem.disY);
if(moveX<=0){
moveX = 0;
}
if(moveX>=width-50){
moveX = width-50;
}
if(moveY<=0){
moveY = 0;
}
if(moveY>=height-50){
moveY = height-50;
}
elem.style.top = moveY + 'px';
elem.style.left = moveX + 'px';
params[i].x = moveX;
params[i].y = moveY;
generateScreenShot();
}
return false;
}
elem.onmouseup = function(){
elem.isMouseDown = false;
elem.style.cursor = "auto";
}
elem.onmouseout = function(){
elem.isMouseDown = false;
}
}
function createMirror(){
var mirrorTop = document.getElementById("mirror-top"),
tctx = mirrorTop.getContext("2d"),
mirrorBottom = document.getElementById("mirror-bottom"),
bctx = mirrorBottom.getContext("2d"),
mirrorLeft = document.getElementById("mirror-left"),
lctx = mirrorLeft.getContext("2d"),
mirrorRight = document.getElementById("mirror-right"),
rctx = mirrorRight.getContext("2d"),
w = screenshot.width,
h = screenshot.height,
imgData,newData;
//top
imgData = scxt.getImageData(0,0,w,mirrorLength);
newData = tctx.createImageData(w,mirrorLength);
newData = imageDataVRevert(imgData,newData);
tctx.putImageData(newData,1,0);
//bottom
imgData = scxt.getImageData(0,h-mirrorLength,w,mirrorLength);
newData = bctx.createImageData(w,mirrorLength);
newData = imageDataVRevert(imgData,newData);
bctx.putImageData(newData,1,0);
//left
imgData = scxt.getImageData(0,0,mirrorLength,w);
newData = lctx.createImageData(mirrorLength,w);
newData = imageDataHRevert(imgData,newData);
lctx.putImageData(newData,0,1);
//right
imgData = scxt.getImageData(w-mirrorLength,0,mirrorLength,w);
newData = rctx.createImageData(mirrorLength,w);
newData = imageDataHRevert(imgData,newData);
rctx.putImageData(newData,0,1);
}
</script>
</body>
</html>

在线demo:http://demo.deanhan.cn/mirror/index-c.html

使用后的代码:


<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>xx</title>
<meta name="description" content="">
<meta name="keywords" content="">
<link href="" rel="stylesheet">
<style type="text/css">
body{
background: #eee;
}
#main{
box-sizing: border-box;
background: #fff;
margin: 100px auto;
position: relative;
border: 1px dashed #f00;
}
#mirror-top{
position: absolute;
top: -51px;
left: -1px;
background: #fff;
}
#mirror-bottom{
position: absolute;
bottom: -51px;
left: -1px;
background: #fff;
}
#mirror-left{
position: absolute;
left: -51px;
top: -1px;
background: #fff;
}
#mirror-right{
position: absolute;
right: -51px;
top: -1px;
background: #fff;
}
canvas{
position: absolute;
}
#screenshot{
display: none;
}
</style>
</head>
<body>
<div id="main">
<canvas id="mirror-top" width="600" height="50"></canvas>
<canvas id="mirror-bottom" width="600" height="50"></canvas>
<canvas id="mirror-left" width="50" height="600"></canvas>
<canvas id="mirror-right" width="50" height="600"></canvas>
</div>
<canvas id="screenshot"></canvas>
<script type="text/javascript">
var params = [],
num = 5,
width = 600,
height = 600,
mirrorLength = 50,
main = document.getElementById("main"),
screenshot = document.getElementById("screenshot"),
scxt = screenshot.getContext("2d"),
timer = null;
main.style.width = width + 'px';
main.style.height = height + 'px';
screenshot.width = width;
screenshot.height = height;
for(var i=0;i<num;i++){
var e = new Elem(),
ttop = ~~rand(50,width-50),
left = ~~rand(50,height-50)
ctx = e.getContext('2d');
e.id = "elem"+i;
e.style.top = ttop + 'px';
e.style.left = left + 'px';
e.width = 50;
e.height = 50;
ctx.fillStyle = randColor();
ctx.fillRect(0,0,50,50);
ctx.font="30px Verdana";
ctx.fillStyle = "#fff";
ctx.textAlign = "end";
ctx.textBaseLine = "Bottom";
ctx.fillText(i,30,30);
params.push({
x : left,
y : ttop
});
addEvents(e,i);
main.appendChild(e);
}
generateScreenShot();
function generateScreenShot(){
scxt.clearRect(0,0,width,height);
console.log(params.length)
for(var i=0,len=params.length;i<len;i++){
var item = params[i],
source = document.getElementById("elem"+i);
console.log("item",item.x,item.y);
(function(source,item){
scxt.drawImage(source,item.x,item.y,50,50);
})(source,item);
}
createMirror();
}
function imageDataVRevert(sourceData,newData){
for(var i=0,h=sourceData.height;i<h;i++){
for(j=0,w=sourceData.width;j<w;j++){
newData.data[i*w*4+j*4+0] = sourceData.data[(h-i)*w*4+j*4+0];
newData.data[i*w*4+j*4+1] = sourceData.data[(h-i)*w*4+j*4+1];
newData.data[i*w*4+j*4+2] = sourceData.data[(h-i)*w*4+j*4+2];
newData.data[i*w*4+j*4+3] = sourceData.data[(h-i)*w*4+j*4+3];
}
}
return newData;
}
function imageDataHRevert(sourceData,newData){
for(var i=0,h=sourceData.height;i<h;i++){
for(j=0,w=sourceData.width;j<w;j++){
newData.data[i*w*4+j*4+0] = sourceData.data[i*w*4+(w-j)*4+0];
newData.data[i*w*4+j*4+1] = sourceData.data[i*w*4+(w-j)*4+1];
newData.data[i*w*4+j*4+2] = sourceData.data[i*w*4+(w-j)*4+2];
newData.data[i*w*4+j*4+3] = sourceData.data[i*w*4+(w-j)*4+3];
}
}
return newData;
}
function Elem(){
return document.createElement("canvas");
}
function rand(min,max){
return Math.random() * (max-min) + min;
}
function randColor(){
return 'rgb('+(~~(Math.random()*255))+','+(~~(Math.random()*255))+','+(~~(Math.random()*255))+')';
}
function addEvents(elem,i){
elem.isMouseDown = false;
elem.onmousedown = function(event){
elem.isMouseDown = true;
elem.disX = event.pageX - parseFloat(elem.style.left);
elem.disY = event.pageY - parseFloat(elem.style.top);
elem.style.cursor = "move";
return false;
}
elem.onmousemove = function(event){
if(elem.isMouseDown){
moveX = ~~(event.pageX - elem.disX);
moveY = ~~(event.pageY - elem.disY);
if(moveX<=0){
moveX = 0;
}
if(moveX>=width-50){
moveX = width-50;
}
if(moveY<=0){
moveY = 0;
}
if(moveY>=height-50){
moveY = height-50;
}
elem.style.top = moveY + 'px';
elem.style.left = moveX + 'px';
params[i].x = moveX;
params[i].y = moveY;
timer && clearTimeout(timer);
timer = setTimeout(function(){
generateScreenShot();
},50);
}
return false;
}
elem.onmouseup = function(){
elem.isMouseDown = false;
elem.style.cursor = "auto";
}
elem.onmouseout = function(){
elem.isMouseDown = false;
}
}
function createMirror(){
var mirrorTop = document.getElementById("mirror-top"),
tctx = mirrorTop.getContext("2d"),
mirrorBottom = document.getElementById("mirror-bottom"),
bctx = mirrorBottom.getContext("2d"),
mirrorLeft = document.getElementById("mirror-left"),
lctx = mirrorLeft.getContext("2d"),
mirrorRight = document.getElementById("mirror-right"),
rctx = mirrorRight.getContext("2d"),
w = screenshot.width,
h = screenshot.height,
imgData,newData;
//top
imgData = scxt.getImageData(0,0,w,mirrorLength);
newData = tctx.createImageData(w,mirrorLength);
newData = imageDataVRevert(imgData,newData);
tctx.putImageData(newData,1,0);
//bottom
imgData = scxt.getImageData(0,h-mirrorLength,w,mirrorLength);
newData = bctx.createImageData(w,mirrorLength);
newData = imageDataVRevert(imgData,newData);
bctx.putImageData(newData,1,0);
//left
imgData = scxt.getImageData(0,0,mirrorLength,w);
newData = lctx.createImageData(mirrorLength,w);
newData = imageDataHRevert(imgData,newData);
lctx.putImageData(newData,0,1);
//right
imgData = scxt.getImageData(w-mirrorLength,0,mirrorLength,w);
newData = rctx.createImageData(mirrorLength,w);
newData = imageDataHRevert(imgData,newData);
rctx.putImageData(newData,0,1);
}
</script>
</body>
</html>

在线Demo:http://demo.deanhan.cn/mirror/

  • 支付宝二维码 支付宝
  • 微信二维码 微信
相关文章