Hammer.js is a lightweight JavaScript library that allows you to easily add touch gestures to your web applications. It provides a consistent and cross-browser API for detecting various touch events such as taps, swipes, pinches, and rotates, abstracting away the complexities of handling different browser and device implementations. Instead of dealing with raw touch events, you can use Hammer.js’s high-level gestures, simplifying development and improving consistency across platforms.
Using Hammer.js offers several key advantages:
Hammer.js can be included in your project in a few ways:
<script src="https://hammerjs.github.io/dist/hammer.js"></script>
npm install hammerjs
Then, import it into your JavaScript code:
import Hammer from 'hammerjs';
After including Hammer.js, you can start using its API to detect and respond to gestures.
Hammer.js supports a wide range of modern browsers and devices. While it aims for broad compatibility, optimal performance and support for all features are generally best achieved using modern, up-to-date browsers. Refer to the official Hammer.js documentation and release notes for the most up-to-date compatibility information, as browser support may evolve over time. Generally, you can expect good support across major desktop browsers and mobile browsers on iOS and Android.
The first step to using Hammer.js is creating a Hammer instance. This instance is associated with a specific DOM element and will listen for gestures on that element. You create a Hammer instance using the Hammer
constructor, passing the target element as an argument. Optionally, you can also pass a configuration object to customize the behavior.
// Get the target element
const element = document.getElementById('myElement');
// Create a Hammer instance
const hammer = new Hammer(element);
// Optionally, pass a configuration object (see below for details)
//const hammer = new Hammer(element, {
// recognizers: [/* ... */]
//});
This creates a hammer
object that you can use to manage gesture recognition for the element with the ID myElement
.
Hammer.js uses recognizers to detect different gestures. A recognizer is a specific type of gesture, such as a tap, swipe, pinch, or rotate. Each recognizer has its own set of criteria for determining if a gesture has occurred. By default, Hammer.js includes several built-in recognizers, and you can also create custom recognizers for more specialized needs. Some common built-in recognizers include:
Tap
: Detects a single touch event.DoubleTap
: Detects two consecutive tap events.Swipe
: Detects a quick movement of the finger across the screen.Pinch
: Detects a pinching or spreading gesture with two fingers.Rotate
: Detects a rotation gesture with two fingers.Pan
: Detects dragging or panning gestures.Each recognizer can have options to fine-tune its behavior (e.g., specifying minimum swipe distance or velocity).
Hammer.js uses events to notify you when a gesture has occurred. You add event listeners to the Hammer instance using the on()
method. The first argument is the gesture event name (e.g., 'tap'
, 'swipe'
, 'pinch'
), and the second is a callback function that will be executed when the event occurs. The callback function receives a event
object containing information about the gesture.
.on('tap', (ev) => {
hammerconsole.log('Tap event:', ev);
; })
This code adds a listener for the tap
event. When a tap occurs on myElement
, the callback function will be executed, and the ev
object will contain details like coordinates, timestamp and more. Other events like swipeleft
, swiperight
, pinchin
, pinchout
, rotate
etc, are also available.
This example shows how to detect taps on an element:
<!DOCTYPE html>
<html>
<head>
<title>Hammer.js Tap Example</title>
<script src="https://hammerjs.github.io/dist/hammer.js"></script>
</head>
<body>
<div id="myElement">Tap me!</div>
<script>
const element = document.getElementById('myElement');
const hammer = new Hammer(element);
.on('tap', (ev) => {
hammeralert('Tapped!');
;
})</script>
</body>
</html>
This code creates a div element, and when you tap it an alert box will appear.
You can add multiple recognizers to a single Hammer instance. Hammer.js will automatically manage conflicts between recognizers to determine which gesture has occurred. You can achieve this by adding multiple on()
handlers for different events or by providing an array of recognizers in the configuration object during instance creation.
.on('tap', (ev) => {
hammerconsole.log('Tapped!');
;
}).on('swipe', (ev) => {
hammerconsole.log('Swiped:', ev.direction);
; })
This code listens for both tap
and swipe
events on the same element. Hammer.js will handle the situation where a swipe might also trigger a tap, and typically choose the more significant gesture. More fine grained control can be gained through recognizer configuration.
The tap
recognizer detects a quick touch and release on the element. It’s essentially a single touch event without significant movement.
tap
taps
: The number of taps required (default: 1). This option is typically used in conjunction with the doubletap
recognizer. Setting to a value greater than 1 will result in the tap
event not firing if a double tap is detected.intervalTime
: The maximum time between taps (in milliseconds) for a multi-tap gesture (default: 250).posThreshold
: The maximum distance (in pixels) the finger can move during the tap (default: 10).timeThreshold
: The maximum time (in milliseconds) the touch can be pressed before it’s considered a tap (default: 250).center
, timeStamp
etc..The doubletap
recognizer detects two consecutive taps within a short time and distance.
doubletap
tap
recognizer, but taps
is implicitly set to 2.tap
, but indicates a double tap occurred.The press
recognizer detects a touch that is held down for a specified duration.
press
time
: The minimum time (in milliseconds) the touch must be held down before the press
event is triggered (default: 500).The swipe
recognizer detects a quick, sliding movement of the finger across the screen.
swipe
, swipeleft
, swiperight
, swipeup
, swipedown
(directional events are also fired)direction
: Specifies the allowed swipe directions (‘horizontal’, ‘vertical’, ‘all’ - default: ‘all’).velocity
: The minimum velocity (in pixels per second) required for a swipe (default: 0.3).threshold
: The minimum distance (in pixels) the finger must move before a swipe is detected (default: 30).direction
), velocity (velocity
), and coordinate information.The pan
recognizer detects dragging or panning movements. It’s triggered continuously while the finger is moving.
pan
, panstart
, panmove
, panend
, panleft
, panright
, panup
, pandown
direction
: Specifies the allowed pan directions (‘horizontal’, ‘vertical’, ‘all’ - default: ‘all’).threshold
: Minimum distance (in pixels) to trigger a panstart
event (default: 0)deltaX
, deltaY
), velocity (velocityX
, velocityY
), and coordinate information. The delta properties show the change in position since the last event.The pinch
recognizer detects a pinching or spreading gesture using two fingers.
pinch
, pinchstart
, pinchmove
, pinchin
, pinchout
threshold
: Minimum scale change to trigger a pinchstart
event.scale
), rotation (rotation
), velocity and coordinate information. The scale
property represents the scaling factor (1.0 is no change, > 1.0 is zoom in, < 1.0 is zoom out).The rotate
recognizer detects a rotation gesture using two fingers.
rotate
, rotatestart
, rotate
, rotateend
threshold
: Minimum rotation (in degrees) to trigger a rotatestart
event (default: 0).rotation
) and velocity information.The release
recognizer is triggered when a single touch is released, it is not a gesture recognizer in the same sense as the others.
release
Hammer.js events provide a rich set of properties within the event object passed to your event handlers. These properties provide detailed information about the gesture, including:
center
: An object containing the x and y coordinates of the gesture’s center point.deltaX
/ deltaY
: The change in x and y coordinates since the last event (for continuous gestures like pan
and pinch
).distance
: The total distance of movement (often used in swipe and pan).angle
: The angle of the gesture (often used in rotate and swipe).rotation
: The rotation in degrees (for rotate and pinch).scale
: The scaling factor (for pinch).velocityX
/ velocityY
: The velocity of the gesture in pixels per second.target
: The DOM element where the gesture occurred.timeStamp
: The timestamp when the event occurred.srcEvent
: The original browser event (e.g., TouchEvent
or MouseEvent
).isFinal
: Boolean indicating if this is the final event for the gesture. (e.g., panend
, pinchend
)Many of these properties are specific to certain recognizers; consult the individual recognizer documentation for details on which properties are available.
enable
, direction
, threshold
, etc.)Each recognizer has a set of options that you can use to customize its behavior. These options are passed as a JavaScript object when you create a recognizer (or when adding them to the Hammer instance’s recognizers
array). Common options include:
enable
: (boolean) Enables or disables the recognizer. Useful for dynamically turning gestures on or off.direction
: (string) Specifies the allowed direction(s) for the gesture (‘horizontal’, ‘vertical’, ‘all’, ‘left’, ‘right’, ‘up’, ‘down’). The specific options vary per recognizer.threshold
: (number) Specifies the minimum movement (in pixels or degrees) required to trigger the recognizer.velocity
: (number) Specifies the minimum velocity (pixels/second) for swipe/pan recognizers.time
: (number) Specifies a time threshold (milliseconds) (often for press
and tap
).taps
: (number) Number of taps required (for tap
and doubletap
).intervalTime
: (number) Time interval between taps for multi-tap gestures.posThreshold
: (number) Maximum distance allowed between taps (for multi-tap gestures).For example, to customize the swipe
recognizer to only detect horizontal swipes with a minimum velocity of 0.5:
const hammer = new Hammer(element, {
recognizers: [
.Swipe, { direction: Hammer.DIRECTION_HORIZONTAL, velocity: 0.5 }]
[Hammer
]; })
Beyond the built-in options, you can further customize the behavior of recognizers by extending them or creating your own custom recognizers. This involves creating a class that inherits from Hammer.Recognizer
and overriding its methods to implement your custom logic. This is advanced usage and requires a deeper understanding of the Hammer.js architecture.
Browser often have default behaviors for touch events (e.g., scrolling). To prevent these defaults from interfering with your gesture handling, use the preventDefault()
method on the event object within your gesture handler.
.on('pan', (ev) => {
hammer.preventDefault(); // Prevent default browser scrolling behavior
ev// ... your pan handling logic ...
; })
Use this carefully, as preventing default behavior can have unintended side effects. It might prevent scrolling or other essential browser actions.
Hammer.js can handle different types of input (touch, mouse, pointer). By default, it attempts to use the most appropriate input type for the current device and browser. You can manage the input types using options during the Hammer
instance creation or configuration.
Hammer.js allows you to use multiple recognizers on the same element. It intelligently manages conflicts between recognizers based on priority and criteria to select the most appropriate gesture. Order in the recognizers
array can affect this selection.
When multiple recognizers might match the same input sequence, Hammer.js uses a priority system to determine which recognizer should be triggered. Recognizers with higher priority are checked first. You can influence priority by the order you define the recognizers in the configuration. If you create a custom recognizer, you will need to define its priority explicitly. Understanding this priority order is crucial for resolving potential conflicts when using several recognizers on the same element.
Hammer.js can be integrated into various JavaScript frameworks. The specific implementation details vary depending on the framework, but the general approach is consistent:
React: You typically use a ref
to get a reference to the DOM element and then create a Hammer instance after the component mounts. Lifecycle methods like useEffect
are helpful for managing the Hammer instance. Remember to clean up the Hammer instance when the component unmounts to prevent memory leaks.
Angular: You can use @ViewChild
to access the DOM element within your Angular component and then create the Hammer instance. Lifecycle hooks (ngOnInit
, ngOnDestroy
) manage instance creation and cleanup.
Vue: You can use a ref
to access the DOM element and create the Hammer instance within the mounted
lifecycle hook and remove the listener in the beforeUnmount
hook.
In all cases, the core Hammer.js API remains the same; the framework integration mostly manages the lifecycle and DOM element access.
Hammer.js can often be combined with other JavaScript libraries. However, ensure that there are no conflicts between event handling or DOM manipulation. For example, if you use a library that already handles touch events, you might need to carefully coordinate the event handling to avoid conflicts or unexpected behavior. Pay close attention to event priorities and how each library interacts with the underlying DOM events.
For gestures not covered by the built-in recognizers, you can create your own. This involves subclassing Hammer.Recognizer
and overriding methods like recognizeWith
, canRecognizeWith
, getTouchAction
, and the core recognition methods (onTouchStart
, onTouchMove
, onTouchEnd
). You’ll define the logic to detect your custom gesture and emit custom events. This is advanced usage and requires a solid understanding of gesture recognition and Hammer.js’s internal workings.
For optimal performance:
requestAnimationFrame
to coordinate updates with the browser’s rendering cycle for smoother animation.Common issues and their solutions:
Ensure your application remains usable for users with disabilities:
This section provides a concise overview of the Hammer.js API. For complete and up-to-date details, refer to the official Hammer.js documentation.
The Hammer
instance (created using new Hammer(element, [options])
) provides several methods for managing gesture recognition:
on(eventName, handler)
: Attaches an event listener for the specified gesture event. eventName
is a string representing the gesture (e.g., ‘tap’, ‘swipe’, ‘pan’). handler
is a callback function executed when the event occurs.
off(eventName, [handler])
: Removes an event listener. If handler
is omitted, all listeners for eventName
are removed.
destroy()
: Completely destroys the Hammer instance, removing all event listeners and freeing resources. This is essential to prevent memory leaks, especially in components that mount and unmount.
get(recognizerName)
: Returns a specific Recognizer instance associated with the Hammer instance.
set(options)
: Allows changing configuration settings dynamically after Hammer instance creation.
emit(eventName, data)
: Allows programmatically triggering a Hammer event. Useful for testing or custom event handling within the application’s logic.
stop()
: Stops the processing of ongoing gestures. Useful when you need to abruptly end recognition.
Each recognizer object (accessible through hammer.get('recognizerName')
) has properties and methods to control its behavior. Key properties include:
options
: An object containing the configuration options for the recognizer (e.g., threshold
, direction
, enable
). These are the options provided when defining the Recognizer, which can be read and modified even after instantiation of the recognizer.
state
: Reflects the current state of the recognizer (e.g., Hammer.STATE_POSSIBLE
, Hammer.STATE_STARTED
, Hammer.STATE_ENDED
). Use this to track the progress of the gesture.
recognizeWith
: (Array or Recognizer) Specifies which recognizers this one should try to combine with or prevent from triggering simultaneously (affects priority). Can be set both when creating the recognizer and afterward.
requireFailure
: (Array or Recognizer) An array of recognizers that must fail for this recognizer to trigger. Useful for managing gesture conflicts.
Methods available on a recognizer instance are limited but important, enabling dynamic changes to its behavior:
set(options)
: Modify the recognizer’s configuration options at runtime.enable()
: Enables the recognizer.disable()
: Disables the recognizer.The event object passed to the event handlers contains comprehensive information about the gesture:
type
: The type of the event (e.g., ‘tap’, ‘swipe’, ‘panstart’, ‘pinchmove’).
target
: The DOM element the gesture occurred on.
center
: An object with x
and y
coordinates representing the center of the gesture.
deltaTime
: The time elapsed since the start of the gesture (in milliseconds).
timeStamp
: Timestamp of the event.
angle
: Angle of the gesture (in degrees, typically for swipe and rotate).
distance
: Distance of movement since gesture start (for swipe and pan).
deltaX
, deltaY
: Change in X and Y coordinates since the last event (for pan and pinch).
velocityX
, velocityY
: Velocity of the gesture along X and Y axes.
scale
: Scaling factor (for pinch).
rotation
: Rotation in degrees (for rotate).
srcEvent
: The underlying browser event object.
isFinal
: Boolean indicating whether this is the last event for this gesture.
direction
: Direction of swipe (e.g., 'left'
, 'right'
, 'up'
, 'down'
).
Remember to check the documentation for the specific properties available for each type of event. The properties listed are common, but not exhaustive.
This section showcases common use cases for Hammer.js and provides conceptual guidance. Specific implementation details will depend on your application’s structure and design.
A common use case involves creating an image gallery with touch gestures for navigation. You can use swipe gestures to move between images, pinch to zoom, and potentially double-tap to zoom in/out.
Implementation: You’d create a container element holding the images. Using Hammer.js, you’d listen for swipeleft
, swiperight
, pinch
, and doubletap
events. The event handlers would update the displayed image or its scale based on the detected gesture.
Considerations: Efficiently manage image loading and caching to prevent performance issues with large galleries. Implement smooth transitions between images for a polished user experience.
A touch-enabled navigation menu can use swipe gestures to reveal or hide the menu, or tap gestures to select menu items.
Implementation: You can use a swipeleft
or swiperight
gesture to slide in/out a navigation menu from the side of the screen. Individual menu items can use tap
gestures to trigger actions.
Considerations: Consider the menu’s placement and animation to ensure a seamless and intuitive user experience. Ensure accessibility by providing alternative ways to access the menu for users who can’t use touch input.
Maps often benefit from pinch-to-zoom and rotate gestures.
Implementation: Use the pinch
and rotate
recognizers to handle scaling and rotation, respectively. The event handlers would update the map’s view based on the detected gestures. You’ll likely integrate with a mapping library (like Leaflet or Google Maps) to manage the map’s rendering.
Considerations: Implement bounds checking to prevent zooming beyond the map’s limits. Ensure smooth transitions to prevent jarring movements during zooming or rotation.
Hammer.js can facilitate drag-and-drop functionality. Use the pan
recognizer to track the element’s movement, updating its position based on the deltaX
and deltaY
properties.
Implementation: Attach the panstart
, panmove
, and panend
event listeners to the draggable element. During the panmove
event, update the element’s position. You might need additional logic to handle drop zones and constraints.
Considerations: Provide visual feedback (e.g., highlighting drop zones) to make the drag-and-drop experience intuitive. Implement appropriate constraints to prevent elements from being dragged outside their allowed areas.
Many games benefit from intuitive gesture controls. You can use various recognizers for different actions: swipes for movement, taps for actions, pinches for zooming, and more.
Implementation: Map different gestures to actions within your game. For example, swipeleft
, swiperight
, swipeup
, swipedown
could control character movement, while a tap
could trigger an attack or interaction. Pinch
could be used to zoom in/out on the game world.
Considerations: Provide clear visual or auditory feedback to communicate the results of the user’s gestures. Balance responsiveness with responsiveness to avoid input lag or frustrating gameplay.
Remember that these are high-level overviews. The specific implementation details depend on your project’s requirements, UI framework, and any other libraries you are using. Careful consideration of event handling, animation, and error handling are crucial to create a robust and user-friendly experience.