title: Touch Behaviour of onMouseWheel on Mobile Devices - three.js
body: <p>How to implement forward and backward scroll on Mobile Touch Devices or have the same behaviour as on Desktop (onMouseWheel)? Examples:</p>
  
  <p>JS Fiddle: <a href="https://jsfiddle.net/xzwve647/" rel="nofollow noreferrer">https://jsfiddle.net/xzwve647/</a></p>
  
  <p>Desktop (animation work ok on Desktop back and forth) </p>
  
  <p><strong>Mobile (animation doesn't work backwards - works only forward):</strong></p>
  
  <pre><code>function onTouchStart(event) {
          startY = event.touches[0].pageY;
      }
      function onTouchMove(event) {
          var delta = event.deltaY;
          if (event.deltaY &gt; 0) {
              for (var i = 0; i &lt; mixers.length; i++) {
                  mixers[i].update(clock.getDelta() * 5);
              }
          } else {
              for (var i = 0; i &lt; mixers.length; i++) {
                  mixers[i].update(clock.getDelta() * -5);
              }
          }
      }
  </code></pre>
  
  <p>Events listeners:</p>
  
  <pre><code> window.addEventListener( 'mousewheel', onMouseWheel, false );
   window.addEventListener( 'touchstart', onTouchStart, false );
   window.addEventListener( 'touchmove', onTouchMove, false );
  </code></pre>
  
  <p><div class="snippet" data-lang="js" data-hide="true" data-console="false" data-babel="false">
  <div class="snippet-code snippet-currently-hidden">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>var container, stats, controls;
  var camera, scene, renderer, light;
  var clock = new THREE.Clock();
  
  var mixer = [];
  
  var mixers = [];
  
  init();
  
  animate();
  
  function init() {
  
    container = document.createElement('div');
    document.body.appendChild(container);
  
    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.set(0, 100, 100);
  
    scene = new THREE.Scene();
  
    light = new THREE.HemisphereLight(0xffffff, 0x444444);
    light.position.set(0, 200, 0);
    scene.add(light);
  
    light = new THREE.DirectionalLight(0xffffff);
    light.position.set(0, 200, 100);
    light.castShadow = true;
    light.shadow.camera.top = 180;
    light.shadow.camera.bottom = -100;
    light.shadow.camera.left = -120;
    light.shadow.camera.right = 120;
    scene.add(light);
  
    // scene.add( new THREE.CameraHelper( light.shadow.camera ) );
  
    var grid = new THREE.GridHelper(2000, 20, 0x000000, 0x000000);
    grid.material.opacity = 0.2;
    grid.material.transparent = true;
    scene.add(grid);
  
    // model
    var loader = new THREE.FBXLoader();
    loader.load('https://threejs.org/examples/models/fbx/Samba Dancing.fbx', function(object) {
  
      object.mixer = new THREE.AnimationMixer(object);
      mixers.push(object.mixer);
  
  
      var action = object.mixer.clipAction(object.animations[0]);
      action.play();
  
  
      object.traverse(function(child) {
  
        if (child.isMesh) {
  
          child.castShadow = true;
          child.receiveShadow = true;
  
        }
  
      });
      object.position.y = 85;
  
      scene.add(object);
  
    });
  
  
    renderer = new THREE.WebGLRenderer({
      alpha: true,
      antialias: true
    });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    container.appendChild(renderer.domElement);
  
    window.addEventListener('mousewheel', onMouseWheel, false);
    window.addEventListener('touchstart', onTouchStart, false);
    window.addEventListener('touchmove', onTouchMove, false);
  
    window.addEventListener('resize', onResize, false);
  
    // stats
    stats = new Stats();
    container.appendChild(stats.dom);
  
  }
  
  
  function onResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
  }
  
  
  function onMouseWheel(event) {
  
  
    if (event.deltaY &gt; 0) {
      for (var i = 0; i &lt; mixers.length; i++) {
        mixers[i].update(clock.getDelta() * 5);
      }
    } else {
      for (var i = 0; i &lt; mixers.length; i++) {
        mixers[i].update(clock.getDelta() * -5);
  
      }
    }
  }
  
  
  function onTouchStart(event) {
  
    startY = event.touches[0].pageY;
  
  
  }
  
  function onTouchMove(event) {
  
    var delta = event.deltaY;
  
    if (event.deltaY &gt; 0) {
      for (var i = 0; i &lt; mixers.length; i++) {
        mixers[i].update(clock.getDelta() * 5);
      }
    } else {
      for (var i = 0; i &lt; mixers.length; i++) {
        mixers[i].update(clock.getDelta() * -5);
  
      }
    }
  
  
  }
  
  
  function animate() {
  
    delta = clock.getDelta();
  
    requestAnimationFrame(animate);
  
    renderer.render(scene, camera);
  
    stats.update();
  
  }</code></pre>
  <pre class="snippet-code-css lang-css prettyprint-override"><code>body {
    margin: 0px;
    overflow: hidden;
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;script src="https://threejs.org/build/three.js"&gt;&lt;/script&gt;
  &lt;script src="https://threejs.org/examples/js/controls/OrbitControls.js"&gt;&lt;/script&gt;
  &lt;script src="https://threejs.org/examples/js/libs/inflate.min.js"&gt;&lt;/script&gt;
  &lt;script src="https://threejs.org/examples/js/loaders/FBXLoader.js"&gt;&lt;/script&gt;
  &lt;script src="https://threejs.org/examples/js/WebGL.js"&gt;&lt;/script&gt;
  &lt;script src="https://threejs.org/examples/js/libs/stats.min.js"&gt;&lt;/script&gt;</code></pre>
  </div>
  </div>
  </p>