Javascript mouse event handlers not functioning properly on my android touch phone

1.1k Views Asked by At

I am working on creating a scratch card script in javascript mouse event handlers is working properly on pc but it is not on my touch phone. on pc , i hold down the left mouse button and move it around to scratch the card. on touch phone , It scratches only if i keep touching and releasing my finger on the phone screen.

;(function() {
  var global = this;
  function ScratchCard(element, options, ownerDocument) {

    // apply default arguments.
    var defaultOptions = {
      'color': 'gray',
      'radius': 20
    };
    if (options) {
      for (var key in defaultOptions) {
        if (!(key in options)) {
          options[key] = defaultOptions[key];
        }
      }
    } else {
      options = defaultOptions;
    }
    ownerDocument = ownerDocument || global.document;
    
    // canvas validate.
    var canvas = document.createElement('canvas');
    if (typeof canvas.getContext != 'function')
      return console.log('Canvas not supported.');

    // apply canvas offset & size of element
    var rect = element.getBoundingClientRect();
    canvas.width = rect.width || rect.right - rect.left
    canvas.height = rect.height || rect.bottom - rect.top;
    canvas.style.top = rect.top + 'px';
    canvas.style.left = rect.left + 'px';
    canvas.style.position = 'absolute';
    canvas.style.zIndex = +element.style.zIndex + 1;

    // fill the canvas
    var context = canvas.getContext('2d');
    context.fillStyle = options.color;
    context.fillRect(0, 0, canvas.width, canvas.height);
    context.globalCompositeOperation = "destination-out";
    context.strokeStyle = "rgba(0,0,0,1)";

    // add mouse events to canvas
    // TODO: supply touch events
    // TODO: scratch from the outside
    function scratchStart(event) {
      if (event.button != 0) // not left button
        return;

      var x = event.offsetX || event.layerX;
      var y = event.offsetY || event.layerY;

      context.beginPath();
      context.arc(x, y, options.radius, 0, Math.PI * 2);
      context.fill();

      canvas.addEventListener('mousemove', scratchMove);
      canvas.addEventListener('touchmove', scratchMove);
      document.addEventListener('mouseup', scratchEnd);
      document.addEventListener('touchend', scratchEnd);
    }

    function scratchMove(event) {
      var x = event.offsetX || event.layerX;
      var y = event.offsetY || event.layerY;

      context.beginPath();
      context.arc(x, y, options.radius, 0, Math.PI * 2);
      context.fill();
    }

    function scratchEnd(event) {
      canvas.removeEventListener('mousemove', scratchMove);
      canvas.removeEventListener('touchmove', scratchMove);
      document.removeEventListener('mouseup', scratchEnd);
      document.removeEventListener('touchend', scratchEnd);

    }

    canvas.addEventListener('mousedown', scratchStart);
    canvas.addEventListener('touchstart', scratchStart);

    // disable element interaction
    ['MozUserSelect',
     'msUserSelect',
     'oUserSelect',
     'webkitUserSelect',
     'pointerEvents']
      .filter(function (cssProp) {
        return cssProp in element.style;
      }).forEach(function (cssProp) {
        element.style[cssProp] = 'none';
      });

    // append canvas to body.
    document.body.appendChild(canvas);
  }

  if (typeof module == 'object' && module.exports) {
    // Node.js module
    module.exports = ScratchCard;
  } else if (typeof define == 'function' && (define.amd || define.cmd)) {
    // AMD or CMD module
    define(ScratchCard);
  } else if (typeof jQuery == 'function' && typeof jQuery.extend == 'function') {
    // jQuery plugin
    jQuery.fn.extend({
      'ScratchCard': function (options) {
        return this.each(function (element) {
          ScratchCard(element, options);
        });
      }
    });
  } else if (typeof angular == 'object' && typeof angular.module == 'function') {
    // AngularJS module
    // TODO: modify it to a directive.
    angular.module('ScratchCard', [])
      .value('ScratchCard', ScratchCard);
  } else {
    // Apply to a global variable.
    if (global.ScratchCard) {
      (function (oldScratchCard) {
        ScratchCard.noConflict = function () {
          global.ScratchCard = oldScratchCard;
          return ScratchCard;
        };
      }) (global.ScratchCard);
    }
    global.ScratchCard = ScratchCard;
  }
}).call(this);
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
  <!--<script type="text/javascript" src="jquery-1.11.2.min.js"></script> -->
  <!-- <script type="text/javascript" src="touch.js"></script> -->
  <title>ScratchCard Demo</title>
  <style>
  div {
   display: inline-block;
   padding: 5px;
   border: 1px solid black;
  }
  p {
   margin: 0;
   /*padding: 5px;*/
   font-size: 20px;
  }

  img {
    width: 200px;
    height: 200px;
    border:10px solid #557FFF;
  }
  </style>
</head>
<body>
  
  <div><p id="scratchable"><img src="sc4.jpg"></img></p></div>
  <script src="ScratchCard.js"></script>
  <script>ScratchCard(document.querySelector('p'));</script>
  <script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-60834029-1', 'auto');
  ga('send', 'pageview');

  </script>
</body>
</html>

I do not know what is wrong with this code but i really need help on that one.

1

There are 1 best solutions below

7
On

To ensure you don't end up with unintended behavior, detect what device is being used and only add event listeners for that device. If you are using touchscreen, then do not add mouse event listeners, and vice-versa.

The rest looks technically correct, you are using touchstart to create the touchmove event listener, then on touchend you remove the touchmove listener. The touchmove would be the only event that contains the scratchMove code, so that should all be good.

I would mostly concentrate on the first paragraph here and only set up event listeners that are related to the device/environment.

In your javascript, you can add this assignment:

var isTouch = 'ontouchstart' in document.documentElement;

Then in each place you are assigning the events, do this:

   if(isTouch) {
      canvas.addEventListener('touchmove', scratchMove);
      document.addEventListener('touchend', scratchEnd);
   } else {
      canvas.addEventListener('mousemove', scratchMove);
      document.addEventListener('mouseup', scratchEnd);
   }