前面的話 前面分別介紹了拖拽模擬和磁性吸附,當可視區域記憶體在多個可拖拽元素,就出現碰撞檢測的問題,這也是javascript動畫的一個經典問題。本篇將詳細介紹碰撞檢測 原理介紹 碰撞檢測的方法有很多,接下來使用九宮格分析法 假設黃色元素要與紅色元素進行碰撞。將紅色元素所處的區域分為9部分,自身處於第 ...
前面的話
前面分別介紹了拖拽模擬和磁性吸附,當可視區域記憶體在多個可拖拽元素,就出現碰撞檢測的問題,這也是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 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; } } function drag(obj){ obj.onmousedown = function(e){ e = e || event; //提升當前元素的層級 obj.style.zIndex = '1'; //獲取元素距離定位父級的x軸及y軸距離 var x0 = this.offsetLeft; var y0 = this.offsetTop; //獲取此時滑鼠距離視口左上角的x軸及y軸距離 var x1 = e.clientX; var y1 = e.clientY; //滑鼠按下時,獲得此時的頁面區域 var L0 = 0; var R0 = document.documentElement.clientWidth; var T0 = 0; var B0 = document.documentElement.clientHeight; //滑鼠按下時,獲得此時的元素寬高 var EH = obj.offsetHeight; var EW = obj.offsetWidth; document.onmousemove = function(e){ e = e || event; //獲取此時滑鼠距離視口左上角的x軸及y軸距離 x2 = e.clientX; 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;} obj.style.left = X + 'px'; obj.style.top = Y + 'px'; //運行碰撞檢測函數 bump(test2,test1,'orange') } document.onmouseup = function(e){ //降低當前元素的層級 obj.style.zIndex = '0'; //當滑鼠抬起時,拖拽結束,則將onmousemove賦值為null即可 document.onmousemove = null; //釋放全局捕獲 if(obj.releaseCapture){ obj.releaseCapture(); } } //阻止預設行為 return false; //IE8-瀏覽器阻止預設行為 if(obj.setCapture){ obj.setCapture(); } } } drag(test1); drag(test2); </script>