added in v3.10.0
Observer
Quick Start
CDN Link
gsap.registerPlugin(Observer)
Minimal usage
Observer.create({
target: window, // can be any element (selector text is fine)
type: "wheel,touch", // comma-delimited list of what to listen for
onUp: () => previous(),
onDown: () => next(),
});
Super-flexible, unified way to sense meaningful events across all (touch/mouse/pointer) devices without wrestling with all the implementation details. Perhaps you want to respond to "scroll-like" user behavior which could be a mouse wheel spin, finger swipe on a touch device, a scrollbar drag, or a pointer press & drag...and of course you need directional data and velocity. No problem!
Tell Observer which event types to watch (wheel, touch, pointer, and/or scroll) and it will collect delta values over the course of each requestAnimationFrame tick (debounced for performance by default) and automatically determine the biggest delta and then trigger the appropriate callback(s) like onUp
, onDown
, onDrag
, etc. (see the full list below).
Look how easy it is to trigger next()/previous() functions based on when the user swipes up/down or uses their mouse wheel:
Observer.create({
target: window, // can be any element (selector text is fine)
type: "wheel,touch", // comma-delimited list of what to listen for ("wheel,touch,scroll,pointer")
onUp: () => previous(),
onDown: () => next(),
});
Demo
Notice there's no actual scrolling in the demo below but you can use your mouse wheel (or swipe on touch devices) to initiate movement so it "feels" like a scroll:
loading...
- Rich callback system including onDown, onUp, onLeft, onRight, onDrag, onDragStart, onDragEnd, onHover, onHoverEnd, onToggleY, onToggleX, onChangeX, onChangeY, onChange, onClick, onPress, onRelease, onMove, onWheel, and onStop
- Debounced by default for maximum performance (you can set
debounce: false
if you prefer) - Cross-browser compatible - automatically senses if TouchEvents, PointerEvents, or MouseEvents should be used.
- Automatically prioritizes the event with the largest delta (like if a wheel and scroll and touch event all occur during the same debounced period)
read more...
- Ignore certain elements, like
ignore: ".deadzone"
- Get velocity (on x and y axis separately) as well as the clientX and clientY coordinates (for touch/pointer events)
- Set a minimum threshold for dragging. For example, dragMinimum: 5 would only fire the onDragStart/onDrag/onDragEnd callbacks if the user moved 5 pixels or more.
- Set a tolerance so that the movement-related callbacks only fire when a minimum delta is reached, so
tolerance: 50
would wait until there has been a change of at least 50 pixels, and then once that's reached it starts over. - Set a wheelSpeed multiplier if you'd like to tweak the wheel-related deltas (speed them up or slow them down).
- Integrated with GSAP and ScrollTrigger
- Roughly 3.5kb gzipped
Configuration Properties
The configuration object that is passed to Observer.create()
can have any of the following optional properties:
ease
Number - The ease to use for the looping preview animation.duration
Number - The duration of the looping preview animation (each iteration)path
String | Element | Array The motion path along which to animate the target(s). This can be a direct reference to a
or selector text or path data like "M9,100c0,0,18-41,49-65" or an Array of points through which the path should be plotted. pathColor
String - The color of the path stroke (only applies if nopath
is defined and MotionPathHelper must create one).pathWidth
Number - The stroke-width of the path (only applies if nopath
is defined and MotionPathHelper must create one).pathOpacity
Number - The opacity of the path stroke (only applies if nopath
is defined and MotionPathHelper must create one).Property
Descriptionaxis
string - whenlockAxis: true
is set, the first drag movement (with type: "pointer" and/or "touch") after each press will set theaxis
property to "x" or "y", depending on which direction the user moved. You can use theonLockAxis()
callback to know when it gets set.capture
Boolean - iftrue
, it will make the touch/pointer-related listeners use the capture phase. Like doing addEventListener("[type]", func, {capture: true});debounce
Boolean - by default, Observer will debounce events so that deltas are additive over the course of each requestAnimationFrame() tick in order to maximize performance, but you can disable that withdebounce: false
in which case it will check immediately on every event. The debounce affects all callbacks exceptonPress
,onRelease
,onHover
,onHoverEnd
,onClick
,onDragStart
, andonDragEnd
because those aren't delta-related.dragMinimum
Number - the minimum distance (in pixels) necessary to be considered "dragging". This can help prevent tiny motions especially on touch devices from indicating intent. For example, just pressing down with a finger on a phone may register slight movement of a few pixels even though the user thinks their finger was stationary. dragMinimum only applies to the initial movement after pressing down, but continued dragging thereafter would only be subject to "tolerance" throttling.id
ignore
Element | String | Array - elements that you'd like the observer to IGNORE, so that when a scroll/touch/pointer/mouse event is triggered by one of these elements, it gets ignored completely. It checks theevent.target
to discern if the event should be ignored. You can defineignore
as an Element reference, selector text like".ignore-me"
, or an Array of elements (it can be as many as you'd like).lockAxis
Boolean - iftrue
, the Observer will watch the direction of the very first drag move after each press (with type: "pointer" and/or "touch") and lock into that direction until the user releases the pointer/touch. So if the first drag is horizontal, then only the horizontal-related callbacks likeonChangeX()
will fire until the pointer/touch is released. There's even anonLockAxis()
callback that you can tie into.onChange
Function - function to call when there is movement on either the y-axis (vertically) or the x-axis (horizontally). It will keep calling the function as long as the movement continues (subject to any tolerance threshold).onChangeX
Function - function to call when there is movement on the x-axis (horizontally). It will keep calling the function as long as the movement continues (subject to any tolerance threshold).onChangeY
Function - function to call when there is movement on the y-axis (vertically). It will keep calling the function as long as the movement continues (subject to any tolerance threshold).onClick
Function - function to call when the target is clicked.onDown
Function - function to call when downward motion is detected, meaning the delta values increase (like dragging your finger/mouse DOWNWARD...which makes they
coordinate increase). If you want to invert only the mouse wheel delta, you can setwheelSpeed: -1
because it's a multiplier.onDragStart
Function - function to call when the user presses down on the target and then begins dragging (subject todragMinimum
). This only applies to "touch" and/or "pointer" types.onDrag
Function - function to call when the user moves the pointer/touch/mouse while pressing on the target element (only applies to "touch" and/or "pointer" types).onDragEnd
Function - function to call when the user stops dragging on the target element (only applies to "touch" and/or "pointer" types).onLeft
Function - function to call when motion is detected toward the left direction.onLockAxis
Function - function to call when the axis gets locked (requireslockAxis: true
). You can check which axis via the Observer'saxis
property ("x" or "y").onHover
Function - function to call when the pointer/mouse hovers over the target ("pointerenter"/"mouseenter" event).onHoverEnd
Function - function to call when the pointer/mouse moves off the target ("pointerleave"/"mouseleave" event).onMove
Function - function to call when the user moves the pointer/mouse while hovered over the target element (only applies to "pointer" types). It listens for "pointermove"/"mousemove" events internally. UseonDrag
if you want it to fire only while pressing and dragging. Note that when you define an onMove, it causes the Observer to measure delta values while hovering over the target, consequently triggering the appropriate movement-related callbacks like onUp, onDown, onChange, etc. for any pointer/mouse movement while over the target. Normally the movement-related callbacks are only triggered when the user presses and drags.onPress
Function - function to call when the user presses down on the target element (only applies to "touch" and/or "pointer" types).onRelease
Function - function to call when the touch/pointer is released after theonPress
was called (only applies to "touch" and/or "pointer" types).onRight
Function - function to call when motion is detected toward the right direction.onStop
Function - function to call when changes have ceased for at least 0.25 seconds (configurable withonStopDelay
)onStopDelay
Number - number of seconds to wait after changes have ceased firing before theonStop
gets called (default: 0.25 seconds).onToggleX
Function - function to call when motion switches direction on the x-axis (horizontally).onToggleY
Function - function to call when motion switches direction on the y-axis (vertically).onUp
Function - function to call when upward motion is detected, meaning the delta values decrease (like dragging your finger/mouse UPWARD...which makes they
coordinate decrease). If you want to invert only the mouse wheel delta, you can setwheelSpeed: -1
because it's a multiplier.onWheel
Function - function to call when the mouse wheel is used.scrollSpeed
Number - a multiplier for scroll delta values. This only applies to type"scroll"
, meaning when the target dispatches a scroll event which is different than a wheel event. You could setscrollSpeed: -1
to invert the delta values and have it callonUp
instead ofonDown
(and vice versa).scrollSpeed: 0.5
would make the delta values half of what they'd normally be. Note: there's also a separatewheelSpeed
option that only applies to wheel events.target
Element | String - the element whose events should be listened for. By default, it's the main viewport.tolerance
Number - the minimum distance (in pixels) necessary to trigger one of the callbacks likeonUp
,onDown
,onChangeY
, etc. So, for example, if the tolerance is 10 but the user only moves 8 pixels, no callback will be fired. Once the distance exceeds the tolerance amount, it fires the callbacks and resets, waiting for that distance to be exceeded again before firing the callback(s).type
String - a comma-delimited list of the types of actions you'd like to listen for which can include any (or all) of the following:"wheel,touch,scroll,pointer"
. "touch" works on any touch devices regardless of browser (iOS/Android may use TouchEvents under the hood whereas Microsoft may use PointerEvents but Observer includes them both in "touch"). "pointer" covers any non-touch pointer/mouse press/drag/swipe movements. "wheel" is for mouse wheel movements, and "scroll" is for scroll events. Default is"wheel,touch,pointer"
wheelSpeed
Number - a multiplier for wheel delta values. By default, it merely passes along the wheel event's delta that the browser reports but perhaps it seems faster/slower than when you press/drag with the pointer and you need a way to make them more similar. To make the wheel delta values half of what they normally are, for example, you'd dowheelSpeed: 0.5
. You could setwheelSpeed: -1
to invert the delta values and have it callonUp
instead ofonDown
(and vice versa). Note: there's also a separatescrollSpeed
option that only applies to scroll events.
Property
Description
Callback data
Each callback is passed the Observer instance itself as the only parameter so that you can easily access data like self.velocityX
, self.velocityY
, self.deltaX
, self.deltaY
, self.x
, self.y
, etc. (see the sidebar to the left for a list of all the available properties) like:
Observer.create({
...
onChange: (self) => {
console.log("velocity:", self.velocityX, self.velocityY, "delta:", self.deltaX, self.deltaY, "target element:", self.target, "last event:", self.event);
}
});
There's a list of properties in the nav bar to the left.
Observer is included in ScrollTrigger too!
There's a ScrollTrigger.observe() method that's identical to Observer.create()
. Since ScrollTrigger's normalizeScroll() functionality leverages Observer under the hood (thus it's included inside ScrollTrigger anyway), it made sense to expose its functionality so that you can avoid loading Observer as a separate file if you're already using ScrollTrigger in your project. You're welcome. 🙂
Showcase & how-to demos
Properties
deltaX : Number |
deltaY : Number |
event : Event |
isDragging : Boolean |
isEnabled : Boolean |
isPressed : Boolean |
startX : Number |
startY : Number |
Observer.isTouch : Number |
target : Element |
vars : Object |
velocityX : Number |
velocityY : Number |
x : Number |
y : Number |
Methods
disable( ) : void |
enable( event:Event ) : Self |
kill( ) : void |
Observer.create( vars:Object ) : Observer |
Observer.getAll( ) : Array |
Observer.getById( id:String ) : Observer |
FAQ's
Can I apply multiple Observer instances to the same target?
Absolutely! That could be useful if, for example, you want certain callbacks debounced but others not. And remember that you can .disable() and .enable() an Observer anytime.
If I'm loading ScrollTrigger already, do I need to ALSO load Observer?
No, Observer is already included inside the ScrollTrigger file; you can access it via ScrollTrigger.observe() and skip loading the Observer file separately.
How do I include Observer in my project?
See the installation page for all the options (CDN, NPM, download, etc.) where there's even an interactive helper that provides the necessary code. Easy peasy. Don't forget to register Observer like this in your project:
gsap.registerPlugin(Observer)
Is this included in the GSAP core?
Is this only for Club GSAP members?
No, it's available to everyone for free! But Club GSAP is pretty awesome...just sayin'.
It works fine during development, but suddenly stops working in the production build! What do I do?
Your build tool is probably dropping the plugin when tree shaking and you forgot to register Observer (which protects it from tree shaking). Just register the plugin like this:
gsap.registerPlugin(Observer)