UNPKG

handsfree

Version:

Quickly integrate face, hand, and/or pose tracking to your frontend projects in a snap ✨👌

204 lines (179 loc) 5.23 kB
// Maps handsfree pincher events to const eventMap = { start: 'mousedown', held: 'mousemove', released: 'mouseup' } // The last pointer positions for each hand, used to determine movement over time let lastHeld = [{x: 0, y: 0}, {x: 0, y: 0}, {x: 0, y: 0}, {x: 0, y: 0}] /** * Move a pointer with your palm */ export default { models: 'hands', tags: ['browser'], enabled: false, // The pointer element $pointer: [], arePointersVisible: true, // Pointers position pointer: [ { x: -20, y: -20, isVisible: false }, { x: -20, y: -20, isVisible: false }, { x: -20, y: -20, isVisible: false }, { x: -20, y: -20, isVisible: false } ], // Used to smoothen out the pointer tween: [ {x: -20, y: -20}, {x: -20, y: -20}, {x: -20, y: -20}, {x: -20, y: -20}, ], config: { offset: { x: 0, y: 0 }, speed: { x: 1, y: 1 } }, /** * Create and toggle pointers */ onUse () { for (let i = 0; i < 4; i++) { const $pointer = document.createElement('div') $pointer.classList.add('handsfree-pointer', 'handsfree-pointer-palm', 'handsfree-hide-when-started-without-hands') document.body.appendChild($pointer) this.$pointer[i] = $pointer } if (this.enabled && this.arePointersVisible) { this.showPointers() } else { this.hidePointers() } }, /** * Show pointers on enable */ onEnable () { const arePointersVisible = this.arePointersVisible this.showPointers() this.arePointersVisible = arePointersVisible }, /** * Hide pointers on disable */ onDisable () { const arePointersVisible = this.arePointersVisible this.hidePointers() this.arePointersVisible = arePointersVisible }, /** * Positions the pointer and dispatches events */ onFrame ({hands}) { // Hide pointers if (!hands?.multiHandLandmarks) { this.$pointer.forEach($pointer => $pointer.style.display = 'none') return } hands.pointer = [ { isVisible: false }, { isVisible: false }, { isVisible: false }, { isVisible: false } ] hands.multiHandLandmarks.forEach((landmarks, n) => { const pointer = hands.pointer[n] // Use the correct hand index let hand if (n < 2) { hand = hands.multiHandedness[n].label === 'Right' ? 0 : 1 } else { hand = hands.multiHandedness[n].label === 'Right' ? 2 : 3 } // Update pointer position this.handsfree.TweenMax.to(this.tween[hand], 1, { x: window.outerWidth * this.config.speed.x - window.outerWidth * this.config.speed.x / 2 + window.outerWidth / 2 - hands.multiHandLandmarks[n][21].x * this.config.speed.x * window.outerWidth + this.config.offset.x, y: hands.multiHandLandmarks[n][21].y * window.outerHeight * this.config.speed.y - window.outerHeight * this.config.speed.y / 2 + window.outerHeight / 2 + this.config.offset.y, overwrite: true, ease: 'linear.easeNone', immediate: true }) hands.pointer[hand] = { x: this.tween[hand].x, y: this.tween[hand].y, isVisible: true } // Visually update pointer element this.$pointer[hand].style.left = `${this.tween[hand].x}px` this.$pointer[hand].style.top = `${this.tween[hand].y}px` // Dispatch events let event = pointer?.pinchState?.[n]?.[0] if (event && pointer.isVisible) { // Get the event and element to send events to event = eventMap[event] const $el = document.elementFromPoint(pointer.x, pointer.y) // Dispatch the event if ($el) { $el.dispatchEvent( new MouseEvent(event, { view: window, button: 0, bubbles: true, cancelable: true, clientX: pointer.x, clientY: pointer.y, // Only used when the mouse is captured in full screen mode movementX: pointer.x - lastHeld[hand].x, movementY: pointer.y - lastHeld[hand].y }) ) } lastHeld[hand] = pointer } }) // Toggle pointers hands.pointer.forEach((pointer, hand) => { if (pointer.isVisible) { this.$pointer[hand].style.display = 'block' } else { this.$pointer[hand].style.display = 'none' } }) }, /** * Toggle pointer */ onDisable() { this.$pointer.forEach($pointer => { $pointer.classList.add('handsfree-hidden') }) }, /** * Toggle pointers */ showPointers () { this.arePointersVisible = true for (let i = 0; i < 4; i++) { this.$pointer[i].classList.remove('handsfree-hidden') } }, hidePointers () { this.arePointersVisible = false for (let i = 0; i < 4; i++) { this.$pointer[i].classList.add('handsfree-hidden') } } }