javascript - PointerEvents: Detect touching "through" an element - Stack Overflow

Using pointer events, I can't find the right event to trigger for finger-based touches on smartpho

Using pointer events, I can't find the right event to trigger for finger-based touches on smartphones (tested with Chrome Android and Chrome Devtools with mobile emulation).

What I need: A "hover" event if you touch action passes through an element while holding the finger down moving over the screen.

That is, put your finger down outside the element, move through it, and move finger up only after pletely passing through the element.

I attached a code snipped to clearify: I don't need events for the blue elements, I would only need respective "in/out" events for the red element in the snippet. The sample JS code will fire for the mouse, but on mobile it does not trigger any console.infos.

var elem = document.querySelector(".element");

elem.addEventListener("pointerover", function() {
    console.clear();
    console.info("pointerover triggered");
});
elem.addEventListener("pointerenter", function() {
    console.clear();
    console.info("pointerenter triggered");
});
elem.addEventListener("pointerleave", function() {
    console.clear();
    console.info("pointerleave triggered");
});
.outer {
    width: 100px;
    height: 100px;
    border: 3px solid grey;
    font-size: 12px;
    color: white;
    text-align:center;
    touch-action: none;
    
}

.start {
   position: relative;
   top:0px;
   left:0px;
   width: 100px;
   height: 20px;
   background-color: blue;
}

.element {
   position: relative;
   top: 20px;
   left: 0px;
   width: 100px;
   height: 20px;
   background-color: red;
}

.end {
   position: relative;
   top: 40px;
   right: 0;
   width: 100px;
   height: 20px;
   background-color: blue;
}
<div class="outer">
    <div class="start">Start touch here</div>
    <div class="element">Move over here</div>
    <div class="end">End touch here</div>
</div>

Using pointer events, I can't find the right event to trigger for finger-based touches on smartphones (tested with Chrome Android and Chrome Devtools with mobile emulation).

What I need: A "hover" event if you touch action passes through an element while holding the finger down moving over the screen.

That is, put your finger down outside the element, move through it, and move finger up only after pletely passing through the element.

I attached a code snipped to clearify: I don't need events for the blue elements, I would only need respective "in/out" events for the red element in the snippet. The sample JS code will fire for the mouse, but on mobile it does not trigger any console.infos.

var elem = document.querySelector(".element");

elem.addEventListener("pointerover", function() {
    console.clear();
    console.info("pointerover triggered");
});
elem.addEventListener("pointerenter", function() {
    console.clear();
    console.info("pointerenter triggered");
});
elem.addEventListener("pointerleave", function() {
    console.clear();
    console.info("pointerleave triggered");
});
.outer {
    width: 100px;
    height: 100px;
    border: 3px solid grey;
    font-size: 12px;
    color: white;
    text-align:center;
    touch-action: none;
    
}

.start {
   position: relative;
   top:0px;
   left:0px;
   width: 100px;
   height: 20px;
   background-color: blue;
}

.element {
   position: relative;
   top: 20px;
   left: 0px;
   width: 100px;
   height: 20px;
   background-color: red;
}

.end {
   position: relative;
   top: 40px;
   right: 0;
   width: 100px;
   height: 20px;
   background-color: blue;
}
<div class="outer">
    <div class="start">Start touch here</div>
    <div class="element">Move over here</div>
    <div class="end">End touch here</div>
</div>

Share Improve this question edited Nov 23, 2018 at 14:25 Bharata 14.2k6 gold badges43 silver badges53 bronze badges asked Nov 19, 2018 at 14:37 DynalonDynalon 6,81410 gold badges58 silver badges87 bronze badges 5
  • I don't think those events work on mobile at all. Try with pointermove – Roberto Zvjerković Commented Nov 19, 2018 at 14:40
  • Neither pointermove nor pointerover will be fired when start AND end of the touch is outside the red element. – Dynalon Commented Nov 19, 2018 at 14:41
  • pointerover doesn't work on mobile either. You will have to manually implement such logic, I'm afraid. – Roberto Zvjerković Commented Nov 19, 2018 at 14:51
  • I hope that I understand you correctly because in your question we could misinterpret the task – it is relatively difficalt to understand the task without images. After a lot of shaman dances with a tambourine (a lot of time) I found two solutions for you. – Bharata Commented Nov 22, 2018 at 17:17
  • @Bharata I think thats unfair to claim, I provided a running snippet that works on dekstop with the mouse but not on a smartphone. What I asked for is how to get that working on a smartphone, so I think its pretty clear what my question is. – Dynalon Commented Nov 23, 2018 at 7:56
Add a ment  | 

2 Answers 2

Reset to default 6 +200

I hope that I understand you correctly. I wrote and tested for you two different solutions: pointerevents and touch events. In each move event from this events you can detect the current element with the function document.elementFromPoint().

Solution with pointerevents

Maybe you can use pointerevents – they work in Chrome Devtools with mobile emulation, but not work on my Android device (I think my device is too old). Or maybe you can use it with Pointer Events Polyfill. The Browser patibility for pointerevents you can see here.

var elementFromPoint,
    isFingerDown = false,
    isThroughElemMoved = false,
    elem = document.querySelector('.element'),
    output = document.querySelector('#output');

document.addEventListener('pointerdown', function(e)
{
    if(elem != e.target)
    {
        isFingerDown = true;
        output.innerHTML = 'pointer-START';
    }
});

document.addEventListener('pointermove', function(e)
{
    elementFromPoint = document.elementFromPoint(e.pageX - window.pageXOffset, e.pageY - window.pageYOffset);

    if(elem == elementFromPoint)
    {
        isThroughElemMoved = true;
        output.innerHTML = 'pointer-MOVE';
    }
});

document.addEventListener('pointerup', function(e)
{
    if(isFingerDown && isThroughElemMoved && elem != elementFromPoint)
        output.innerHTML = 'It is done!';

    isFingerDown = isThroughElemMoved = false;
});
.outer
{
    width: 100px;
    height: 100px;
    border: 3px solid grey;
    font-size: 12px;
    color: white;
    text-align: center;
    /*touch-action: none*/
}
.outer div{position: relative; left: 0; height: 20px}
.start{top: 0; background: blue}
.element{top: 20px; background: red}
.end{top: 40px; background: blue}
<div class="outer">
    <div class="start">Start touch here</div>
    <div class="element">Move over here</div>
    <div class="end">End touch here</div>
</div>
<br><br>
<div id="output">info</div>

Solution with touch events

But you can use touch events too. Unfortunatelly, the events touchenter and touchleave were deleted from the specification and because of them we have to write a workaround using document.elementFromPoint() too.

The following snippet works only in the mobile emulation (tested with Chrome Devtools) or on devices which support touch events (tested with Android).

var elementFromPoint,
    isFingerDown = false,
    isThroughElemMoved = false,
    elem = document.querySelector('.element'),
    output = document.querySelector('#output');

document.addEventListener('touchstart', function(e)
{
    if(elem != e.target)
    {
        isFingerDown = true;
        output.innerHTML = 'touch-START';
    }
});

document.addEventListener('touchmove', function(e)
{
    var touch = e.touches[0];
    
    elementFromPoint = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset);

    if(elem == elementFromPoint)
    {
        isThroughElemMoved = true;
        output.innerHTML = 'touch-MOVE';
    }
});

document.addEventListener('touchend', function(e)
{
    if(isFingerDown && isThroughElemMoved && elem != elementFromPoint)
        output.innerHTML = 'It is done!';

    isFingerDown = isThroughElemMoved = false;
});
.outer
{
    width: 100px;
    height: 100px;
    border: 3px solid grey;
    font-size: 12px;
    color: white;
    text-align: center;
    /*touch-action: none*/
}
.outer div{position: relative; left: 0; height: 20px}
.start{top: 0; background: blue}
.element{top: 20px; background: red}
.end{top: 40px; background: blue}
<div class="outer">
    <div class="start">Start touch here</div>
    <div class="element">Move over here</div>
    <div class="end">End touch here</div>
</div>
<br><br>
<div id="output">info</div>

Maybe the following links can help you:

  • Get element from point when you have overlapping elements?
  • How to find out the actual event.target of touchmove javascript event?

Try this

<script>
    var startElem = document.querySelector(".start");
    var endElem = document.querySelector(".end");
    var elem = document.querySelector(".element");

    var started = false;
    var passedThroughStart = false;
    var passedThroughEnd = false;
    var ended = false;

    startElem.addEventListener("pointerdown", function(e){
        started = true;
    });

    window.addEventListener("pointermove", function(e) {
        var x = e.clientX;
        var y = e.clientY;
        var bounds = elem.getBoundingClientRect();

        if( !passedThroughStart &&
            x > bounds.left && x < bounds.left + bounds.width &&
            y > bounds.top && y < bounds.top + bounds.height
        ){
            passedThroughStart = true;
        }

        if( passedThroughStart && !passedThroughEnd &&
            x > bounds.left && x < bounds.left + bounds.width &&
            y > bounds.top + bounds.height
        ){
            passedThroughEnd = true;
        }
    })

    window.addEventListener("pointerup", function(e) {
        var x = e.clientX;
        var y = e.clientY;
        var bounds = endElem.getBoundingClientRect();

        ended = ( x > bounds.left && x < bounds.left + bounds.width && y > bounds.top && y < bounds.top + bounds.height)

        if( started && passedThroughStart && passedThroughEnd && ended ){
            console.log("Hooray!");
        }

        started = false;
        passedThroughStart = false;
        passedThroughEnd = false;
        ended = false;
    });
</script>

Alternatively use pointerenter and pointerleave rather than pointermove

elem.addEventListener('pointenter', function(e) {
    passedThroughStart = true;
}
elem.addEventListener('pointleave', function(e) {
    passedThroughEnd = true;
}

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744275117a4566290.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信