为什么canvas 的父元素(直接父元素或者祖先元素)有定位 监听事件就会失效?

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Examples</title>
<style type="text/css">
    .box{
        position: absolute;
        left: 100px;
        top: 100px;
        width: 500px;
        height: 500px;
    }
    .box2{
        width: 200px;
        height: 200px;
        
    }
    .box3{
        width: 200px;
        height: 200px;
    }
    #canvasId{
        position: absolute;
        left: 50%;
        top: 10px;
        margin-left: -200px;
    }
 
 </style>
</head>
<body>
    <div class="box">
        <div class="box2">
            <div class="box3">
                <canvas id="canvasId" width="200" height="200"></canvas>
            </div>
        </div>
    </div>
    <!-- 此处的长宽是指画布的大小 -->
    <script type="text/javascript">
        var canvas = document.getElementById("canvasId");
        var ctx = canvas.getContext("2d");
        var ox = 110;//圆环在画布上的x轴坐标
        var oy = 110;//圆环在画布上的y轴坐标
        var or = 80;//圆环半径
        var br = 20;//圆珠半径
        var moveFlag = false;
         
        function offset(r,d) {//根据弧度与距离计算偏移坐标
            return {x: -Math.sin(r)*d, y: Math.cos(r)*d};
        };
         
        function draw(n) {
            console.log(canvas.width);
            ctx.clearRect(0,0,canvas.width,canvas.height);
            //clearRect()==>HTML5中的方法,用于擦除指定区域  
            //调用示例 context.clearRect(x,y,width,height);

            //底环
            ctx.strokeStyle = "#ccc";//颜色
            ctx.lineWidth = 10;//宽度
            ctx.beginPath();
            //Math.PI:圆周率
            ctx.arc(ox,oy,or,0,2*Math.PI,true);
            ctx.stroke();

            //有色环
            ctx.strokeStyle = "#ff5151";//颜色
            ctx.lineWidth = 10;//宽度
            ctx.beginPath();
            ctx.arc(ox,oy,or,0.5*Math.PI,(n*2+0.5)*Math.PI,false);
            ctx.stroke();

            //中间文字
            ctx.fillStyle = "#ff5151";//颜色
            ctx.font = "70px Arial";//字号
            ctx.textAlign = "center";
            ctx.textBaseline = "middle";
            //计算数值的取值区间
            ctx.fillText(Math.round(n/5*100+10)+"°",ox,oy);

            //圆珠
            ctx.fillStyle = "#ff5151";
            ctx.beginPath();
            var d =  offset(n*2*Math.PI,or);
            console.log(d);
            ctx.arc(ox+d.x,oy+d.y,br,0,2*Math.PI,true);
            ctx.fill();
        }
        var on = ("ontouchstart" in document)? {
            start: "touchstart", move: "touchmove", end: "touchend"
        } : {
            start: "mousedown", move: "mousemove", end: "mouseup"
        };//是否支持触屏
        //监听鼠标坐标
        function getXY(e,obj) {
            var et = e.touches? e.touches[0] : e;
            var x = et.clientX;
            var y = et.clientY;
            return {
                x : x - obj.offsetLeft + (document.body.scrollLeft || document.documentElement.scrollLeft),
                y : y - obj.offsetTop  + (document.body.scrollTop || document.documentElement.scrollTop)
            }
        }
         
        //事件监听
        canvas.addEventListener(on.start, function(e) {
            moveFlag = true;
        }, false);
        canvas.addEventListener(on.move, function(e) {
            if (moveFlag) {
                var k = getXY(e,canvas);
                var r = Math.atan2(k.x-ox, oy-k.y);
                draw((Math.PI+r)/(2*Math.PI));
            }
        }, false);
        canvas.addEventListener(on.end, function(e) {
            moveFlag = false;
        }, false);
         
        draw(0.7);
    </script>
</body>

</html>
阅读 4.9k
1 个回答
function getXY(e,obj) {
    var et = e.touches? e.touches[0] : e;
    var x = et.clientX;
    var y = et.clientY;
    return {
        x : x - obj.offsetLeft + (document.body.scrollLeft || document.documentElement.scrollLeft),
        y : y - obj.offsetTop  + (document.body.scrollTop || document.documentElement.scrollTop)
    }
}

因为你的getXY函数中使用的offsetLeftoffsetTop是有一定的兼容问题的。
其在有些浏览器中是根据父元素获取其偏移值,有些却是根据body元素获取偏移值。
这里可以使用getBoundingClientRect获取对应元素到视窗的距离
例如:

function getXY(e) {
    var et = e.touches? e.touches[0] : e;
    var x = et.clientX;
    var y = et.clientY;
    return {
        x : x - canvas.getBoundingClientRect().left + (document.body.scrollLeft || document.documentElement.scrollLeft),
        y : y - canvas.getBoundingClientRect().top  + (document.body.scrollTop || document.documentElement.scrollTop)
    }
}
推荐问题