前面的话

  前面分别介绍了拖拽模拟磁性吸附,当可视区域内存在多个可拖拽元素,就出现碰撞检测的问题,这也是javascript动画的一个经典问题。本篇将详细介绍碰撞检测

原理介绍

  碰撞检测的方法有很多,接下来使用九宫格分析法

  假设黄色元素要与红色元素进行碰撞。将红色元素所处的区域分为9部分,自身处于第9部分,周围还存在8个部分。只要黄色元素进入红色元素的第9部分,就算碰撞。否则,都算未碰撞

  总共分为以下5种情况:

  1、处于上侧未碰撞区域——1、2、3区域

  2、处于右侧未碰撞区域——3、4、5区域

  3、处于下侧未碰撞区域——5、6、7区域

  4、处于左侧未碰撞区域——1、7、8区域

  5、处于碰撞区域——9区域

代码实现

  我们把上面的原理用代码实现

function bump(obj,objOther,bgColor){

    /***被碰元素***/
//被碰元素左侧距离可视区域左侧的距离
var L0 = obj.offsetLeft;
//被碰元素上侧距离可视区域上侧的距离
var T0 = obj.offsetTop;
//被碰元素右侧距离可视区域右侧的距离
var R0 = obj.offsetLeft + obj.offsetWidth;
//被碰元素下侧距离可视区域下侧的距离
var B0 = obj.offsetTop + obj.offsetHeight;
/**侵入元素**/
var L = objOther.offsetLeft;
var T = objOther.offsetTop;
var R = objOther.offsetLeft + objOther.offsetWidth;
var B = objOther.offsetTop + objOther.offsetHeight; /*******碰撞检测*******/
//上侧区域if(B < T0)
//左侧区域if(R < L0)
//右侧区域if(L > R0)
//下侧区域if(T > B0) //碰撞区域
if(B >= T0 && R >= L0 && L <= R0 && T <= B0){
obj.style.backgroundColor = 'red';
}else{
obj.style.backgroundColor = bgColor;
}
}

完整效果

<div id="test1" style="height: 100px;width: 100px;background:pink;position:absolute;top:0;left:0;">元素一</div>
<div id="test2" style="height: 100px;width: 100px;background:orange;position:absolute;top:150px;left:150px;">元素二</div>
<script>
function addEvent(target,type,handler){
if(target.addEventListener){
target.addEventListener(type,handler,false);
}else{
target.attachEvent('on'+type,function(event){
return handler.call(target,event);
});
}
}
function getCSS(obj,style){
if(window.getComputedStyle){
return getComputedStyle(obj)[style];
}
return obj.currentStyle[style];
}
function bump(obj,objOther){
bump.objBGColor = (bump.objBGColor === undefined) ? getCSS(obj,'backgroundColor') : bump.objBGColor;
bump.objOtherBGColor = (bump.objOtherBGColor === undefined) ? getCSS(objOther,'backgroundColor') : bump.objOtherBGColor;
/***被碰元素***/
//被碰元素左侧距离可视区域左侧的距离
var L0 = obj.offsetLeft;
//被碰元素上侧距离可视区域上侧的距离
var T0 = obj.offsetTop;
//被碰元素右侧距离可视区域右侧的距离
var R0 = obj.offsetLeft + obj.offsetWidth;
//被碰元素下侧距离可视区域下侧的距离
var B0 = obj.offsetTop + obj.offsetHeight;
/**侵入元素**/
var L = objOther.offsetLeft;
var T = objOther.offsetTop;
var R = objOther.offsetLeft + objOther.offsetWidth;
var B = objOther.offsetTop + objOther.offsetHeight; /*******碰撞检测*******/
//上侧区域if(B < T0)
//左侧区域if(R < L0)
//右侧区域if(L > R0)
//下侧区域if(T > B0) //碰撞区域
if(B >= T0 && R >= L0 && L <= R0 && T <= B0){
obj.style.backgroundColor = objOther.style.backgroundColor ='red';
}else{
obj.style.backgroundColor = bump.objBGColor;
objOther.style.backgroundColor = bump.objOtherBGColor; }
} function drag(ele){
var x0,y0,x1,y1,isMoving;
var L0,R0,T0,B0,EH,EW; var mousedownHandler = function(e){
e = e || event;
//获取元素距离定位父级的x轴及y轴距离
x0 = this.offsetLeft;
y0 = this.offsetTop;
//获取此时鼠标距离视口左上角的x轴及y轴距离
x1 = e.clientX;
y1 = e.clientY;
//按下鼠标时,表示正在运动
isMoving = true;
//鼠标按下时,获得此时的页面区域
L0 = 0;
R0 = document.documentElement.clientWidth;
T0 = 0;
B0 = document.documentElement.clientHeight;
//鼠标按下时,获得此时的元素宽高
EH = ele.offsetHeight;
EW = ele.offsetWidth;
}
var mousemoveHandler = function(e){
//如果没有触发down事件,而直接触发move事件,则函数直接返回
if(!isMoving){
return;
}
e = e || event;
//获取此时鼠标距离视口左上角的x轴及y轴距离
var x2 = e.clientX;
var y2 = e.clientY;
//计算此时元素应该距离视口左上角的x轴及y轴距离
var X = x0 + (x2 - x1);
var Y = y0 + (y2 - y1);
/******范围限定*******/
//获取鼠标移动时元素四边的瞬时值
var L = X;
var R = X + EW;
var T = Y;
var B = Y + EH;
//在将X和Y赋值给left和top之前,进行范围限定。只有在范围内时,才进行相应的移动
//如果脱离左侧范围,则left置L0
if(L < L0){X = L0;}
//如果脱离右侧范围,则left置为R0
if(R > R0){X = R0 - EW;}
//如果脱离上侧范围,则top置T0
if(T < T0){Y = T0;}
//如果脱离下侧范围,则top置为B0
if(B > B0){Y = B0 - EH;} //将X和Y的值赋给left和top,使元素移动到相应位置
ele.style.left = X + 'px';
ele.style.top = Y + 'px'; bump(test2,test1);
}
var mouseupHandler = function(e){
//鼠标抬起时,表示停止运动
isMoving = false;
//释放全局捕获
if(ele.releaseCapture){
ele.releaseCapture();
}
}
var preventDefaultHandler = function(e){
e = e || event;
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue = false;
}
//IE8-浏览器阻止默认行为
if(ele.setCapture){
ele.setCapture();
} }
addEvent(ele,'mousedown',mousedownHandler);
addEvent(ele,'mousedown',preventDefaultHandler);
addEvent(document,'mousemove',mousemoveHandler)
addEvent(document,'mouseup',mouseupHandler) }; drag(test1);
drag(test2);
</script>

源码查看

javascript动画系列第三篇——碰撞检测的更多相关文章

  1. javascript面向对象系列第三篇——实现继承的3种形式

    × 目录 [1]原型继承 [2]伪类继承 [3]组合继承 前面的话 学习如何创建对象是理解面向对象编程的第一步,第二步是理解继承.本文是javascript面向对象系列第三篇——实现继承的3种形式 [ ...

  2. 深入理解javascript函数系列第三篇——属性和方法

    × 目录 [1]属性 [2]方法 前面的话 函数是javascript中的特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本 ...

  3. 深入理解javascript作用域系列第三篇——声明提升(hoisting)

    × 目录 [1]变量 [2]函数 [3]优先 前面的话 一般认为,javascript代码在执行时是由上到下一行一行执行的.但实际上这并不完全正确,主要是因为声明提升的存在.本文是深入理解javasc ...

  4. 深入理解javascript作用域系列第三篇

    前面的话 一般认为,javascript代码在执行时是由上到下一行一行执行的.但实际上这并不完全正确,主要是因为声明提升的存在.本文是深入理解javascript作用域系列第三篇——声明提升(hois ...

  5. 深入理解javascript函数系列第三篇

    前面的话 函数是javascript中特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本文是深入理解javascript函数 ...

  6. javascript动画系列第四篇——拖拽改变元素大小

    × 目录 [1]原理简介 [2]范围圈定 [3]大小改变[4]代码优化 前面的话 拖拽可以让元素移动,也可以改变元素大小.本文将详细介绍拖拽改变元素大小的效果实现 原理简介 拖拽让元素移动,是改变定位 ...

  7. javascript运动系列第三篇——曲线运动

    × 目录 [1]圆周运动[2]三维圆周 [3]钟摆运动 [4]抛物线[5]流体运动 前面的话 上一篇介绍了变速运动,但只实现了直线运动.如果元素的left和top同时运动,并遵循不同的曲线公式,则会进 ...

  8. 深入理解javascript对象系列第三篇——神秘的属性描述符

    × 目录 [1]类型 [2]方法 [3]详述[4]状态 前面的话 对于操作系统中的文件,我们可以驾轻就熟将其设置为只读.隐藏.系统文件或普通文件.于对象来说,属性描述符提供类似的功能,用来描述对象的值 ...

  9. javascript动画系列第五篇——模拟滚动条

    × 目录 [1]原理介绍 [2]数字加减 [3]元素尺寸[4]内容滚动 前面的话 当元素内容溢出元素尺寸范围时,会出现滚动条.但由于滚动条在各浏览器下表现不同,兼容性不好.所以,模拟滚动条也是很常见的 ...

随机推荐

  1. HTML5 程序设计 - 使用HTML5 Canvas API

    请你跟着本篇示例代码实现每个示例,30分钟后,你会高喊:“HTML5 Canvas?!在哥面前,那都不是事儿!” 呵呵.不要被滚动条吓到,很多都是代码和图片.我没有分开写,不过上面给大家提供了目录,方 ...

  2. c# cache 缓存

    System.Web.Caching简介 /// <summary> /// 创建随机字符串 /// </summary> /// <returns></re ...

  3. easy-ui 小白进阶史(一):加载数据,easy-ui显示

    作为一个没上过大学,没经过正规培训的96年的小白来说,找工作就没报特别大的希望,大不了找不到在回炉重造,继续学... 终于在海投了200份的简历之后...终于找到了...面试也挺简单的,,,第二天就去 ...

  4. Gym 100917J---dir -C(RMQ--ST)

    题目链接 http://codeforces.com/gym/100917/problem/D problem description Famous Berland coder and IT mana ...

  5. 我遇到的CocoaPods的问题(也许后期会解决,持续更新)

    在此博客中写下两类关于CocoaPods的问题: 未解决的问题:可以留着以后解决 已经解决的问题:可以备份以后回头再参考解决同样的问题 <已解决的问题> 解决方法是:pod install ...

  6. 玩了一下SDN:MININET+FLOODLIGHT,感觉这确实是一个趋势啊

    功能用增加中间层的方案来解决. 仿佛回到用交换机和路由器模拟器的感觉. 遇到执行命令小问题,狗哥搞定: mininet>mininet> dpctl dump-flows tcp:127. ...

  7. 如何实现Sublime Text3中vue文件高亮显示的最有效的方法

    今天第一次使用Sublime Text3软件,在实现vue文件高亮显示的过程中一直报错,经过了半天时间的不停尝试终于找到了最有效的一种解决方法!错误提示如下: 刚开始尝试了很多方法都不行,只要打开in ...

  8. Docker学习笔记 - Docker容器的网络基础

    一.虚拟网桥 docker0 docker0 是 linux的虚拟网桥,守护进程通过docker0给容器提供网络连接的各种服务. 网桥是数据链路层设备,通常ip地址是网络层的设置.linux的虚拟网桥 ...

  9. CentOS(十二)--crontab命令的使用方法

    crontab命令常见于Unix和Linux的操作系统之中,用于设置周期性被执行的指令.该命令从标准输入设备读取指令,并将其存放于"crontab"文件中,以供之后读取和执行. 在 ...

  10. 关于TCP连接状态的解释

    TCP各个状态主要存在于三次握手和四次挥手的过程 1.TCP建立连接时的三次握手: 服务端应用监听端口处于LISTEN状态,等待建立连接. 第一次握手:客户端发送SYN=一个随机数,然后进入SYN_S ...