Ajit Kumar Singh
Ajit Kumar Singh

Reputation: 115

Touchenter and touchleave events support

I read about touchenter and touchleave events, at mozilla website and w3 website, but can not find any browser to support it or any javascript library that mimics that effect.

Please suggest what could be done as there workaround, as I am working for some mouseover like effect , event gets triggered when fingers enter the element, not when user lifts and touches elements again.

Thanks :)

Upvotes: 10

Views: 19338

Answers (6)

Marcel van der Drift
Marcel van der Drift

Reputation: 373

This works for me. In callbacks I just need the element; not the mouse/touch event and not the context (don't use 'this' in callback).

pointer.ts

/**
 *  Simulate touchenter and touchleave by tracking touchmove. See https://stackoverflow.com/questions/23111671/touchenter-and-touchleave-events-support
 */
const touchEventSimulator = {

    // enterElementCallback stores element as key and callback as value
    enterElementCallback: new Map(),
    leaveElementCallback: new Map(),
    previousElement: null,

    init: function() {
        window.addEventListener('touchmove', event => {
            var currentElement = document.elementFromPoint(event.touches[0].clientX, event.touches[0].clientY)
            if (currentElement !== this.previousElement) {

                // touch leave
                const leaveCallback = this.leaveElementCallback.get(this.previousElement)
                if (leaveCallback) {
                    leaveCallback.call(null, this.previousElement)
                }

                // touch enter
                const enterCallback = this.enterElementCallback.get(currentElement)
                if (enterCallback) {
                    enterCallback.call(null, currentElement)
                }

                // Current element will be the previous one, next time we check.
                this.previousElement = currentElement;
            }
        });
    },
    onEnter(element, callback) {
        this.enterElementCallback.set(element, callback);
    },
    onLeave(element, callback) {
        this.leaveElementCallback.set(element, callback);
    }
}

const mouseAvailable = matchMedia('(pointer:fine)').matches;

/**
 * Pointer is a wrapper for mouse and (simulated) touch events
 */
export const pointer = {
    mouseAvailable,

    init() {
        if (!mouseAvailable) {
            touchEventSimulator.init()
        }
    },

    onEnter: (element, callback) => {
        if (mouseAvailable) {
            element.addEventListener('mouseenter', ()=>callback.call(null, element))
        } else {
            touchEventSimulator.onEnter(element, callback)
        }
    },

    onLeave: (element, callback) => {
        if (mouseAvailable) {
            element.addEventListener('mouseleave', ()=>callback.call(null, element))
        } else {
            touchEventSimulator.onLeave(element, callback)
        }
    }
}

example.ts

import {pointer} from './pointer';

pointer.init();
const element = document.getElementById('test');
pointer.onEnter(anchor, element=>{
    console.log('enter', element)
})

pointer.onLeave(anchor, element=>{
    console.log('leave', element)
})

Upvotes: 0

Guilherme Oliveira
Guilherme Oliveira

Reputation: 2369

Currently, there is no support for such events at core, however it is possible to simulate them.

I Created a small script to make onTouchEnter and onTouchLeave methods available. Very simple use (To test the snippet activate the mobile version of this website, or use it at a smartphone browser)

onTouchEnter('.some-selector', function(element,event){/*DO ANYTHING*/})
onTouchLeave('.some-selector', function(element,event){/*DO ANYTHING*/})

The script bellow uses document.elementFromPoint to make the magic.

let onTouchLeaveEvents = [];
let onTouchEnterEvents = [];
const onTouchEnter = function (selector, fn) {
    onTouchEnterEvents.push([selector, fn]);
    return function () {
        onTouchEnterEvents.slice().map(function (e, i) {
            if (e[0] === selector && e[1] === fn) {
                onTouchEnterEvents.splice(1, i);
            }
        });
    };
};

const onTouchLeave = function (selector, fn) {
    onTouchLeaveEvents.push([selector, fn]);
    return function () {
        onTouchLeaveEvents.slice().map(function (e, i) {
            if (e[0] === selector && e[1] === fn) {
                onTouchLeaveEvents.splice(1, i);
            }
        });
    };
};

let lastTouchLeave;
let lastTouchEnter;
document.addEventListener('touchmove', function (e) {
    var el = document.elementFromPoint(e.touches[0].clientX, e.touches[0].clientY);
    if (!el) return;
  
  onTouchLeaveEvents.map((event) => {
    if (el!=lastTouchEnter && lastTouchEnter && lastTouchEnter.matches(event[0])) {
      
        
            if (lastTouchEnter !== lastTouchLeave ) {
                event[1](lastTouchEnter, e);
        lastTouchLeave = lastTouchEnter;
        lastTouchEnter = null
            }
            
        }
    });
  
    onTouchEnterEvents.map((event) => {
        if (el.matches(event[0]) && el!==lastTouchEnter) {
            lastTouchEnter = el;
      lastTouchLeave = null;
      event[1](el, e);
     }
    });

});

onTouchEnter('.area',function(el,e){
  el.classList.add('hover')
})
onTouchLeave('.area',function(el,e){
  el.classList.remove('hover')
})
.area {
  width:100px;
  height:100px;
  margin:2px ;
  font-size:12px;
  display:flex;
  align-items:center;
  justify-content:center;
  float:left;
}
.area.hover{
  background-color:#333 !important;
  color:#fff;
}
#div-1{background-color:#f00;}
#div-2{background-color:#0f0;}
#div-3{background-color:#00f;}
body{
overflow:hidden
}
<div id="div-1" class="area">DIV 1</div>
<div id="div-2" class="area">DIV 2</div>
<div id="div-3" class="area">DIV 3</div>

This GIST contains the same code as above, for improvements, please create comments there.

Upvotes: 0

diyism
diyism

Reputation: 12955

W3C removed ontouchenter and ontouchleave, so that we can only do these(with zepto.js, touch.js, ontouchmove, elementFromPoint):

var last_touched_button='';
$('#container,#button1,#button2').on('touchmove',function(e){
      var ele=document.elementFromPoint(e.touches[0].clientX, e.touches[0].clientY);
      if (ele==document.getElementById('button1'))
      {last_touched_button='button1';
      }
      else if (ele==document.getElementById('button2'))
      {last_touched_button='button2';
      }
});
$('#container,#button1,#button2').on('swipeLeft',function(e){
      console.log('the button '+last_touched_button+' triggered swipe_into_left_side event or swipe_out_from_left_side event!');
});

Upvotes: 1

rvignacio
rvignacio

Reputation: 1740

You're referencing an old draft, the latest one removed the touchenter and touchleave events.

Upvotes: 11

Lorenzo Von Matterhorn
Lorenzo Von Matterhorn

Reputation: 383

I suggest that you use

document.elementFromPoint(touch.x, touch.y);

on touchmove event.

Upvotes: 24

Daksh Shah
Daksh Shah

Reputation: 3113

There is a list here stating the version-wise compatibility. Currently Chrome, Opera, iOS Safari, Android Browser, Blackberry Browser, Opera Mobile, Chrome for Android, Firefox for android support this feature

Upvotes: 1

Related Questions