Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create custom animation from longpress jQuery function

Updated (with additions from answer)

(function($) {
    $.fn.longpress = function(longCallback, duration) {

    // set some defaults
    let defaults = {
        click:      function(el, e) {},
        start:      function(el, e) { el.css("color", "#000"); },
        complete:   function(el, e) { el.css("color", "#FFF"); },
        cancel:     function(el, e) { el.css("color", "#F00"); },
        duration:   1000
    };

    // extend the options
    let options = $.extend({}, defaults);

    return this.each(function() {
        var $this = $(this);

        // to keep track of how long something was pressed
        var mouse_down_time;
        var timeout;
        $this.data("clicked", "false");

        // mousedown or touchstart callback
        function mousedown_callback(e) {

            // start callback
            options.start($this, e);

            $this.data("clicked", "true");
            mouse_down_time = new Date().getTime();
            var context = $(this);

            // set a timeout to call the longpress callback when time elapses
            timeout = setTimeout(function() {
                if (typeof longCallback === "function") {
                    longCallback.call(context, e);
                    options.complete($this, e);
                    $this.data("clicked", "false");
                } else {
                    $.error('Callback required for long press. You provided: ' + typeof longCallback);
                }
            }, options.duration);

        }

        // mouseup or touchend callback
        function mouseup_callback(e) {
            var press_time = new Date().getTime() - mouse_down_time;

            if (press_time < options.duration) {
                // cancel the timeout
                clearTimeout(timeout);
                $this.data("clicked", "false");

                // call the click if provided
                options.click($this, e);
            }
        }

        // cancel long press event if the finger or mouse was moved
        function move_callback(e) {
            let isClicked = $this.data("clicked");
            if (isClicked == "false")
                return;

            // call the cancel callback
            options.cancel($this, e);
            clearTimeout(timeout);
            $this.data("clicked", "false");
        }


      // Browser Support
      $this.on('mousedown', mousedown_callback);
      $this.on('mouseup', mouseup_callback);
      $this.on('mousemove', move_callback);

      // Mobile Support
      $this.on('touchstart', mousedown_callback);
      $this.on('touchend', mouseup_callback);
      $this.on('touchmove', move_callback);
    });
  };
}(jQuery));

I have a jQuery plugin that I found a while ago (cant remember the source) which allowed me to have long press features on a website:

(function(b) {
    b.fn.longpress = function(e, c, d) {
        "undefined" === typeof d && (d = 1000);
        return this.each(function() {
            function g(a) {
                h = (new Date).getTime();
                var c = b(this);
                f = setTimeout(function() {
                    "function" === typeof e ? e.call(c, a) : b.error("Callback required for long press. You provided: " + typeof e)
                }, d)
            }

            function k(a) {
                (new Date).getTime() - h < d && (clearTimeout(f), "function" === typeof c ? c.call(b(this), a) : "undefined" !== typeof c && b.error("Optional callback for short press should be a function."))
            }

            function l(a) {
                clearTimeout(f)
            }
            var a = b(this),
                h, f;
            a.on("mousedown", g);
            a.on("mouseup", k);
            a.on("mousemove", l);
            a.on("touchstart", g);
            a.on("touchend", k);
            a.on("touchmove", l)
        })
    }
})(jQuery);

It works great, but I was wondering if there was a way to have say the background go from #fff to #000 or make any other custom animation based on the duration of the long press.

I was toying around, but couldn't figure it out. I was trying to add a class for every second the long press was held, then have a CSS rule for each. I then tried using steps in CSS to make it time too, but couldn't get that to work as the classes would only add when the long press was successful not loading.

like image 567
markb Avatar asked Nov 09 '19 03:11

markb


2 Answers

The original plugin can be found here: https://github.com/vaidik/jquery-longpress.

I have modified to accept an object of options (explained in comments). Here is an example:

(function($) {
  $.fn.longpress = function(opts) {
    let defaults = {
      click: function(el, e) {},
      start: function(el, e) {},
      complete: function(el, e) {},
      duration: 500
    };

    let options = $.extend({}, defaults, opts);

    return this.each(function() {
      var $this = $(this);

      // to keep track of how long something was pressed
      var mouse_down_time;
      var timeout;
      $this.data("clicked", "false");

      // mousedown or touchstart callback
      function mousedown_callback(e) {

        // start callback
        options.start($this, e);

        $this.data("clicked", "true");
        mouse_down_time = new Date().getTime();
        var context = $(this);

        // set a timeout to call the longpress callback when time elapses
        timeout = setTimeout(function() {
          options.complete($this, e);
          $this.data("clicked", "false");
        }, options.duration);
      }

      // mouseup or touchend callback
      function mouseup_callback(e) {
        var press_time = new Date().getTime() - mouse_down_time;
        if (press_time < options.duration) {
          // cancel the timeout
          clearTimeout(timeout);
          $this.data("clicked", "false");

          // call the click if provided
          options.click($this, e);
        }
      }

      // cancel long press event if the finger or mouse was moved
      function move_callback(e) {
        let isClicked = $this.data("clicked");
        if (isClicked == "false")
          return;

        // call the cancel callback
        options.cancel($this, e);
        clearTimeout(timeout);
        $this.data("clicked", "false");
      }


      // Browser Support
      $this.on('mousedown', mousedown_callback);
      $this.on('mouseup', mouseup_callback);
      $this.on('mousemove', move_callback);

      // Mobile Support
      $this.on('touchstart', mousedown_callback);
      $this.on('touchend', mouseup_callback);
      $this.on('touchmove', move_callback);
    });
  };
}(jQuery));

let options = {
  // Callback after a "normal" click has completed
  click: function(el, event) {
    el.removeClass("rotate");
  },
  // callback after longpress completed
  complete: function(el, event) {
    el.removeClass("rotate");
  },
  // callback before click starts (for both normal and longpress clicks)
  start: function(el, event) {
    el.addClass("rotate");
  },
  // Callback when click is cancelled (user moves mouse)
  cancel: function(el, event) {
    el.removeClass("rotate");
  },
  // Longpress duration
  duration: 5000
};
$('#button').longpress(options);
div {
  border: 1px solid;
  width: 200px;
  height: 200px;
  left: 50px;
  top: 50px;
  position: relative;
}

.rotate {
  animation: 1s rotate infinite linear;
}

@keyframes rotate {
  100% {
    transform: rotate(1turn);
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='button'>

</div>
like image 148
Kalimah Avatar answered Oct 05 '22 22:10

Kalimah


Since you define the plugin, you can add some behaviors. One way to animate would be to use transitions based on classes you would add at different steps. And for the duration you can define it in the plugin so it has the same length as the longpress delay. Like this for example:

(function(b) {
  b.fn.longpress = function(e, c, d) {
    "undefined" === typeof d && (d = 1000);
    return this.each(function() {
      function g(a) {
        h = (new Date).getTime();
        var c = b(this);
        // here you define transition duration using user defined or default long press delay
        c.css("transition-duration", d + 'ms');
        // the class while element is being pressed
        c.addClass("pressing");
        f = setTimeout(function() {
          // when delay is done you remove pressing, add another class to signify the element has been long pressed
          c.removeClass("pressing").addClass("pressed");

          "function" === typeof e ? e.call(c, a) : b.error("Callback required for long press. You provided: " + typeof e)
        }, d)
      }

      function k(a) {
        // this is the cancel callback, so you remove pressing
        $(this).removeClass("pressing");
        (new Date).getTime() - h < d && (clearTimeout(f), "function" === typeof c ? c.call(b(this), a) : "undefined" !== typeof c && b.error("Optional callback for short press should be a function."))
      }

      function l(a) {
        clearTimeout(f)
      }
      var a = b(this),
        h, f;
      a.on("mousedown", g);
      a.on("mouseup", k);
      a.on("mousemove", l);
      a.on("touchstart", g);
      a.on("touchend", k);
      a.on("touchmove", l)
    })
  }
})(jQuery);


$('#a').longpress(function(e) {
  this.text('pressed')
}, function() {}, 1500)
div {
  background-color: #fff;
  transition: background-color;
  transition-timing-function: linear;
  cursor: pointer;
}

.pressing {
  background-color: #000;
}

.pressed {
  background-color: #FF0;
  transition: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id=a>
  long press me
</div>
like image 23
Julien Grégoire Avatar answered Oct 06 '22 00:10

Julien Grégoire