Touch in three js

How to enable the mobile ring event for this code, I’ve tried everything else I can’t → https://jsfiddle.net/IuryBorges/6na9q045/33/

1 Like

Are you trying to enable orbit controls so you can rotate around or zoom in to the model on mobile?

If so, see the OrbitControls example: three.js docs

If you look at the code I’m using fragment shader, even the 3D model was made using glsl code, I just want to access Android touch

You can add event listeners with JavaScript directly using the Touch API (outside of ThreeJS). See: Touch events - Web APIs | MDN

i tried to use this but it doesn’t work for some reason:

document.getElementsByTagName(“canvas”)[0].addEventListener(‘touchmove’, function(event) {
alert(“teste”);
event.preventDefault();
var touch = event.touches[0];

        this.mousePosition.setX(touch.pageX);
       this.mousePosition.setX(this.height - touch.pageY);
}, false);
1 Like

here is my solution in a similar problem, I think …
First fo all, to have both (mobile and desktop) navigation the better solution I’ve found is having two behavior.
With this solution is possible to manage orbit and click(tap) to manage raycast only when a tap is a real tap and not a pointermove.
For desktop, IOS device and Android.
For Apple device works only pointermove, for Android device it depends from the age.

I’m sorry, I don’t have a sample working now couse the project was changed.

I forgot
of course my orbit is an OrbitControls

I hope it can helps

// mouse event vars
let isSwiping = false;
const delta = 1.5;
let sogliaMove = 0;
let startX;
let startY;
let firstTouch = true;
let firstTime = true;
// device detection
let isMobile = false;

if (
  /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(
    navigator.userAgent,
  )
  || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
    navigator.userAgent.substr(0, 4),
  )
) {
  isMobile = true;
}

//pointer event works better than touch event
container.style.touchAction = 'none';
  if (isMobile) {
    container.addEventListener('pointerdown', (event) => {
      firstTouch = true; 
      startX = event.pageX;
      startY = event.pageY;

      isSwiping = false;
    });
    container.addEventListener('pointermove', (event) => {
      if (firstTouch) {
        startX = event.pageX;
        startY = event.pageY;
        firstTouch = false;
      } else {
        const diffX = Math.abs(event.pageX - startX);
        const diffY = Math.abs(event.pageY - startY);
        if (diffX < delta && diffY < delta && sogliaMove > 2) {
          // sogliaMove>2 means 2 frame still when isSwiping is true
          onDocumentTouchClick(event); // for iOS  
        }
      }
      isSwiping = true; 
    });
    container.addEventListener('pointerup', (event) => {
      const diffX = Math.abs(event.pageX - startX);
      const diffY = Math.abs(event.pageY - startY);
      if (diffX < delta && diffY < delta) {
        onDocumentMouseClick(event); // Android old: is better desktop solution
      }
      firstTouch = true;
    });
  } else {
//desktop behavior
    container.addEventListener('pointerdown', (event) => {
      isSwiping = false;
      startX = event.pageX;
      startY = event.pageY;
    });
    container.addEventListener('pointermove', () => {
      isSwiping = true;
    });

    container.addEventListener('pointerup', (event) => {
      const diffX = Math.abs(event.pageX - startX);
      const diffY = Math.abs(event.pageY - startY);

      if (diffX < delta && diffY < delta) {
        onDocumentMouseClick(event);
      }
    });
  }

function onDocumentTouchClick(event) {
  event.preventDefault();
  scene.updateMatrixWorld();
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

  raycaster.setFromCamera(mouse, camera);
  intersects = raycaster.intersectObject(mesh);

  if (intersects.length > 0 && firstTouch === false) {
    firstTouch = true; 
    evaluateRaycast();
  }
}

function onDocumentMouseClick(event) {
  event.preventDefault();
  if (!isSwiping) {
    scene.updateMatrixWorld();

    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

    raycaster.setFromCamera(mouse, camera);
    intersects = raycaster.intersectObject(mesh, true);

    if (intersects.length > 0) {
      evaluateRaycast(); //it continues
    }
  }
  isSwiping = false;
}