• JS判断鼠标是否在三角形内


    做项目的时候需要实现一个翻页按钮的效果,如下图:

    一开始想到用图片热区做,可是后来发现热区做有问题,有一个按钮不能点击,调了层级顺序后可以点击,但是另外一个按钮又不能点击,于是决定模拟一个三角形热区的功能。

    首先:

    判断鼠标坐标是否在三角形内有很多种方法,比较简单的是面积法,即把一个大三角形(T)按照鼠标当前的点连接三个顶点,分成三份(A、B、C),然后三个小三角形面积相加等于原来那个大三角形的面积,得出公式:T = A + B + C。但是JS有误差,所以用 Math.abs(A + B + C - T) < 0.0001 减小误差。


    如何求三角形面积呢?

    1. 首先要求得三条边的边长a, b, c,然后再令 p = (a + b + c) / 2

    2. 套用求三角形面积公式算出三角型面积S:即 S = Math.sqrt(p * (p - a) * (p - b) * (p - c))


    现在还不知道三条边的边长,但是三角形三个顶点是已知的,那么可以用任意两点求得距离,算出三条边长。

    已知任意两点p1(x1, y1)、p2(x2, y2)的坐标如何求边长?

    X轴坐标之差的平方加上Y轴坐标之差的平方,然后对其值开根号就是这两点间的距离。

    得出公式

    L = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2))

    至此即可求出三角形的面积,再根据鼠标当前位置算出大三角形跟三个小三角形的面积,即可判断出此点是否在三角形内。

    下面提供示例:

    此方法已封装好直接调用即可

    onTriangle(obj, x1, y1, x2, y2, x3, y3, inFn, outFn, clickFn)

    obj为要判断的对象,x1、y1、x2、y2、x3、y3为三角形三个顶点的坐标,inFn为鼠标移入时的函数,outFn为鼠标移出时的函数,clickFn为鼠标点击时的函数。

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>判断鼠标是否在三角形内</title>
    <style>
    .box { 0; height:0; border:100px solid transparent; border-left-color:#000; border-bottom-color:#000; border-right-color:#369; border-top-color:#369; cursor:pointer; }
    </style>
    <script>
    window.onload = function () {
        var oBox = document.getElementsByTagName('div')[0];
        
        var tri1X1 = posLeft(oBox);
        var tri1X2 = tri1X1 + oBox.offsetWidth;
        var tri1X3 = tri1X2;
        
        var tri1Y1 = posTop(oBox);
        var tri1Y2 = tri1Y1;
        var tri1Y3 = tri1Y2 + oBox.offsetHeight;
        
        var tri2X1 = posLeft(oBox);
        var tri2X2 = tri2X1;
        var tri2X3 = tri2X2 + oBox.offsetWidth;
        
        var tri2Y1 = posTop(oBox);
        var tri2Y2 = tri2Y1 + oBox.offsetHeight;
        var tri2Y3 = tri2Y2;
        
        onTriangle(oBox, tri1X1, tri1Y1, tri1X2, tri1Y2, tri1X3, tri1Y3, function () {
            oBox.style.borderTopColor = '#F00';
            oBox.style.borderRightColor = '#F00';
        }, function () {
            oBox.style.borderTopColor = '#369';
            oBox.style.borderRightColor = '#369';
        }, function () {
            alert('三角1');    
        });
        
        onTriangle(oBox, tri2X1, tri2Y1, tri2X2, tri2Y2, tri2X3, tri2Y3, function () {
            oBox.style.borderLeftColor = '#F00';
            oBox.style.borderBottomColor = '#F00';
        }, function () {
            oBox.style.borderLeftColor = '#000';
            oBox.style.borderBottomColor = '#000';
        }, function () {
            alert('三角2');    
        });
    };

    function onTriangle(obj, x1, y1, x2, y2, x3, y3, inFn, outFn, clickFn)
    {
        bindEvent(obj, 'mouseover', function () {
            var triAll = triangleArea(x1, y1, x2, y2, x3, y3);
            
            bindEvent(obj, 'mousemove', function (ev) {
                var ev = ev || window.event;
                
                var disX = ev.clientX;
                var disY = ev.clientY;
                
                var tri1 = triangleArea(x1, y1, x2, y2, disX, disY);
                var tri2 = triangleArea(x2, y2, x3, y3, disX, disY);
                var tri3 = triangleArea(x3, y3, x1, y1, disX, disY);
                
                var isIn = Math.abs(tri1 + tri2 + tri3 - triAll) < 1/10000;
                
                if(isIn)
                {
                    if(inFn)
                    {
                        inFn.call(this);    
                    }
                    
                    if(clickFn)
                    {
                        bindEvent(obj, 'click', clickFn);
                    }
                }
                else
                {
                    if(outFn)
                    {
                        outFn.call(this);
                        
                    }
                    
                    if(clickFn)
                    {
                        delEvent(obj, 'click', clickFn);
                    }
                }
            });
        });
        
        bindEvent(obj, 'mouseout', outFn);
    }

    function delEvent(obj, ev, fn)
    {
        if(obj.removeEventListener)
        {
            obj.removeEventListener(ev, fn, false);
        }
        else
        {
            obj.detachEvent('on' + ev, fn);
        }
    }

    function bindEvent(obj, ev, fn)
    {
        if(obj.addEventListener)
        {
            obj.addEventListener(ev, fn, false);
        }
        else
        {
            obj.attachEvent('on' + ev, function () {
                fn.call(obj);
            });
        }
    }

    function posLeft(obj)
    {
        var left = 0;
        
        while(obj)
        {
            left += obj.offsetLeft;
            obj = obj.offsetParent;
        };
        
        return left;
    }

    function posTop(obj)
    {
        var top = 0;
        
        while(obj)
        {
            top += obj.offsetTop;
            obj = obj.offsetParent;    
        }
        
        return top;
    }

    function triangleArea(x1, y1, x2, y2, x3, y3)
    {
        var a = dist(x1, y1, x2, y2);
        var b = dist(x2, y2, x3, y3);
        var c = dist(x3, y3, x1, y1);
        var p = (a + b + c) / 2;
        var area = Math.sqrt(p * (p - a) * (p - b) * (p - c));
        
        return area;
    };

    function dist(x1, y1, x2, y2)
    {
        return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));    
    }
    </script>
    </head>

    <body>
    <div class="box"></div>
    </body>
    </html>

  • 相关阅读:
    Android之遍历SD卡所有文件显示在ListView
    Android之ViewPager
    控制ViewPager的切换速度
    Android中显示sd卡的图片和视频
    java中主线程等待所有子线程结束
    Android之ViewFlipper实现图片切换
    Android闹钟服务详解
    Gradle基本操作入手
    设计模式
    【CSON原创】 基于HTML5的小球物理测试系统
  • 原文地址:https://www.cnblogs.com/baie/p/2652918.html
Copyright © 2020-2023  润新知