diff --git a/dist/index.cjs b/dist/index.cjs index f5f96b3..b80be33 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -344,6 +344,8 @@ function getController$1 (config) { }; } +const MOVEMENT_RESET_DELAY = 1e3 / 60 * 3; // == 50 (3 frames in 60fps) + /** * @class Pointer * @param {PointerConfig} config @@ -409,15 +411,19 @@ class Pointer { const DPR = shouldFixSynthPointer ? window.devicePixelRatio : 1; const _measure = (event) => { - this.progress.x = this.config.root ? event.offsetX : event.x; - this.progress.y = this.config.root ? event.offsetY : event.y; - this.progress.vx = event.movementX; - this.progress.vy = event.movementY; + const newX = this.config.root ? event.offsetX : event.x; + const newY = this.config.root ? event.offsetY : event.y; + this.progress.vx = newX - this.progress.x; + this.progress.vy = newY - this.progress.y; + this.progress.x = newX; + this.progress.y = newY; this._nextTick = trigger(); }; this._pointerLeave = () => { this.progress.active = false; + this.progress.vx = 0; + this.progress.vy = 0; this._nextTick = trigger(); }; @@ -434,8 +440,6 @@ class Pointer { cancelable: true, clientX: e.x * DPR, clientY: e.y * DPR, - movementX: e.movementX * DPR, - movementY: e.movementY * DPR, }); e.stopPropagation(); @@ -481,11 +485,18 @@ class Pointer { const duration = this.config.transitionDuration; const easing = this.config.transitionEasing || ((p) => p); const now = performance.now(); + let resetMovement = false; const tick = (time) => { const p = (time - this._startTime) / duration; const t = easing(Math.min(1, p)); + if (resetMovement) { + this.progress.vx = 0; + this.progress.vy = 0; + resetMovement = false; + } + this.currentProgress = Object.entries(this.progress).reduce((acc, [key, value]) => { if (key === 'active') { acc[key] = value; @@ -497,9 +508,9 @@ class Pointer { if (p < 1) { this._nextTransitionTick = requestAnimationFrame(tick); - } else { - this.currentProgress.vx = 0; - this.currentProgress.vy = 0; + + // reset movement on next frame + resetMovement = time - this._startTime > MOVEMENT_RESET_DELAY; } this.effect.tick(this.currentProgress); diff --git a/docs/demo/index.html b/docs/demo/index.html index c140183..bdf0753 100644 --- a/docs/demo/index.html +++ b/docs/demo/index.html @@ -28,8 +28,8 @@ #target { box-sizing: border-box; width: 40px; - margin: -20px 0 0 -20px; - /*margin: calc(25% - 20px) 0 0 calc(50% - 20px);*/ + /*margin: -20px 0 0 -20px;*/ + margin: calc(25% - 20px) 0 0 calc(50% - 20px); aspect-ratio: 1; border: 10px solid #007bff; border-radius: 50%; @@ -37,7 +37,7 @@ 0 0 6px rgb(0 0 0 / 50%), inset 0 0 4px rgb(0 0 0 / 50%); pointer-events: none; - /*transition: transform 1s linear;*/ + /*transition: transform 0.5s linear;*/ } #cover { @@ -66,6 +66,7 @@

       
 

       
 

+      

     
     
@@ -84,11 +85,12 @@ const vxmax = document.getElementById('vxmax'); const vy = document.getElementById('vy'); const vymax = document.getElementById('vymax'); + const active = document.getElementById('active'); let vxmaxValue = 0; let vymaxValue = 0; - function log (p, v) { + function log (p, v, isActive) { x.innerText = `X: ${p.x}`; y.innerText = `Y: ${p.y}`; vx.innerText = `Vx: ${v.x}`; @@ -97,21 +99,24 @@ vymaxValue = Math.max(vymaxValue, v.y); vxmax.innerText = `Vx Max: ${vxmaxValue}`; vymax.innerText = `Vy Max: ${vymaxValue}`; + active.innerText = `Active: ${isActive}`; } const WIDTH = root.clientWidth; const HEIGHT = root.clientHeight; const pointer = new Pointer({ root, + allowActiveEvent: true, scenes: [{ target, - effect: (scene, p, v) => { - log(p, v); - target.style.transform = `translate(${p.x * WIDTH}px, ${p.y * HEIGHT}px)`; - // target.style.transform = `translate(${v.x * 5}px, ${v.y * 5}px)`; + effect: (scene, p, v, isActive) => { + log(p, v, isActive); + // target.style.transform = `translate(${p.x * WIDTH}px, ${p.y * HEIGHT}px)`; + target.style.transform = `translate(${v.x * 5}px, ${v.y * 5}px)`; } }], - transitionDuration: 1000, + // noThrottle: true, + transitionDuration: 500, transitionEasing: (t) => 1 - (1 - t) ** 2, // quadOut }); diff --git a/docs/demo/index.js b/docs/demo/index.js index 3b48f53..78a703b 100644 --- a/docs/demo/index.js +++ b/docs/demo/index.js @@ -342,6 +342,8 @@ function getController$1 (config) { }; } +const MOVEMENT_RESET_DELAY = 1e3 / 60 * 3; // 3 frames + /** * @class Pointer * @param {PointerConfig} config @@ -407,15 +409,19 @@ class Pointer { const DPR = shouldFixSynthPointer ? window.devicePixelRatio : 1; const _measure = (event) => { - this.progress.x = this.config.root ? event.offsetX : event.x; - this.progress.y = this.config.root ? event.offsetY : event.y; - this.progress.vx = event.movementX; - this.progress.vy = event.movementY; + const newX = this.config.root ? event.offsetX : event.x; + const newY = this.config.root ? event.offsetY : event.y; + this.progress.vx = newX - this.progress.x; + this.progress.vy = newY - this.progress.y; + this.progress.x = newX; + this.progress.y = newY; this._nextTick = trigger(); }; this._pointerLeave = () => { this.progress.active = false; + this.progress.vx = 0; + this.progress.vy = 0; this._nextTick = trigger(); }; @@ -432,8 +438,6 @@ class Pointer { cancelable: true, clientX: e.x * DPR, clientY: e.y * DPR, - movementX: e.movementX * DPR, - movementY: e.movementY * DPR, }); e.stopPropagation(); @@ -479,11 +483,18 @@ class Pointer { const duration = this.config.transitionDuration; const easing = this.config.transitionEasing || ((p) => p); const now = performance.now(); + let resetMovement = false; const tick = (time) => { const p = (time - this._startTime) / duration; const t = easing(Math.min(1, p)); + if (resetMovement) { + this.progress.vx = 0; + this.progress.vy = 0; + resetMovement = false; + } + this.currentProgress = Object.entries(this.progress).reduce((acc, [key, value]) => { if (key === 'active') { acc[key] = value; @@ -495,9 +506,9 @@ class Pointer { if (p < 1) { this._nextTransitionTick = requestAnimationFrame(tick); - } else { - this.currentProgress.vx = 0; - this.currentProgress.vy = 0; + + // reset movement on next frame + resetMovement = time - this._startTime > MOVEMENT_RESET_DELAY; } this.effect.tick(this.currentProgress); diff --git a/package.json b/package.json index 7195911..431ac37 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "kuliso", - "version": "0.4.5", + "version": "0.4.6", "sideeffects": true, "description": "Tiny library for performant pointer-driven or gyroscope-driven effects", "main": "dist/index.cjs", diff --git a/src/Pointer.js b/src/Pointer.js index bf8c35a..9d599ac 100644 --- a/src/Pointer.js +++ b/src/Pointer.js @@ -1,6 +1,8 @@ import { getController } from './controller.js'; import { frameThrottle, testPointerOffsetDprBug } from './utilities.js'; +const MOVEMENT_RESET_DELAY = 1e3 / 60 * 3; // == 50 (3 frames in 60fps) + /** * @class Pointer * @param {PointerConfig} config @@ -66,15 +68,19 @@ export class Pointer { const DPR = shouldFixSynthPointer ? window.devicePixelRatio : 1; const _measure = (event) => { - this.progress.x = this.config.root ? event.offsetX : event.x; - this.progress.y = this.config.root ? event.offsetY : event.y; - this.progress.vx = event.movementX; - this.progress.vy = event.movementY; + const newX = this.config.root ? event.offsetX : event.x; + const newY = this.config.root ? event.offsetY : event.y; + this.progress.vx = newX - this.progress.x; + this.progress.vy = newY - this.progress.y; + this.progress.x = newX; + this.progress.y = newY; this._nextTick = trigger(); }; this._pointerLeave = () => { this.progress.active = false; + this.progress.vx = 0; + this.progress.vy = 0; this._nextTick = trigger(); }; @@ -91,8 +97,6 @@ export class Pointer { cancelable: true, clientX: e.x * DPR, clientY: e.y * DPR, - movementX: e.movementX * DPR, - movementY: e.movementY * DPR, }); e.stopPropagation(); @@ -138,11 +142,18 @@ export class Pointer { const duration = this.config.transitionDuration; const easing = this.config.transitionEasing || ((p) => p); const now = performance.now(); + let resetMovement = false; const tick = (time) => { const p = (time - this._startTime) / duration; const t = easing(Math.min(1, p)); + if (resetMovement) { + this.progress.vx = 0; + this.progress.vy = 0; + resetMovement = false; + } + this.currentProgress = Object.entries(this.progress).reduce((acc, [key, value]) => { if (key === 'active') { acc[key] = value; @@ -154,9 +165,9 @@ export class Pointer { if (p < 1) { this._nextTransitionTick = requestAnimationFrame(tick); - } else { - this.currentProgress.vx = 0; - this.currentProgress.vy = 0; + + // reset movement on next frame + resetMovement = time - this._startTime > MOVEMENT_RESET_DELAY; } this.effect.tick(this.currentProgress);