### Basic Gesture Recognition with Hammer.js Source: https://github.com/hammerjs/hammer.js/blob/master/README.md Demonstrates how to initialize Hammer.js on an HTML element and subscribe to pre-defined quick start events such as 'press'. It requires the hammer.js library to be included in the project. ```javascript // Get a reference to an element. var square = document.querySelector('.square'); // Create an instance of Hammer with the reference. var hammer = new Hammer(square); // Subscribe to a quick start event: press, tap, or doubletap. // For a full list of quick start events, read the documentation. hammer.on('press', function(e) { e.target.classList.toggle('expand'); console.log("You're pressing me!"); console.log(e); }); ``` -------------------------------- ### Install Hammer.js via NPM or Yarn Source: https://github.com/hammerjs/hammer.js/blob/master/README.md Instructions for installing the Hammer.js library using package managers like NPM or Yarn. This is the recommended approach for project integration. ```sh npm install --save hammerjs ``` ```sh yarn add hammerjs ``` -------------------------------- ### Hammer.js Gestures Simulator Setup and Execution (JavaScript) Source: https://github.com/hammerjs/hammer.js/blob/master/tests/manual/simulator-googlemaps.html This snippet sets up and runs the Hammer.js gestures simulator. It initializes a Google Maps instance, collects the target element, and then iteratively simulates predefined gestures using the Simulator.gestures API. It includes helper functions for generating random values and configuring gesture options. ```javascript Simulator.events.touch.fakeSupport(); var el, map; var container = document.getElementById('maps'); var program = [ ['pan', ['deltaX', 'deltaY']], ['pinch', ['scale']], ['tap', ['pos']], ['swipe', ['deltaX', 'deltaY']], ['pinch', ['pos', 'scale']], ['pan', ['pos']], ['rotate', ['pos', 'rotation']], ['doubleTap', ['pos']], ['pinchRotate', ['pos', 'scale', 'rotation']] ]; function randomRange(min, max) { return Math.random() * (max - min) + min; } function randomRangeInt(min, max) { return Math.round(randomRange(min, max)); } function gestureOption(name) { var max = map.getDiv().offsetWidth * .9; switch (name) { case 'deltaY': case 'deltaX': return randomRangeInt(10, max * .5); case 'pos': return [randomRangeInt(10, max), randomRangeInt(10, max)]; case 'scale': return randomRange(.2, 2); case 'rotation': return randomRange(-180, 180); } } function walkProgram(done) { var clone = [].concat(program); (function next() { if (clone.length) { var entry = clone.shift(); var options = {}; for (var i = 0; i < entry[1].length; i++) { options[entry[1][i]] = gestureOption(entry[1][i]); } Simulator.gestures[entry[0]](el, options, next); } else { done(); } }()); } function startSimulator() { walkProgram(startSimulator); } (function setupGoogleMaps() { map = new google.maps.Map(container, { zoom: 14, center: new google.maps.LatLng(51.98, 5.91) }); google.maps.event.addListenerOnce(map, 'idle', function() { el = container.childNodes[0].childNodes[0]; startSimulator(); }); })(); ``` -------------------------------- ### Initialize Hammer.js with Custom Options Source: https://github.com/hammerjs/hammer.js/wiki/Getting-Started Illustrates how to initialize Hammer.js with custom configuration options. This example disables 'drag' and 'transform' gestures by passing an options object as the second argument. ```javascript var hammertime = Hammer(element, { drag: false, transform: false }); ``` -------------------------------- ### Hammer.js Gesture Simulation and Logging Source: https://github.com/hammerjs/hammer.js/blob/master/tests/manual/simulator.html This JavaScript code initializes Hammer.js on an HTML element, configures gesture recognition, simulates a sequence of gestures with random options, and logs gesture details to the DOM. It defines helper functions for random number generation and gesture option creation. ```javascript var program = [ ['pan', ['deltaX', 'deltaY']], ['pinch', ['scale']], ['tap', ['pos']], ['swipe', ['deltaX', 'deltaY']], ['pinch', ['pos', 'scale']], ['pan', ['pos']], ['rotate', ['pos', 'rotation']], ['doubleTap', ['pos']], ['pinchRotate', ['pos', 'scale', 'rotation']] ]; function randomRange(min, max) { return Math.random() * (max - min) + min; } function randomRangeInt(min, max) { return Math.round(randomRange(min, max)); } function gestureOption(name) { var max = el.offsetWidth * .9; switch (name) { case 'deltaY': case 'deltaX': return randomRangeInt(10, max * .5); case 'pos': return [randomRangeInt(10, max), randomRangeInt(10, max)]; case 'scale': return randomRange(.2, 2); case 'rotation': return randomRange(-180, 180); } } function walkProgram(done) { var clone = [].concat(program); (function next() { if (clone.length) { var entry = clone.shift(); var options = {}; for (var i = 0; i < entry[1].length; i++) { options[entry[1][i]] = gestureOption(entry[1][i]); } setTimeout(function() { log.innerHTML = ''; Simulator.gestures[entry[0]](el, options, next); }, 1000); } else { done(); } }()); } function startSimulator() { walkProgram(startSimulator); } var el = document.querySelector("#hit"); var log = document.querySelector("#log"); var debug = document.querySelector("#debug"); var mc = new Hammer(el); mc.get('pinch').set({ enable: true, threshold: .1 }); mc.get('rotate').set({ enable: true }); mc.on("swipe pan multipan press pinch rotate tap doubletap", logGesture); function logGesture(ev) { log.textContent = ev.toDirString(); } Object.prototype.toDirString = function() { var output = []; for (var key in this) { if (this.hasOwnProperty(key)) { var value = this[key]; if (Array.isArray(value)) { value = "Array(" + value.length + "):"; } else if (value instanceof HTMLElement) { value = value + " (" + value.outerHTML.substring(0, 50) + "...)"; } output.push(key + ": " + value); } } return output.join("\n") }; startSimulator(); ``` -------------------------------- ### Hammer Manager: Custom Gesture Configuration (JavaScript) Source: https://context7.com/hammerjs/hammer.js/llms.txt Illustrates using Hammer.Manager for fine-grained control over gesture recognition. It configures custom recognizers for 'doubletap', 'singletap', 'swipe', 'pan', and 'press' with specific options. The example shows how to prevent conflicts between gestures and log detected events with their properties. ```javascript const element = document.getElementById('gesture-area'); const manager = new Hammer.Manager(element, { touchAction: 'auto', recognizers: [ [Hammer.Tap, { event: 'doubletap', taps: 2 }], [Hammer.Tap, { event: 'singletap' }], [Hammer.Swipe, { direction: Hammer.DIRECTION_ALL }], [Hammer.Pan, { direction: Hammer.DIRECTION_ALL, threshold: 10 }], [Hammer.Press, { time: 500 }] ] }); manager.get('doubletap').recognizeWith('singletap'); manager.get('singletap').requireFailure('doubletap'); manager.on('singletap', function(ev) { console.log('Single tap detected'); }); manager.on('doubletap', function(ev) { console.log('Double tap detected'); console.log('Tap count:', ev.tapCount); }); manager.on('press', function(ev) { console.log('Press and hold detected'); console.log('Duration:', ev.deltaTime, 'ms'); }); ``` -------------------------------- ### Hammer.js Nested Recognizer Setup (JavaScript) Source: https://github.com/hammerjs/hammer.js/blob/master/tests/manual/nested.html Configures nested Hammer.js Pan recognizers for a carousel UI. It creates an outer horizontal scroller and inner vertical scrollers, using `requireFailure()` to ensure the outer pan only activates when the inner pan fails. ```javascript // the horizontal pane scroller var outer = new HammerCarousel(document.querySelector(".panes.wrapper"), Hammer.DIRECTION_HORIZONTAL); // each pane should contain a vertical pane scroller Hammer.each(document.querySelectorAll(".pane .panes"), function(container) { // setup the inner scroller var inner = new HammerCarousel(container, Hammer.DIRECTION_VERTICAL); // only recognize the inner pan when the outer is failing. // they both have a threshold of some px outer.hammer.get('pan').requireFailure(inner.hammer.get('pan')); }); ``` -------------------------------- ### Hammer.js Carousel Implementation (JavaScript) Source: https://github.com/hammerjs/hammer.js/blob/master/tests/manual/nested.html Defines a HammerCarousel class to manage horizontal or vertical scrolling panes. It initializes Hammer.js, sets up Pan recognizers, and handles pan events to animate pane transitions. Dependencies include the Hammer.js library. ```javascript var reqAnimationFrame = (function() { return window[Hammer.prefixed(window, "requestAnimationFrame")] || function(callback) { setTimeout(callback, 1000 / 60); } })(); function dirProp(direction, hProp, vProp) { return (direction & Hammer.DIRECTION_HORIZONTAL) ? hProp : vProp } /** * Carousel * @param container * @param direction * @constructor */ function HammerCarousel(container, direction) { this.container = container; this.direction = direction; this.panes = Array.prototype.slice.call(this.container.children, 0); this.containerSize = this.container[dirProp(direction, 'offsetWidth', 'offsetHeight')]; this.currentIndex = 0; this.hammer = new Hammer.Manager(this.container); this.hammer.add(new Hammer.Pan({ direction: this.direction, threshold: 10 })); this.hammer.on("panstart panmove panend pancancel", Hammer.bindFn(this.onPan, this)); this.show(this.currentIndex); } HammerCarousel.prototype = { /** * show a pane * @param {Number} showIndex * @param {Number} [percent] percentage visible * @param {Boolean} [animate] */ show: function(showIndex, percent, animate){ showIndex = Math.max(0, Math.min(showIndex, this.panes.length - 1)); percent = percent || 0; var className = this.container.className; if(animate) { if(className.indexOf('animate') === -1) { this.container.className += ' animate'; } } else { if(className.indexOf('animate') !== -1) { this.container.className = className.replace('animate', '').trim(); } } var paneIndex, pos, translate; for (paneIndex = 0; paneIndex < this.panes.length; paneIndex++) { pos = (this.containerSize / 100) * (((paneIndex - showIndex) * 100) + percent); if(this.direction & Hammer.DIRECTION_HORIZONTAL) { translate = 'translate3d(' + pos + 'px, 0, 0)'; } else { translate = 'translate3d(0, ' + pos + 'px, 0)' } this.panes[paneIndex].style.transform = translate; this.panes[paneIndex].style.mozTransform = translate; this.panes[paneIndex].style.webkitTransform = translate; } this.currentIndex = showIndex; }, /** * handle pan * @param {Object} ev */ onPan : function (ev) { var delta = dirProp(this.direction, ev.deltaX, ev.deltaY); var percent = (100 / this.containerSize) * delta; var animate = false; if (ev.type == 'panend' || ev.type == 'pancancel') { if (Math.abs(percent) > 20 && ev.type == 'panend') { this.currentIndex += (percent < 0) ? 1 : -1; } percent = 0; animate = true; } this.show(this.currentIndex, percent, animate); } }; ``` -------------------------------- ### Initialize Hammer.js with Event Listener Source: https://github.com/hammerjs/hammer.js/wiki/Getting-Started Demonstrates how to initialize Hammer.js on an HTML element and attach a 'tap' event listener. It shows the basic usage without requiring the 'new' keyword and highlights method chaining. ```javascript var element = document.getElementById('test_el'); var hammertime = Hammer(element).on("tap", function(event) { alert('hello!'); }); ``` -------------------------------- ### Hammer.js Touch Action Polyfill Initialization (JavaScript) Source: https://github.com/hammerjs/hammer.js/blob/master/tests/manual/touchaction.html This snippet demonstrates how to initialize Hammer.js instances with different touch-action values. It checks for browser support of the touch-action property and uses the polyfill if necessary. It configures pan, pinch, and rotate gestures and attaches event listeners for various touch gestures. ```javascript var support = Hammer.prefixed(document.body.style, 'touchAction'); document.getElementById(support ? 'native' : 'no-native').className += ' show'; var touchActions = ['auto', 'pan-y', 'pan-x', 'pan-x pan-y', 'none']; Hammer.each(touchActions, function(touchAction) { var el = document.getElementById(touchAction.replace(" ", "-")); var mc = Hammer(el, { touchAction: touchAction }); mc.get('pan').set({ direction: Hammer.DIRECTION_ALL }); mc.get('pinch').set({ enable: true }); mc.get('rotate').set({ enable: true }); mc.on("pan swipe rotate pinch tap doubletap press", function(ev) { el.textContent = ev.type + " " + el.textContent; }); }); ``` -------------------------------- ### Hammer.js Manager Lifecycle and Cleanup Source: https://context7.com/hammerjs/hammer.js/llms.txt This section explains how to properly initialize, manage, and destroy Hammer.js instances. It covers creating a manager with specific recognizers, setting up event handlers, temporarily stopping recognition, forcing a stop, and performing cleanup by removing listeners and destroying the manager. It also provides guidance for integrating cleanup into SPA/framework lifecycles. ```javascript const element = document.querySelector('.temporary-element'); // Create manager const manager = new Hammer.Manager(element, { recognizers: [ [Hammer.Pan, { direction: Hammer.DIRECTION_ALL }], [Hammer.Tap], [Hammer.Press] ] }); // Set up event handlers manager.on('pan tap press', handleGesture); function handleGesture(ev) { console.log('Gesture:', ev.type); } // Stop recognition temporarily function pauseGestures() { manager.stop(false); // Stop current session } // Force stop immediately function forceStopGestures() { manager.stop(true); // Force stop } // Destroy and cleanup function cleanup() { // Remove all event listeners manager.off('pan tap press', handleGesture); // Destroy manager manager.destroy(); console.log('Manager destroyed'); console.log('Element reference:', manager.element); // null console.log('Handlers:', manager.handlers); // {} } // Call cleanup when element is removed element.addEventListener('remove', cleanup); // Or use in SPA/framework lifecycle // React: useEffect cleanup // Vue: onUnmounted // Angular: ngOnDestroy ``` -------------------------------- ### Hammer.js Direction Constants and Configuration Source: https://context7.com/hammerjs/hammer.js/llms.txt Demonstrates how to use built-in direction constants (e.g., DIRECTION_NONE, DIRECTION_LEFT, DIRECTION_ALL) to configure gesture recognizers like 'pan' and 'swipe'. It also shows how to check the direction of a detected gesture. This requires the Hammer.js library to be included. ```javascript const element = document.querySelector('.directional'); const hammer = new Hammer(element); // Direction constants console.log('DIRECTION_NONE:', Hammer.DIRECTION_NONE); // 1 console.log('DIRECTION_LEFT:', Hammer.DIRECTION_LEFT); // 2 console.log('DIRECTION_RIGHT:', Hammer.DIRECTION_RIGHT); // 4 console.log('DIRECTION_UP:', Hammer.DIRECTION_UP); // 8 console.log('DIRECTION_DOWN:', Hammer.DIRECTION_DOWN); // 16 console.log('DIRECTION_HORIZONTAL:', Hammer.DIRECTION_HORIZONTAL); // 6 console.log('DIRECTION_VERTICAL:', Hammer.DIRECTION_VERTICAL); // 24 console.log('DIRECTION_ALL:', Hammer.DIRECTION_ALL); // 30 // Configure pan for vertical only hammer.get('pan').set({ direction: Hammer.DIRECTION_VERTICAL }); // Configure swipe for horizontal only hammer.get('swipe').set({ direction: Hammer.DIRECTION_HORIZONTAL, threshold: 50, velocity: 0.5 }); // Handle specific directions hammer.on('pan', function(ev) { if (ev.direction === Hammer.DIRECTION_LEFT) { console.log('Panning left'); } else if (ev.direction === Hammer.DIRECTION_RIGHT) { console.log('Panning right'); } else if (ev.direction === Hammer.DIRECTION_UP) { console.log('Panning up'); } else if (ev.direction === Hammer.DIRECTION_DOWN) { console.log('Panning down'); } }); // Check if direction matches function isHorizontal(direction) { return direction & Hammer.DIRECTION_HORIZONTAL; } function isVertical(direction) { return direction & Hammer.DIRECTION_VERTICAL; } hammer.on('pan', function(ev) { if (isHorizontal(ev.direction)) { console.log('Horizontal pan detected'); } if (isVertical(ev.direction)) { console.log('Vertical pan detected'); } }); ``` -------------------------------- ### Hammer.js Initialization and Event Handling Source: https://github.com/hammerjs/hammer.js/blob/master/tests/manual/visual.html Initializes Hammer.js on an element, sets up various gesture recognizers (Pan, Swipe, Rotate, Pinch, Tap, DoubleTap), and defines event handlers for each gesture. It also includes a listener for hammer.input events to reset the element's state after a gesture is completed. ```javascript var reqAnimationFrame = (function () { return window[Hammer.prefixed(window, 'requestAnimationFrame')] || function (callback) { window.setTimeout(callback, 1000 / 60); }; })(); var log = document.querySelector("#log"); var el = document.querySelector("#hit"); var START_X = Math.round((window.innerWidth - el.offsetWidth) / 2); var START_Y = Math.round((window.innerHeight - el.offsetHeight) / 2); var ticking = false; var transform; var timer; var mc = new Hammer.Manager(el); mc.add(new Hammer.Pan({ threshold: 0, pointers: 0 })); mc.add(new Hammer.Swipe()).recognizeWith(mc.get('pan')); mc.add(new Hammer.Rotate({ threshold: 0 })).recognizeWith(mc.get('pan')); mc.add(new Hammer.Pinch({ threshold: 0 })).recognizeWith([mc.get('pan'), mc.get('rotate')]); mc.add(new Hammer.Tap({ event: 'doubletap', taps: 2 })); mc.add(new Hammer.Tap()); mc.on("panstart panmove", onPan); mc.on("rotatestart rotatemove", onRotate); mc.on("pinchstart pinchmove", onPinch); mc.on("swipe", onSwipe); mc.on("tap", onTap); mc.on("doubletap", onDoubleTap); mc.on("hammer.input", function(ev) { if(ev.isFinal) { resetElement(); } }); ``` -------------------------------- ### Dynamic Recognizer Management in Hammer.js Source: https://context7.com/hammerjs/hammer.js/llms.txt Demonstrates how to dynamically add, remove, configure, and manage gesture recognizers using Hammer.js. This allows for flexible gesture handling, including setting thresholds, directions, and enabling/disabling recognizers. Requires Hammer.js library. ```javascript const element = document.querySelector('.dynamic-element'); const manager = new Hammer.Manager(element); // Add recognizers dynamically const pan = new Hammer.Pan({ direction: Hammer.DIRECTION_ALL }); const pinch = new Hammer.Pinch(); const rotate = new Hammer.Rotate(); manager.add([pan, pinch, rotate]); // Make pinch and rotate work together pinch.recognizeWith([rotate, pan]); rotate.recognizeWith(pinch); // Get recognizer by name const panRecognizer = manager.get('pan'); // Update recognizer options panRecognizer.set({ threshold: 20, direction: Hammer.DIRECTION_HORIZONTAL }); // Disable a recognizer manager.get('pinch').set({ enable: false }); // Re-enable later setTimeout(() => { manager.get('pinch').set({ enable: true }); }, 2000); // Remove a recognizer manager.remove('rotate'); // Check recognizer state console.log('Pan enabled:', panRecognizer.options.enable); console.log('Pan threshold:', panRecognizer.options.threshold); ``` -------------------------------- ### Configure Transform Gestures (Pinch, Rotate) Source: https://github.com/hammerjs/hammer.js/wiki/Tips-&-Tricks Sets up Hammer.js to handle transform gestures like pinch and rotate by enabling `preventDefault` to give Hammer full control over touch input, disabling default browser actions for a smoother experience. ```javascript var options = { preventDefault: true }; var hammertime = new Hammer(element, options); hammertime.on("transform", function(ev){ }); ``` -------------------------------- ### Instance-Specific Hammer.js Touch Action Configuration Source: https://github.com/hammerjs/hammer.js/wiki/How-to-fix-Chrome-35--and-IE10--scrolling-(touch-action) This code shows how to configure the `touchAction` property for a specific Hammer.js instance. It involves extending the default behavior object and then passing this custom configuration during the Hammer instance creation, allowing for granular control over touch interactions on individual elements. ```javascript // clone the default behavior object // for 1.0.x this is at the stop_default_behavior object var myCustomBehavior = Hammer.utils.extend({}, Hammer.defaults.behavior); myCustomBehavior.touchAction = 'pan-y'; var mc = new Hammer(document.body, { behavior: myCustomBehavior }); ``` -------------------------------- ### Initialize Hammer.js with Multiple Gestures and Event Handling (JavaScript) Source: https://github.com/hammerjs/hammer.js/blob/master/tests/manual/multiple.html This JavaScript code initializes Hammer.js on a given HTML element, enabling multiple gestures (pan, swipe, pinch, rotate) and setting their configurations. It also attaches event listeners for a combination of gestures, updating the element's text with event details. ```javascript Object.prototype.toDirString = function() { var output = []; for(var key in this) { if(this.hasOwnProperty(key)) { var value = this[key]; if(Array.isArray(value)) { value = "Array("+ value.length +"):"+ value; } else if(value instanceof HTMLElement) { value = value +" ("+ value.outerHTML.substring(0, 50) +"...)"; } output.push(key +": "+ value); } } return output.join("\n") }; function addHammer(el) { var mc = new Hammer(el, { multiUser: true }); mc.get('pan').set({ direction: Hammer.DIRECTION_ALL }); mc.get('swipe').set({ direction: Hammer.DIRECTION_ALL }); mc.get('pinch').set({ enable: true }); mc.get('rotate').set({ enable: true }); mc.on("swipe pan press pinch rotate tap doubletap", function (ev) { ev.preventDefault(); el.innerText = ev.toDirString(); }); } addHammer(document.querySelector("#left")); addHammer(document.querySelector("#right")); ``` -------------------------------- ### Custom Gesture Recognition with Hammer.js Source: https://github.com/hammerjs/hammer.js/blob/master/README.md Illustrates how to define and recognize custom gestures, like 'tripletap', using Hammer.js. This involves creating a Hammer.Manager instance, defining a new recognizer, adding it to the manager, and subscribing to the custom event. ```javascript // Get a reference to an element. var square = document.querySelector('.square'); // Create a manager to manage the element. var manager = new Hammer.Manager(square); // Create a recognizer. var TripleTap = new Hammer.Tap({ event: 'tripletap', taps: 3 }); // Add the recognizer to the manager. manager.add(TripleTap); // Subscribe to the event. manager.on('tripletap', function(e) { e.target.classList.toggle('expand'); console.log("You're triple tapping me!"); console.log(e); }); ``` -------------------------------- ### Hammer.js Event Listener Management Source: https://context7.com/hammerjs/hammer.js/llms.txt Explains how to manage event listeners in Hammer.js using 'on', 'off', and event delegation. Covers adding single and multiple listeners, removing specific or all listeners for an event, and chaining listener calls. Requires Hammer.js library. ```javascript const element = document.querySelector('.interactive'); const hammer = new Hammer(element); // Add event listener function handleTap(ev) { console.log('Tap handler called'); console.log('Target:', ev.target.className); } hammer.on('tap', handleTap); // Add multiple event listeners hammer.on('swipeleft swiperight', function(ev) { console.log('Horizontal swipe:', ev.type); }); // Remove specific handler hammer.off('tap', handleTap); // Remove all handlers for event hammer.off('swipeleft swiperight'); // Multiple handlers for same event hammer.on('pan', handler1); hammer.on('pan', handler2); // Chainable API hammer .on('tap', handleTap) .on('press', handlePress) .on('swipe', handleSwipe); function handler1(ev) { console.log('Handler 1:', ev.type); } function handler2(ev) { console.log('Handler 2:', ev.type); // Stop after this handler hammer.off('pan', handler2); } function handlePress(ev) { console.log('Press detected'); } function handleSwipe(ev) { console.log('Swipe detected'); } ``` -------------------------------- ### Basic Hammer Instance: Detect Tap and Swipe Gestures (JavaScript) Source: https://context7.com/hammerjs/hammer.js/llms.txt Demonstrates how to create a basic Hammer instance on a DOM element to detect 'tap' and 'swipeleft'/'swiperight' gestures. It logs gesture details like position, target, direction, and velocity to the console. This is useful for simple gesture interactions. ```javascript const element = document.querySelector('.interactive-area'); const hammer = new Hammer(element); hammer.on('tap', function(ev) { console.log('Tapped!'); console.log('Position:', ev.center.x, ev.center.y); console.log('Target:', ev.target); }); hammer.on('swipeleft swiperight', function(ev) { console.log('Swiped:', ev.type); console.log('Direction:', ev.direction); console.log('Velocity:', ev.velocityX); }); ``` -------------------------------- ### Create and Use Custom Gesture Recognizer (Shake) in Hammer.js Source: https://context7.com/hammerjs/hammer.js/llms.txt This code demonstrates how to create a custom gesture recognizer for a 'shake' action in Hammer.js. It defines a `ShakeRecognizer` that inherits from `Hammer.Recognizer` and implements a `process` method to detect rapid movements within a time threshold. The custom recognizer is then added to a Hammer manager and can be listened to like any built-in gesture. ```javascript // Define custom shake gesture recognizer function ShakeRecognizer() { Hammer.Recognizer.apply(this, arguments); this.shakeThreshold = 15; this.shakeTime = 500; } // Inherit from base Recognizer Hammer.inherit(ShakeRecognizer, Hammer.Recognizer, { defaults: { event: 'shake', threshold: 15, time: 500 }, getTouchAction: function() { return [Hammer.TOUCH_ACTION_AUTO]; }, process: function(input) { const options = this.options; const validTime = input.deltaTime < options.time; const validMovement = Math.abs(input.velocityX) > options.threshold || Math.abs(input.velocityY) > options.threshold; if (validTime && validMovement) { this.state = Hammer.STATE_RECOGNIZED; return Hammer.STATE_RECOGNIZED; } return Hammer.STATE_FAILED; } }); // Use custom recognizer const element = document.querySelector('.shake-target'); const manager = new Hammer.Manager(element); manager.add(new ShakeRecognizer()); manager.on('shake', function(ev) { console.log('Shake detected!'); console.log('Velocity:', ev.velocityX, ev.velocityY); }); ``` -------------------------------- ### Enable Fake Multitouch Gestures (JavaScript) Source: https://github.com/hammerjs/hammer.js/wiki/Plugins This plugin enables multitouch gestures on desktop browsers. It should be loaded after the main Hammer.js script and initialized by calling `Hammer.plugins.fakeMultitouch();`. No specific inputs or outputs are defined, but it modifies Hammer.js behavior. ```javascript Hammer.plugins.fakeMultitouch(); ``` -------------------------------- ### Hammer.js - Initialize and Configure Pinch Gesture in JavaScript Source: https://github.com/hammerjs/hammer.js/blob/master/tests/manual/input.html This code initializes Hammer.js on an HTML element identified by '#hit'. It then enables the 'pinch' gesture and sets up an event listener for 'hammer.input' events. The listener updates a debug element with details about the touch input, such as event type, number of pointers, and movement deltas. ```javascript var el = document.querySelector("#hit"); var log = document.querySelector("#log"); var debug = document.querySelector("#debug"); var mc = new Hammer(el); mc.get('pinch').set({ enable: true }); mc.on("hammer.input", function(ev) { debug.innerHTML = [ev.srcEvent.type, ev.pointers.length, ev.isFinal, ev.deltaX, ev.deltaY].join("
"); }); ``` -------------------------------- ### Accessing Gesture Event Data with Hammer.js Source: https://context7.com/hammerjs/hammer.js/llms.txt Learn how to access detailed data from various gesture events like pan, tap, and swipe. This includes timing, position, velocity, multi-touch information, and preventing default browser behavior. Requires Hammer.js library. ```javascript const element = document.querySelector('.gesture-target'); const hammer = new Hammer(element); hammer.get('pan').set({ direction: Hammer.DIRECTION_ALL }); hammer.on('pan tap swipe press', function(ev) { // Event type console.log('Gesture type:', ev.type); // Timing information console.log('Timestamp:', ev.timeStamp); console.log('Delta time:', ev.deltaTime); // Position data console.log('Center point:', ev.center); // { x, y } console.log('Delta movement:', ev.deltaX, ev.deltaY); // Velocity and direction console.log('Velocity:', ev.velocityX, ev.velocityY); console.log('Overall velocity:', ev.overallVelocity); console.log('Direction:', ev.direction); console.log('Offset direction:', ev.offsetDirection); // Distance and angle console.log('Distance:', ev.distance); console.log('Angle:', ev.angle); // Multi-touch data console.log('Scale:', ev.scale); console.log('Rotation:', ev.rotation); console.log('Pointers:', ev.pointers.length); console.log('Max pointers:', ev.maxPointers); // Pointer information console.log('Pointer type:', ev.pointerType); // 'mouse', 'touch', 'pen' console.log('Target element:', ev.target); // Original event console.log('Source event:', ev.srcEvent); // Event flags console.log('Is first:', ev.isFirst); console.log('Is final:', ev.isFinal); // Prevent default browser behavior ev.preventDefault(); }); ``` -------------------------------- ### Hammer.js Gesture Recognition and Logging Source: https://github.com/hammerjs/hammer.js/blob/master/tests/manual/log.html This JavaScript code demonstrates how to use Hammer.js to detect various touch gestures on an HTML element and log the gesture details to the console and the DOM. It initializes Hammer.js on a specific element, enables pinch and rotate gestures, and sets up event listeners for multiple gesture types. ```javascript Object.prototype.toDirString = function() { var output = []; for(var key in this) { if(this.hasOwnProperty(key)) { var value = this[key]; if(Array.isArray(value)) { value = "Array(" + value.length +"):"+ value; } else if(value instanceof HTMLElement) { value = value + " ("+ value.outerHTML.substring(0, 50) +"...)"; } output.push(key + ": "+ value); } } return output.join("\n") }; var el = document.querySelector("#hit"); var log = document.querySelector("#log"); var debug = document.querySelector("#debug"); var mc = new Hammer(el); mc.get('pinch').set({ enable: true }); mc.get('rotate').set({ enable: true }); mc.on("swipe pan panstart panmove panend pancancel multipan press pressup pinch rotate tap doubletap", logGesture); function DEBUG(str) { debug.textContent = str; } function logGesture(ev) { console.log(ev.timeStamp, ev.type, ev); log.textContent = ev.toDirString(); } ``` -------------------------------- ### Hammer.js Recognizer Dependencies and Simultaneous Recognition Source: https://context7.com/hammerjs/hammer.js/llms.txt Illustrates how to manage relationships between Hammer.js recognizers, such as setting dependencies (recognizeWith, requireFailure) to control when gestures are recognized. This allows for complex gesture interactions, like recognizing swipe and pan simultaneously or ensuring a double-tap doesn't trigger a single tap. Requires Hammer.js. ```javascript const element = document.querySelector('.complex-gestures'); const manager = new Hammer.Manager(element); // Create recognizers const pan = new Hammer.Pan({ direction: Hammer.DIRECTION_ALL }); const swipe = new Hammer.Swipe({ direction: Hammer.DIRECTION_ALL }); const tap = new Hammer.Tap(); const doubleTap = new Hammer.Tap({ event: 'doubletap', taps: 2 }); const press = new Hammer.Press(); manager.add([pan, swipe, tap, doubleTap, press]); // Recognize swipe and pan simultaneously pan.recognizeWith(swipe); // Tap requires doubletap to fail first (prevent false single taps) tap.requireFailure(doubleTap); // Allow press to work with pan press.recognizeWith(pan); // Drop recognition relationship // pan.dropRecognizeWith(swipe); // tap.dropRequireFailure(doubleTap); manager.on('pan swipe', function(ev) { console.log('Gesture:', ev.type); console.log('Can recognize together'); }); manager.on('tap', function(ev) { console.log('Single tap (doubletap failed)'); }); manager.on('doubletap', function(ev) { console.log('Double tap detected'); }); ``` -------------------------------- ### Detect Input Types and Pointer Events with Hammer.js Source: https://context7.com/hammerjs/hammer.js/llms.txt This snippet demonstrates how to detect different input types (mouse, touch, pen) and access detailed pointer event information using Hammer.js. It logs the pointer type, specific event details like button or pressure, and raw pointer coordinates. Dependencies include the Hammer.js library. ```javascript const element = document.querySelector('.multi-input'); const hammer = new Hammer(element); // Input type constants console.log('INPUT_TYPE_MOUSE:', 'mouse'); console.log('INPUT_TYPE_TOUCH:', 'touch'); console.log('INPUT_TYPE_PEN:', 'pen'); hammer.on('tap press pan', function(ev) { // Detect input type console.log('Pointer type:', ev.pointerType); if (ev.pointerType === 'mouse') { console.log('Mouse input detected'); console.log('Button:', ev.srcEvent.button); } else if (ev.pointerType === 'touch') { console.log('Touch input detected'); console.log('Number of touches:', ev.pointers.length); } else if (ev.pointerType === 'pen') { console.log('Stylus/pen input detected'); console.log('Pressure:', ev.srcEvent.pressure); } // Access raw pointer data ev.pointers.forEach((pointer, index) => { console.log(`Pointer ${index}:`, { x: pointer.clientX, y: pointer.clientY, identifier: pointer.identifier }); }); }); // Custom input class (advanced) const customManager = new Hammer.Manager(element, { inputClass: Hammer.TouchInput // Force touch input handling }); ``` -------------------------------- ### Pan Gesture Recognition: Detect Dragging and Direction (JavaScript) Source: https://context7.com/hammerjs/hammer.js/llms.txt Shows how to enable and handle pan gestures for dragging elements. It configures pan detection, updates element position during 'panmove', and logs details like delta movement, direction, and velocity. It also demonstrates handling 'panstart', 'panend', and directional pan events ('panleft', 'panright', etc.). ```javascript const element = document.querySelector('.draggable'); const hammer = new Hammer(element); hammer.get('pan').set({ direction: Hammer.DIRECTION_ALL }); let startX = 0; let startY = 0; hammer.on('panstart', function(ev) { startX = parseFloat(element.style.left) || 0; startY = parseFloat(element.style.top) || 0; element.classList.add('dragging'); console.log('Pan started at:', ev.center); }); hammer.on('panmove', function(ev) { element.style.left = (startX + ev.deltaX) + 'px'; element.style.top = (startY + ev.deltaY) + 'px'; console.log('Pan delta:', ev.deltaX, ev.deltaY); console.log('Pan direction:', ev.direction); console.log('Pan velocity:', ev.velocityX, ev.velocityY); }); hammer.on('panend', function(ev) { element.classList.remove('dragging'); console.log('Pan ended'); console.log('Final position:', element.style.left, element.style.top); if (Math.abs(ev.velocityX) > 0.5) { console.log('Fast swipe detected, velocity:', ev.velocityX); } }); hammer.on('panleft panright panup pandown', function(ev) { console.log('Directional pan:', ev.type); }); ``` -------------------------------- ### Pinch and Rotate Gestures with Hammer.js Source: https://context7.com/hammerjs/hammer.js/llms.txt Handles multi-touch pinch (zoom) and rotate gestures on an element. It allows for dynamic scaling and rotation of images or other elements. Requires Hammer.js. ```javascript const image = document.querySelector('.zoomable-image'); const hammer = new Hammer(image); // Enable pinch and rotate hammer.get('pinch').set({ enable: true }); hammer.get('rotate').set({ enable: true }); let currentScale = 1; let currentRotation = 0; hammer.on('pinchstart rotatestart', function(ev) { console.log('Multi-touch gesture started'); image.classList.add('transforming'); }); hammer.on('pinchmove', function(ev) { currentScale = Math.max(0.5, Math.min(currentScale * ev.scale, 3)); updateTransform(); console.log('Pinch scale:', ev.scale); console.log('Current scale:', currentScale); console.log('Pinch direction:', ev.scale > 1 ? 'out' : 'in'); }); hammer.on('rotatemove', function(ev) { currentRotation += ev.rotation; updateTransform(); console.log('Rotation angle:', ev.rotation); console.log('Total rotation:', currentRotation); }); hammer.on('pinchend rotateend', function(ev) { image.classList.remove('transforming'); console.log('Final scale:', currentScale); console.log('Final rotation:', currentRotation); }); // Handle pinch in/out specifically hammer.on('pinchin pinchout', function(ev) { console.log('Pinch type:', ev.type); }); function updateTransform() { image.style.transform = `scale(${currentScale}) rotate(${currentRotation}deg)`; } ``` -------------------------------- ### Tap and Double Tap Recognition with Hammer.js Source: https://context7.com/hammerjs/hammer.js/llms.txt Recognizes single, double, and triple tap gestures on an element. It includes configuration for tap interval and position threshold to ensure accurate detection. Requires Hammer.js. ```javascript const element = document.querySelector('.tappable'); const manager = new Hammer.Manager(element); // Add tap recognizers const singleTap = new Hammer.Tap({ event: 'singletap' }); const doubleTap = new Hammer.Tap({ event: 'doubletap', taps: 2, interval: 300, // max time between taps posThreshold: 10 // max distance between taps }); const tripleTap = new Hammer.Tap({ event: 'tripletap', taps: 3 }); manager.add([tripleTap, doubleTap, singleTap]); // Set up recognition dependencies doubleTap.recognizeWith(singleTap); singleTap.requireFailure([doubleTap, tripleTap]); tripleTap.recognizeWith(doubleTap); manager.on('singletap', function(ev) { console.log('Single tap'); console.log('Position:', ev.center.x, ev.center.y); console.log('Tap count:', ev.tapCount); }); manager.on('doubletap', function(ev) { console.log('Double tap detected'); console.log('Time between taps:', ev.deltaTime, 'ms'); // Zoom in or select action }); manager.on('tripletap', function(ev) { console.log('Triple tap detected'); // Special action }); ``` -------------------------------- ### Hammer.js Touch Action and Browser Behavior Control Source: https://context7.com/hammerjs/hammer.js/llms.txt Explains how to configure the `touchAction` option in Hammer.js to control default browser behaviors like scrolling and zooming. It shows different settings such as 'auto', 'none', 'pan-y', 'pan-x', and 'manipulation' to customize touch interactions. This is useful for preventing conflicts between Hammer gestures and native browser gestures. Requires Hammer.js. ```javascript const element = document.querySelector('.scroll-container'); // Let Hammer compute optimal touch-action const manager = new Hammer.Manager(element, { touchAction: 'auto' }); // Disable all touch actions (no scrolling, no zooming) const strictManager = new Hammer.Manager(element, { touchAction: 'none' }); // Allow vertical scrolling only const verticalScrollManager = new Hammer.Manager(element, { touchAction: 'pan-y' }); // Allow horizontal scrolling only const horizontalScrollManager = new Hammer.Manager(element, { touchAction: 'pan-x' }); // Allow pinch-zoom const zoomManager = new Hammer.Manager(element, { touchAction: 'manipulation' }); // Configure pan with appropriate touch action const panElement = document.querySelector('.pan-only'); const panManager = new Hammer.Manager(panElement, { touchAction: 'pan-y' // Allow vertical scroll, prevent horizontal }); panManager.add(new Hammer.Pan({ direction: Hammer.DIRECTION_HORIZONTAL })); panManager.on('pan', function(ev) { console.log('Horizontal pan without interfering with vertical scroll'); console.log('Delta X:', ev.deltaX); }); ``` -------------------------------- ### Configure Vertical Swipe and Drag Gestures Source: https://github.com/hammerjs/hammer.js/wiki/Tips-&-Tricks Configures Hammer.js for vertical swipe and drag gestures by enabling `preventDefault`. This is recommended because vertical movements can conflict with default browser scrolling, and this setting gives Hammer control. ```javascript var options = { preventDefault: true }; var hammertime = new Hammer(element, options); hammertime.on("dragup dragdown swipeup swipedown", function(ev){ }); ``` -------------------------------- ### Show Touches for Debugging (JavaScript) Source: https://github.com/hammerjs/hammer.js/wiki/Plugins This plugin visually displays touch points, useful in conjunction with the `fakemultitouch` plugin for desktop testing. It relies on the CSS `pointer-events` property, meaning it will not function in older Internet Explorer versions. It's typically enabled within a script block. ```javascript // // ``` -------------------------------- ### Extend Object Prototype with toDirString in JavaScript Source: https://github.com/hammerjs/hammer.js/blob/master/tests/manual/input.html This snippet extends the Object prototype to add a `toDirString` method. This method iterates over an object's own properties and formats their values for display, handling arrays and HTMLElements specifically. It's useful for debugging and logging object structures. ```javascript Object.prototype.toDirString = function() { var output = []; for(var key in this) { if(this.hasOwnProperty(key)) { var value = this[key]; if(Array.isArray(value)) { value = "Array("+ value.length +"):"+ value; } else if(value instanceof HTMLElement) { value = value +" ("+ value.outerHTML.substring(0, 50) +"...)"; } output.push(key +": "+ value); } } return output.join("\n") }; ``` -------------------------------- ### Configure Horizontal Swipe and Drag Gestures Source: https://github.com/hammerjs/hammer.js/wiki/Tips-&-Tricks Configures Hammer.js to prioritize horizontal swipe and drag gestures by locking the drag to an axis and blocking horizontal movement, improving the user experience for these specific actions. ```javascript var options = { dragLockToAxis: true, dragBlockHorizontal: true }; var hammertime = new Hammer(element, options); hammertime.on("dragleft dragright swipeleft swiperight", function(ev){ }); ``` -------------------------------- ### Disable Viewport Scaling Source: https://github.com/hammerjs/hammer.js/wiki/Tips-&-Tricks This meta tag should be added to your page to prevent double-tap zooming and enable multitouch gestures. It also helps remove the 300ms delay on Chrome Mobile. ```HTML ``` -------------------------------- ### Element Transformation Logic Source: https://github.com/hammerjs/hammer.js/blob/master/tests/manual/visual.html Contains functions to manage and update the CSS transformations (translate, scale, rotate) of an HTML element. It uses requestAnimationFrame for smooth updates and handles resetting the element's style and transform properties. ```javascript function resetElement() { el.className = 'animate'; transform = { translate: { x: START_X, y: START_Y }, scale: 1, angle: 0, rx: 0, ry: 0, rz: 0 }; requestElementUpdate(); if (log.textContent.length > 2000) { log.textContent = log.textContent.substring(0, 2000) + "..."; } } function updateElementTransform() { var value = [ 'translate3d(' + transform.translate.x + 'px, ' + transform.translate.y + 'px, 0)', 'scale(' + transform.scale + ', ' + transform.scale + ')', 'rotate3d('+ transform.rx +','+ transform.ry +','+ transform.rz +','+ transform.angle + 'deg)' ]; value = value.join(" "); el.textContent = value; el.style.webkitTransform = value; el.style.mozTransform = value; el.style.transform = value; ticking = false; } function requestElementUpdate() { if(!ticking) { reqAnimationFrame(updateElementTransform); ticking = true; } } function logEvent(str) { //log.insertBefore(document.createTextNode(str +"\n"), log.firstChild); } ``` -------------------------------- ### Hammer.js Gesture Event Handlers Source: https://github.com/hammerjs/hammer.js/blob/master/tests/manual/visual.html Provides specific callback functions for different Hammer.js gestures. These functions update the 'transform' object based on gesture data (delta, scale, rotation, direction) and trigger element updates. ```javascript function onPan(ev) { el.className = ''; transform.translate = { x: START_X + ev.deltaX, y: START_Y + ev.deltaY }; requestElementUpdate(); logEvent(ev.type); } var initScale = 1; function onPinch(ev) { if(ev.type == 'pinchstart') { initScale = transform.scale || 1; } el.className = ''; transform.scale = initScale * ev.scale; requestElementUpdate(); logEvent(ev.type); } var initAngle = 0; function onRotate(ev) { if(ev.type == 'rotatestart') { initAngle = transform.angle || 0; } el.className = ''; transform.rz = 1; transform.angle = initAngle + ev.rotation; requestElementUpdate(); logEvent(ev.type); } function onSwipe(ev) { var angle = 50; transform.ry = (ev.direction & Hammer.DIRECTION_HORIZONTAL) ? 1 : 0; transform.rx = (ev.direction & Hammer.DIRECTION_VERTICAL) ? 1 : 0; transform.angle = (ev.direction & (Hammer.DIRECTION_RIGHT | Hammer.DIRECTION_UP)) ? angle : -angle; clearTimeout(timer); timer = setTimeout(function () { resetElement(); }, 300); requestElementUpdate(); logEvent(ev.type); } function onTap(ev) { transform.rx = 1; transform.angle = 25; clearTimeout(timer); timer = setTimeout(function () { resetElement(); }, 200); requestElementUpdate(); logEvent(ev.type); } function onDoubleTap(ev) { transform.rx = 1; transform.angle = 80; clearTimeout(timer); timer = setTimeout(function () { resetElement(); }, 500); requestElementUpdate(); logEvent(ev.type); } resetElement(); ```