碰撞检测

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        *{
            padding: 0;
            margin: 0;
        }
        ul{
            list-style:none;
            width: 900px;
            height: 500px;
            margin:50px auto;
        }
        img{
            display:block;
            width: 100%;
            height: 100%;
        }
        li{
            float:left;
            width: 200px;
            height: 150px;
            margin:10px;
            border:1px solid blue;
            cursor:move;
        }
        .active{
            border:1px dashed #ccc;
        }
    </style>
</head>
<body>
    <ul id="list">
        <li><img src="./img/1.jpg" alt=""></li>
        <li><img src="./img/2.jpg" alt=""></li>
        <li><img src="./img/3.jpg" alt=""></li>
        <li><img src="./img/4.jpg" alt=""></li>
        <li><img src="./img/5.jpg" alt=""></li>
        <li><img src="./img/6.jpg" alt=""></li>
        <li><img src="./img/7.jpg" alt=""></li>
        <li><img src="./img/8.jpg" alt=""></li>
        <li><img src="./img/9.jpg" alt=""></li>
        <li><img src="./img/10.jpg" alt=""></li>
        <li><img src="./img/11.jpg" alt=""></li>
        <li><img src="./img/12.jpg" alt=""></li>
    </ul>

    <script src="./base.js"></script>
    <script>

    /*思路:封装一个拖拽的函数,使每个对象可以实现拖拽
        (1)分析:拖拽的实现需要绝对定位脱离文档流
            问题:给css设置position:absolute;图片重叠在一处
            解决:先通过循环利用每个元素的offsetLeft以及offsetTop记住每个元素的位置,然后赋值给各个元素的left和top值,将所有元素的left和top值设置好之后再给元素脱离文档流 并且清除元素的margin值,循环调用拖拽函数.

        (2)如何让元素抬起鼠标的时候回到原来的位置?
            解决:调用move函数,move(操作的对象,回到的位置(json对象),回调函数);
            问题:位置如何找?
            解决:循环把各个元素的位置按照对象的形式{"left":值,"top":值}保存在数组里面,可以通过下标来访到每个元素的位置

        (3)层级问题
            解决:利用计数器让点击元素层级++;

        (4)碰撞检测
            思路:封装一个碰撞的函数,返回碰撞最多那个元素的下标(因为咱们要通过下标找位置);
                找到两个元素:①拖拽元素obj②碰撞元素(得循坏查找拖拽元素是否占了人家的位置){要除去本身}
                找没碰的范围,排除没碰的范围剩下的就是碰了
                左:boxL+boxW<objL
                右:objL+objW<boxL
                上:boxT+boxH<objT
                下:objT+objH<boxT


        (5)找碰撞最多的元素(即左上角对角线最短的)以及这个元素的下标
            问题:因为要检测的碰撞元素时除本身外的其他所有元素
                有可能它同时跟好多元素进行碰撞
                咱们要在一堆里面找距离最小的
                找最小距离的方法:先假设某个数最小完后跟后面一堆数进行比较,如果后面出现比假设的最小数还小的数,那么将这个数赋给最小数,这个l对应哪个元素的下标i赋给最小数的下标
                在循环结束找到最小值的下标返回;
                在鼠标抬起的时候,调用碰撞的函数bb(obj),将它返回值保存在_index里面

        (6)换位置
            对象(aLi)                    下标          位置(arr)

            拖拽元素aLi[index](obj)      index             arr[index]
            碰撞元素aLi[_index]          _index         arr[_index]
 

            如果没碰到(即返回值-1),回到拖拽元素自己的位置move(obj,arr[index]);
            如果碰到了,进行位置交换move(obj,arr[_index])
                                       move(aLi[_index],arr[index])
            同时要把保存位置的数组里面的位置进行交换*/

        var oList=document.getElementById("list");
        var aLi=oList.getElementsByTagName("li");
        var zIndex=1;
        var arr=[];
        for(var i=0;i<aLi.length;i++){
            aLi[i].style.left=aLi[i].offsetLeft+"px";
            aLi[i].style.top=aLi[i].offsetTop+"px";
            arr.push({"left":aLi[i].offsetLeft,"top":aLi[i].offsetTop});  
        }
        for(var i=0;i<aLi.length;i++){
            aLi[i].style.position="absolute";
            aLi[i].style.margin=0;
            getDay(aLi[i],i);
        }


        function getDay(obj,index){
            obj.οnmοusedοwn=function(ev){
                obj.style.zIndex=zIndex++;
                var evt=ev||window.event;
                var dx=evt.offsetX;
                var dy=evt.offsetY;
                document.οnmοusemοve=function(ev){
                    var evt=ev||window.event;
                    var x=evt.clientX; 
                    var y=evt.clientY;
                    obj.style.left=x-dx+"px";
                    obj.style.top=y-dy+"px";
                    ww=PZ(obj);
                    for(var i=0;i<aLi.length;i++){
                        aLi[i].className="";
                    }
                    if(ww!=-1){
                        aLi[ww].className="active";
                    }
                    return false;
                }
                document.οnmοuseup=function(){
                    document.οnmοusemοve=null;
                    ww=PZ(obj);
                    if(ww==-1){
                        move(obj,arr[index]);
                    }else{
                        move(obj,arr[ww]);
                        move(aLi[ww],arr[index]);//元素和位置
                        //出现问题,都给第一张换位
                        var timep=arr[index];
                        arr[index]=arr[ww];
                        arr[ww]=timep;
                        for(var i=0;i<aLi.length;i++){
                            aLi[i].className="";
                        }
                        
                    }
                    return false;
                }
            }
        }

        function PZ(obj){
            var oL=obj.offsetLeft;
            var oT=obj.offsetTop;
            var oW=obj.offsetWidth;
            var oH=obj.offsetHeight;
            var min=100000;
            var mIndex=-1;

            for(var i=0;i<aLi.length;i++){
                //不能跟本身比较
                if(aLi[i]==obj){
                    continue;
                }
                var aL=aLi[i].offsetLeft;
                var aT=aLi[i].offsetTop;
                var aW=aLi[i].offsetWidth;
                var aH=aLi[i].offsetHeight;
                //找一个判断一个
                if(oL+oW<aL||oL>aL+aW || oT+oH<aT || oT>aT+aH){
                    //没碰的
                }else{
                    /*console.log("碰到了"+i);*/
                    var a=oL-aL;
                    var b=aT-oT;
                    var l=Math.sqrt(a*a+b*b);
                    if(l<min){
                        min=l;
                        mIndex=i;
                    }
                }
            }
            return mIndex;
        }
    </script>
</body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值