From bd4822d5904e65bb3eadd36ce70764d6f5203c3f Mon Sep 17 00:00:00 2001 From: Kevin Lee Date: Thu, 1 Feb 2018 15:20:08 -0800 Subject: [PATCH 01/14] optionally pass in entity in event to enable specifying which entity to grab --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index ae3fc95..188ca24 100644 --- a/index.js +++ b/index.js @@ -161,7 +161,7 @@ AFRAME.registerComponent('super-hands', { this.dispatchMouseEventAll('mousedown', this.el) this.gehClicking = new Set(this.hoverEls) if (!carried) { - carried = this.findTarget(this.GRAB_EVENT, { + carried = evt.detail.targetEntity || this.findTarget(this.GRAB_EVENT, { hand: this.el, buttonEvent: evt }) From 9b9c7754fdaf3c9d78f0866e7bd7a45104768c59 Mon Sep 17 00:00:00 2001 From: Kevin Lee Date: Thu, 22 Feb 2018 15:59:17 -0800 Subject: [PATCH 02/14] aframe master doesn't always have evt.detail --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 188ca24..336caba 100644 --- a/index.js +++ b/index.js @@ -161,7 +161,7 @@ AFRAME.registerComponent('super-hands', { this.dispatchMouseEventAll('mousedown', this.el) this.gehClicking = new Set(this.hoverEls) if (!carried) { - carried = evt.detail.targetEntity || this.findTarget(this.GRAB_EVENT, { + carried = (evt.detail ? evt.detail.targetEntity : false) || this.findTarget(this.GRAB_EVENT, { hand: this.el, buttonEvent: evt }) From 0c956b889acccdaa9b8b57d5315861dbbfddc49d Mon Sep 17 00:00:00 2001 From: Kevin Lee Date: Wed, 14 Mar 2018 16:08:27 -0700 Subject: [PATCH 03/14] optionally use world position when calculating hand distance for stretchable component --- reaction_components/stretchable.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/reaction_components/stretchable.js b/reaction_components/stretchable.js index e19d188..2b8298a 100644 --- a/reaction_components/stretchable.js +++ b/reaction_components/stretchable.js @@ -8,7 +8,8 @@ AFRAME.registerComponent('stretchable', inherit(base, { schema: { usePhysics: {default: 'ifavailable'}, invert: {default: false}, - physicsUpdateRate: {default: 100} + physicsUpdateRate: {default: 100}, + useWorldSpaceCoordinates: {type: "bool", default: false} }, init: function () { this.STRETCHED_STATE = 'stretched' @@ -37,8 +38,13 @@ AFRAME.registerComponent('stretchable', inherit(base, { tick: function (time, timeDelta) { if (!this.stretched) { return } this.scale.copy(this.el.getAttribute('scale')) - this.handPos.copy(this.stretchers[0].getAttribute('position')) - this.otherHandPos.copy(this.stretchers[1].getAttribute('position')) + if (this.data.useWorldSpaceCoordinates) { + this.stretchers[0].object3D.getWorldPosition(this.handPos) + this.stretchers[1].object3D.getWorldPosition(this.otherHandPos) + } else { + this.handPos.copy(this.stretchers[0].getAttribute('position')) + this.otherHandPos.copy(this.stretchers[1].getAttribute('position')) + } const currentStretch = this.handPos.distanceTo(this.otherHandPos) let deltaStretch = 1 if (this.previousStretch !== null && currentStretch !== 0) { From c5be38efee5deecb31b0879a3bc131cef8c2e554 Mon Sep 17 00:00:00 2001 From: Kevin Lee Date: Wed, 14 Mar 2018 16:47:46 -0700 Subject: [PATCH 04/14] fix quotes --- reaction_components/stretchable.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reaction_components/stretchable.js b/reaction_components/stretchable.js index 2b8298a..0561be1 100644 --- a/reaction_components/stretchable.js +++ b/reaction_components/stretchable.js @@ -9,7 +9,7 @@ AFRAME.registerComponent('stretchable', inherit(base, { usePhysics: {default: 'ifavailable'}, invert: {default: false}, physicsUpdateRate: {default: 100}, - useWorldSpaceCoordinates: {type: "bool", default: false} + useWorldSpaceCoordinates: {type: 'bool', default: false} }, init: function () { this.STRETCHED_STATE = 'stretched' From dcf2d5c70382cef5194a95fd13a3cb215d19bea9 Mon Sep 17 00:00:00 2001 From: Kevin Lee Date: Wed, 14 Mar 2018 16:50:08 -0700 Subject: [PATCH 05/14] update dist --- dist/super-hands.js | 14 ++++++++++---- dist/super-hands.min.js | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/dist/super-hands.js b/dist/super-hands.js index 5d6f496..8d25433 100644 --- a/dist/super-hands.js +++ b/dist/super-hands.js @@ -143,7 +143,7 @@ AFRAME.registerComponent('super-hands', { this.dispatchMouseEventAll('mousedown', this.el); this.gehClicking = new Set(this.hoverEls); if (!carried) { - carried = this.findTarget(this.GRAB_EVENT, { + carried = (evt.detail ? evt.detail.targetEntity : false) || this.findTarget(this.GRAB_EVENT, { hand: this.el, buttonEvent: evt }); @@ -1391,7 +1391,8 @@ AFRAME.registerComponent('stretchable', inherit(base, { schema: { usePhysics: { default: 'ifavailable' }, invert: { default: false }, - physicsUpdateRate: { default: 100 } + physicsUpdateRate: { default: 100 }, + useWorldSpaceCoordinates: { type: 'bool', default: false } }, init: function () { this.STRETCHED_STATE = 'stretched'; @@ -1418,8 +1419,13 @@ AFRAME.registerComponent('stretchable', inherit(base, { return; } this.scale.copy(this.el.getAttribute('scale')); - this.handPos.copy(this.stretchers[0].getAttribute('position')); - this.otherHandPos.copy(this.stretchers[1].getAttribute('position')); + if (this.data.useWorldSpaceCoordinates) { + this.stretchers[0].object3D.getWorldPosition(this.handPos); + this.stretchers[1].object3D.getWorldPosition(this.otherHandPos); + } else { + this.handPos.copy(this.stretchers[0].getAttribute('position')); + this.otherHandPos.copy(this.stretchers[1].getAttribute('position')); + } const currentStretch = this.handPos.distanceTo(this.otherHandPos); let deltaStretch = 1; if (this.previousStretch !== null && currentStretch !== 0) { diff --git a/dist/super-hands.min.js b/dist/super-hands.min.js index bb07115..7eb7453 100644 --- a/dist/super-hands.min.js +++ b/dist/super-hands.min.js @@ -1,5 +1,5 @@ (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o{a.removeEventListener('stateremoved',this.unWatch)}),this.hoverEls.length=0,this.state.get(this.HOVER_EVENT)&&this._unHover(this.state.get(this.HOVER_EVENT)),this.onGrabEndButton(),this.onStretchEndButton(),this.onDragDropEndButton()},pause:function(){},play:function(){},onGrabStartButton:function(a){let b=this.state.get(this.GRAB_EVENT);this.dispatchMouseEventAll('mousedown',this.el),this.gehClicking=new Set(this.hoverEls),b||(b=this.findTarget(this.GRAB_EVENT,{hand:this.el,buttonEvent:a}),b&&(this.state.set(this.GRAB_EVENT,b),this._unHover(b)))},onGrabEndButton:function(a){const b=this.hoverEls.filter((a)=>this.gehClicking.has(a)),c=this.state.get(this.GRAB_EVENT),d={hand:this.el,buttonEvent:a};this.dispatchMouseEventAll('mouseup',this.el);for(let c=0;c{this.dispatchMouseEvent(a,'dragend',this.el),this.dispatchMouseEventAll('drop',a,!0,!0),this.dispatchMouseEventAll('dragleave',a,!0,!0)}),this.gehDragged.clear(),b){const c={hand:this.el,dropped:b,on:null,buttonEvent:a},d={hand:this.el,buttonEvent:a},e=this.findTarget(this.DRAGDROP_EVENT,c,!0);e&&(c.on=e,this.emitCancelable(b,this.DRAGDROP_EVENT,c),this._unHover(e)),this.emitCancelable(b,this.UNDRAG_EVENT,d)||(this.promoteHoveredEl(b),this.state.delete(this.DRAG_EVENT),this.hover())}},onHit:function(a){const b=a.detail[this.data.colliderEventProperty];var c=(a,b)=>{let c;if(c=this.hoverEls.indexOf(a),-1===c){if(b){let c=0;for(const a=this.hoverElsDist;b{this.dispatchMouseEventAll('dragenter',a,!0,!0)}),this.hover()}};if(b)if(Array.isArray(b)){for(let d,e=0;ethis._unHover(a)):this._unHover(b):a.detail.state===this.data.colliderState&&this._unHover(a.target)},_unHover:function(a,b){let c,d=!1;a.removeEventListener('stateremoved',this.unHover),a===this.state.get(this.DRAGOVER_EVENT)&&(this.state.delete(this.DRAGOVER_EVENT),d=!0,c={hand:this.el,hovered:a,carried:this.state.get(this.DRAG_EVENT)},this.emitCancelable(a,this.UNDRAGOVER_EVENT,c),this.state.has(this.DRAG_EVENT)&&this.emitCancelable(this.state.get(this.DRAG_EVENT),this.UNDRAGOVER_EVENT,c)),a===this.state.get(this.HOVER_EVENT)&&(this.state.delete(this.HOVER_EVENT),d=!0,this.emitCancelable(a,this.UNHOVER_EVENT,{hand:this.el})),d&&!b&&this.hover()},unWatch:function(a){const b=a.detail[this.data.colliderEndEventProperty];b?Array.isArray(b)?b.forEach((a)=>this._unWatch(a)):this._unWatch(b):a.detail.state===this.data.colliderState&&this._unWatch(a.target)},_unWatch:function(a){var b=this.hoverEls.indexOf(a);a.removeEventListener('stateremoved',this.unWatch),-1!==b&&(this.hoverEls.splice(b,1),this.hoverElsDist.splice(b,1)),this.gehDragged.forEach((b)=>{this.dispatchMouseEvent(a,'dragleave',b),this.dispatchMouseEvent(b,'dragleave',a)}),this.dispatchMouseEvent(a,'mouseout',this.el)},registerListeners:function(){this.el.addEventListener(this.data.colliderEvent,this.onHit),this.el.addEventListener(this.data.colliderEndEvent,this.unWatch),this.el.addEventListener(this.data.colliderEndEvent,this.unHover),this.data.grabStartButtons.forEach((a)=>{this.el.addEventListener(a,this.onGrabStartButton)}),this.data.stretchStartButtons.forEach((a)=>{this.el.addEventListener(a,this.onStretchStartButton)}),this.data.dragDropStartButtons.forEach((a)=>{this.el.addEventListener(a,this.onDragDropStartButton)}),this.data.dragDropEndButtons.forEach((a)=>{this.el.addEventListener(a,this.onDragDropEndButton)}),this.data.stretchEndButtons.forEach((a)=>{this.el.addEventListener(a,this.onStretchEndButton)}),this.data.grabEndButtons.forEach((a)=>{this.el.addEventListener(a,this.onGrabEndButton)})},unRegisterListeners:function(a){a=a||this.data;0===Object.keys(a).length||(this.el.removeEventListener(a.colliderEvent,this.onHit),this.el.removeEventListener(a.colliderEndEvent,this.unHover),this.el.removeEventListener(a.colliderEndEvent,this.unWatch),a.grabStartButtons.forEach((a)=>{this.el.removeEventListener(a,this.onGrabStartButton)}),a.grabEndButtons.forEach((a)=>{this.el.removeEventListener(a,this.onGrabEndButton)}),a.stretchStartButtons.forEach((a)=>{this.el.removeEventListener(a,this.onStretchStartButton)}),a.stretchEndButtons.forEach((a)=>{this.el.removeEventListener(a,this.onStretchEndButton)}),a.dragDropStartButtons.forEach((a)=>{this.el.removeEventListener(a,this.onDragDropStartButton)}),a.dragDropEndButtons.forEach((a)=>{this.el.removeEventListener(a,this.onDragDropEndButton)}))},emitCancelable:function(a,b,c){var d,e;return c=c||{},d={bubbles:!0,cancelable:!0,detail:c},d.detail.target=d.detail.target||a,e=new window.CustomEvent(b,d),a.dispatchEvent(e)},dispatchMouseEvent:function(a,b,c){var d=new window.MouseEvent(b,{relatedTarget:c});a.dispatchEvent(d)},dispatchMouseEventAll:function(a,b,c,d){let e=this.hoverEls;if(c&&(e=e.filter((a)=>a!==this.state.get(this.GRAB_EVENT)&&a!==this.state.get(this.DRAG_EVENT)&&a!==this.state.get(this.STRETCH_EVENT)&&!this.gehDragged.has(a))),d)for(let c=0;ca!==this.state.get(this.GRAB_EVENT)&&a!==this.state.get(this.DRAG_EVENT)&&a!==this.state.get(this.STRETCH_EVENT))),d=e.length-1;0<=d;d--)if(!this.emitCancelable(e[d],a,b))return e[d];return null},promoteHoveredEl:function(a){var b=this.hoverEls.indexOf(a);-1!==b&&null==this.hoverElsDist[b]&&(this.hoverEls.splice(b,1),this.hoverElsDist.splice(b,1),this.hoverEls.push(a),this.hoverElsDist.push(null))}}); +'use strict';if('undefined'==typeof AFRAME)throw new Error('Component attempted to register before AFRAME was available.');require('./systems/super-hands-system.js'),require('./reaction_components/hoverable.js'),require('./reaction_components/grabbable.js'),require('./reaction_components/stretchable.js'),require('./reaction_components/drag-droppable.js'),require('./reaction_components/draggable.js'),require('./reaction_components/droppable.js'),require('./reaction_components/clickable.js'),require('./misc_components/locomotor-auto-config.js'),require('./misc_components/progressive-controls.js'),require('./primitives/a-locomotor.js'),AFRAME.registerComponent('super-hands',{schema:{colliderState:{default:''},colliderEvent:{default:'hit'},colliderEventProperty:{default:'el'},colliderEndEvent:{default:'hitend'},colliderEndEventProperty:{default:'el'},grabStartButtons:{default:['gripdown','trackpaddown','triggerdown','gripclose','abuttondown','bbuttondown','xbuttondown','ybuttondown','pointup','thumbup','pointingstart','pistolstart','thumbstickdown','mousedown','touchstart']},grabEndButtons:{default:['gripup','trackpadup','triggerup','gripopen','abuttonup','bbuttonup','xbuttonup','ybuttonup','pointdown','thumbdown','pointingend','pistolend','thumbstickup','mouseup','touchend']},stretchStartButtons:{default:['gripdown','trackpaddown','triggerdown','gripclose','abuttondown','bbuttondown','xbuttondown','ybuttondown','pointup','thumbup','pointingstart','pistolstart','thumbstickdown','mousedown','touchstart']},stretchEndButtons:{default:['gripup','trackpadup','triggerup','gripopen','abuttonup','bbuttonup','xbuttonup','ybuttonup','pointdown','thumbdown','pointingend','pistolend','thumbstickup','mouseup','touchend']},dragDropStartButtons:{default:['gripdown','trackpaddown','triggerdown','gripclose','abuttondown','bbuttondown','xbuttondown','ybuttondown','pointup','thumbup','pointingstart','pistolstart','thumbstickdown','mousedown','touchstart']},dragDropEndButtons:{default:['gripup','trackpadup','triggerup','gripopen','abuttonup','bbuttonup','xbuttonup','ybuttonup','pointdown','thumbdown','pointingend','pistolend','thumbstickup','mouseup','touchend']}},multiple:!1,init:function(){this.HOVER_EVENT='hover-start',this.UNHOVER_EVENT='hover-end',this.GRAB_EVENT='grab-start',this.UNGRAB_EVENT='grab-end',this.STRETCH_EVENT='stretch-start',this.UNSTRETCH_EVENT='stretch-end',this.DRAG_EVENT='drag-start',this.UNDRAG_EVENT='drag-end',this.DRAGOVER_EVENT='dragover-start',this.UNDRAGOVER_EVENT='dragover-end',this.DRAGDROP_EVENT='drag-drop',this.otherSuperHand=null,this.gehDragged=new Set,this.gehClicking=new Set,this.hoverEls=[],this.hoverElsDist=[],this.state=new Map,this.dragging=!1,this.unHover=this.unHover.bind(this),this.unWatch=this.unWatch.bind(this),this.onHit=this.onHit.bind(this),this.onGrabStartButton=this.onGrabStartButton.bind(this),this.onGrabEndButton=this.onGrabEndButton.bind(this),this.onStretchStartButton=this.onStretchStartButton.bind(this),this.onStretchEndButton=this.onStretchEndButton.bind(this),this.onDragDropStartButton=this.onDragDropStartButton.bind(this),this.onDragDropEndButton=this.onDragDropEndButton.bind(this),this.system.registerMe(this)},update:function(a){this.data.colliderState.length&&console.warn('super-hands colliderState property is deprecated. Use colliderEndEvent/colliderEndEventProperty instead'),this.unRegisterListeners(a),this.registerListeners()},remove:function(){this.system.unregisterMe(this),this.unRegisterListeners(),this.hoverEls.forEach((a)=>{a.removeEventListener('stateremoved',this.unWatch)}),this.hoverEls.length=0,this.state.get(this.HOVER_EVENT)&&this._unHover(this.state.get(this.HOVER_EVENT)),this.onGrabEndButton(),this.onStretchEndButton(),this.onDragDropEndButton()},pause:function(){},play:function(){},onGrabStartButton:function(a){let b=this.state.get(this.GRAB_EVENT);this.dispatchMouseEventAll('mousedown',this.el),this.gehClicking=new Set(this.hoverEls),b||(b=!!a.detail&&a.detail.targetEntity||this.findTarget(this.GRAB_EVENT,{hand:this.el,buttonEvent:a}),b&&(this.state.set(this.GRAB_EVENT,b),this._unHover(b)))},onGrabEndButton:function(a){const b=this.hoverEls.filter((a)=>this.gehClicking.has(a)),c=this.state.get(this.GRAB_EVENT),d={hand:this.el,buttonEvent:a};this.dispatchMouseEventAll('mouseup',this.el);for(let c=0;c{this.dispatchMouseEvent(a,'dragend',this.el),this.dispatchMouseEventAll('drop',a,!0,!0),this.dispatchMouseEventAll('dragleave',a,!0,!0)}),this.gehDragged.clear(),b){const c={hand:this.el,dropped:b,on:null,buttonEvent:a},d={hand:this.el,buttonEvent:a},e=this.findTarget(this.DRAGDROP_EVENT,c,!0);e&&(c.on=e,this.emitCancelable(b,this.DRAGDROP_EVENT,c),this._unHover(e)),this.emitCancelable(b,this.UNDRAG_EVENT,d)||(this.promoteHoveredEl(b),this.state.delete(this.DRAG_EVENT),this.hover())}},onHit:function(a){const b=a.detail[this.data.colliderEventProperty];var c=(a,b)=>{let c;if(c=this.hoverEls.indexOf(a),-1===c){if(b){let c=0;for(const a=this.hoverElsDist;b{this.dispatchMouseEventAll('dragenter',a,!0,!0)}),this.hover()}};if(b)if(Array.isArray(b)){for(let d,e=0;ethis._unHover(a)):this._unHover(b):a.detail.state===this.data.colliderState&&this._unHover(a.target)},_unHover:function(a,b){let c,d=!1;a.removeEventListener('stateremoved',this.unHover),a===this.state.get(this.DRAGOVER_EVENT)&&(this.state.delete(this.DRAGOVER_EVENT),d=!0,c={hand:this.el,hovered:a,carried:this.state.get(this.DRAG_EVENT)},this.emitCancelable(a,this.UNDRAGOVER_EVENT,c),this.state.has(this.DRAG_EVENT)&&this.emitCancelable(this.state.get(this.DRAG_EVENT),this.UNDRAGOVER_EVENT,c)),a===this.state.get(this.HOVER_EVENT)&&(this.state.delete(this.HOVER_EVENT),d=!0,this.emitCancelable(a,this.UNHOVER_EVENT,{hand:this.el})),d&&!b&&this.hover()},unWatch:function(a){const b=a.detail[this.data.colliderEndEventProperty];b?Array.isArray(b)?b.forEach((a)=>this._unWatch(a)):this._unWatch(b):a.detail.state===this.data.colliderState&&this._unWatch(a.target)},_unWatch:function(a){var b=this.hoverEls.indexOf(a);a.removeEventListener('stateremoved',this.unWatch),-1!==b&&(this.hoverEls.splice(b,1),this.hoverElsDist.splice(b,1)),this.gehDragged.forEach((b)=>{this.dispatchMouseEvent(a,'dragleave',b),this.dispatchMouseEvent(b,'dragleave',a)}),this.dispatchMouseEvent(a,'mouseout',this.el)},registerListeners:function(){this.el.addEventListener(this.data.colliderEvent,this.onHit),this.el.addEventListener(this.data.colliderEndEvent,this.unWatch),this.el.addEventListener(this.data.colliderEndEvent,this.unHover),this.data.grabStartButtons.forEach((a)=>{this.el.addEventListener(a,this.onGrabStartButton)}),this.data.stretchStartButtons.forEach((a)=>{this.el.addEventListener(a,this.onStretchStartButton)}),this.data.dragDropStartButtons.forEach((a)=>{this.el.addEventListener(a,this.onDragDropStartButton)}),this.data.dragDropEndButtons.forEach((a)=>{this.el.addEventListener(a,this.onDragDropEndButton)}),this.data.stretchEndButtons.forEach((a)=>{this.el.addEventListener(a,this.onStretchEndButton)}),this.data.grabEndButtons.forEach((a)=>{this.el.addEventListener(a,this.onGrabEndButton)})},unRegisterListeners:function(a){a=a||this.data;0===Object.keys(a).length||(this.el.removeEventListener(a.colliderEvent,this.onHit),this.el.removeEventListener(a.colliderEndEvent,this.unHover),this.el.removeEventListener(a.colliderEndEvent,this.unWatch),a.grabStartButtons.forEach((a)=>{this.el.removeEventListener(a,this.onGrabStartButton)}),a.grabEndButtons.forEach((a)=>{this.el.removeEventListener(a,this.onGrabEndButton)}),a.stretchStartButtons.forEach((a)=>{this.el.removeEventListener(a,this.onStretchStartButton)}),a.stretchEndButtons.forEach((a)=>{this.el.removeEventListener(a,this.onStretchEndButton)}),a.dragDropStartButtons.forEach((a)=>{this.el.removeEventListener(a,this.onDragDropStartButton)}),a.dragDropEndButtons.forEach((a)=>{this.el.removeEventListener(a,this.onDragDropEndButton)}))},emitCancelable:function(a,b,c){var d,e;return c=c||{},d={bubbles:!0,cancelable:!0,detail:c},d.detail.target=d.detail.target||a,e=new window.CustomEvent(b,d),a.dispatchEvent(e)},dispatchMouseEvent:function(a,b,c){var d=new window.MouseEvent(b,{relatedTarget:c});a.dispatchEvent(d)},dispatchMouseEventAll:function(a,b,c,d){let e=this.hoverEls;if(c&&(e=e.filter((a)=>a!==this.state.get(this.GRAB_EVENT)&&a!==this.state.get(this.DRAG_EVENT)&&a!==this.state.get(this.STRETCH_EVENT)&&!this.gehDragged.has(a))),d)for(let c=0;ca!==this.state.get(this.GRAB_EVENT)&&a!==this.state.get(this.DRAG_EVENT)&&a!==this.state.get(this.STRETCH_EVENT))),d=e.length-1;0<=d;d--)if(!this.emitCancelable(e[d],a,b))return e[d];return null},promoteHoveredEl:function(a){var b=this.hoverEls.indexOf(a);-1!==b&&null==this.hoverElsDist[b]&&(this.hoverEls.splice(b,1),this.hoverElsDist.splice(b,1),this.hoverEls.push(a),this.hoverElsDist.push(null))}}); },{"./misc_components/locomotor-auto-config.js":2,"./misc_components/progressive-controls.js":3,"./primitives/a-locomotor.js":4,"./reaction_components/clickable.js":5,"./reaction_components/drag-droppable.js":6,"./reaction_components/draggable.js":7,"./reaction_components/droppable.js":8,"./reaction_components/grabbable.js":9,"./reaction_components/hoverable.js":10,"./reaction_components/stretchable.js":14,"./systems/super-hands-system.js":15}],2:[function(require,module,exports){ 'use strict';AFRAME.registerComponent('locomotor-auto-config',{schema:{camera:{default:!0},stretch:{default:!0},move:{default:!0}},dependencies:['grabbable','stretchable'],init:function(){if(this.ready=!1,this.data.camera&&!document.querySelector('a-camera, [camera]')){let a=document.createElement('a-camera');a.setAttribute('position','0 1.6 0'),this.el.appendChild(a)}this.fakeCollisions(),this.fakeCollisionsB=this.fakeCollisions.bind(this),this.el.addEventListener('controllerconnected',this.fakeCollisionsB)},update:function(){this.el.getAttribute('stretchable')&&!this.data.stretch?(this.stretchSet=this.el.getAttribute('stretchable'),this.el.removeAttribute('stretchable')):!this.el.getAttribute('stretchable')&&this.data.stretch&&this.el.setAttribute('stretchable',this.stretchSet),this.el.getAttribute('grabbable')&&!this.data.move?(this.grabSet=this.el.getAttribute('grabbable'),this.el.removeAttribute('grabbable')):!this.el.getAttribute('grabbable')&&this.data.move&&this.el.setAttribute('grabbable',this.grabSet)},remove:function(){this.el.getChildEntities().forEach((a)=>{let b=a.getAttribute('super-hands');if(b){let c={};c[b.colliderEndEventProperty]=this.el,a.emit(b.colliderEndEvent,c)}}),this.el.removeEventListener('controllerconnected',this.fakeCollisionsB)},announceReady:function(){this.ready||(this.ready=!0,this.el.emit('locomotor-ready',{}))},fakeCollisions:function(){this.el.getChildEntities().forEach((a)=>{let b=a.getAttribute('super-hands');if(b){let c={};c[b.colliderEventProperty]=this.el,a.emit(b.colliderEvent,c),this.colliderState=b.colliderState,this.el.addState(this.colliderState)}}),this.announceReady()}}); @@ -38,7 +38,7 @@ 'use strict';module.exports={schema:{usePhysics:{default:'ifavailable'}},physicsInit:function(){this.constraints=new Map},physicsUpdate:function(){'never'===this.data.usePhysics&&this.constraints.size&&this.physicsClear()},physicsRemove:function(){this.physicsClear()},physicsStart:function(a){if('never'!==this.data.usePhysics&&this.el.body&&a.detail.hand.body&&!this.constraints.has(a.detail.hand)){const b=Math.random().toString(36).substr(2,9);return this.el.setAttribute('constraint__'+b,{target:a.detail.hand}),this.constraints.set(a.detail.hand,b),!0}return'only'===this.data.usePhysics},physicsEnd:function(a){let b=this.constraints.get(a.detail.hand);b&&(this.el.removeAttribute('constraint__'+b),this.constraints.delete(a.detail.hand))},physicsClear:function(){if(this.el.body)for(let a of this.constraints.values())this.el.body.world.removeConstraint(a);this.constraints.clear()},physicsIsConstrained:function(a){return this.constraints.has(a)},physicsIsGrabbing(){return 0{b.otherSuperHand===a&&(b.otherSuperHand=null)})}}); From be32bae5166a44647a226a59b28753f2b731e03e Mon Sep 17 00:00:00 2001 From: Kevin Lee Date: Wed, 14 Mar 2018 16:56:05 -0700 Subject: [PATCH 06/14] rename --- reaction_components/stretchable.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reaction_components/stretchable.js b/reaction_components/stretchable.js index 0561be1..dd7f034 100644 --- a/reaction_components/stretchable.js +++ b/reaction_components/stretchable.js @@ -9,7 +9,7 @@ AFRAME.registerComponent('stretchable', inherit(base, { usePhysics: {default: 'ifavailable'}, invert: {default: false}, physicsUpdateRate: {default: 100}, - useWorldSpaceCoordinates: {type: 'bool', default: false} + useWorldPosition: {type: 'bool', default: false} }, init: function () { this.STRETCHED_STATE = 'stretched' @@ -38,7 +38,7 @@ AFRAME.registerComponent('stretchable', inherit(base, { tick: function (time, timeDelta) { if (!this.stretched) { return } this.scale.copy(this.el.getAttribute('scale')) - if (this.data.useWorldSpaceCoordinates) { + if (this.data.useWorldPosition) { this.stretchers[0].object3D.getWorldPosition(this.handPos) this.stretchers[1].object3D.getWorldPosition(this.otherHandPos) } else { From 24feda2728a2aaed37caa2349428043e9d9d9848 Mon Sep 17 00:00:00 2001 From: Kevin Lee Date: Tue, 17 Apr 2018 15:36:26 -0700 Subject: [PATCH 07/14] just use default --- reaction_components/stretchable.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reaction_components/stretchable.js b/reaction_components/stretchable.js index dd7f034..cf9ab63 100644 --- a/reaction_components/stretchable.js +++ b/reaction_components/stretchable.js @@ -9,7 +9,7 @@ AFRAME.registerComponent('stretchable', inherit(base, { usePhysics: {default: 'ifavailable'}, invert: {default: false}, physicsUpdateRate: {default: 100}, - useWorldPosition: {type: 'bool', default: false} + useWorldPosition: {default: false} }, init: function () { this.STRETCHED_STATE = 'stretched' From 369faf65e5f45ba4a379ed6a91c1e3f090ea2431 Mon Sep 17 00:00:00 2001 From: Kevin Lee Date: Mon, 23 Apr 2018 14:40:47 -0700 Subject: [PATCH 08/14] call emitCancelable so the grab-start event is properly fired on the targetEntity --- index.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 6dcb7b9..b1b6579 100644 --- a/index.js +++ b/index.js @@ -161,11 +161,16 @@ AFRAME.registerComponent('super-hands', { let carried = this.state.get(this.GRAB_EVENT) this.dispatchMouseEventAll('mousedown', this.el) this.gehClicking = new Set(this.hoverEls) + const detail = { + hand: this.el, + buttonEvent: evt + } if (!carried) { - carried = (evt.detail ? evt.detail.targetEntity : false) || this.findTarget(this.GRAB_EVENT, { - hand: this.el, - buttonEvent: evt - }) + if (evt.detail && evt.detail.targetEntity && !this.emitCancelable(evt.detail.targetEntity, this.GRAB_EVENT, detail)) { + carried = evt.detail.targetEntity + } else { + carried = this.findTarget(this.GRAB_EVENT, detail) + } if (carried) { this.state.set(this.GRAB_EVENT, carried) this._unHover(carried) From c9eb93f8ef68ed7305efb3d8bfb08af13fe0a033 Mon Sep 17 00:00:00 2001 From: joni Date: Mon, 7 May 2018 19:22:46 -0700 Subject: [PATCH 09/14] Use shared vectors and quaternions when calling getWorldPosition/Quaternion --- reaction_components/grabbable.js | 87 ++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/reaction_components/grabbable.js b/reaction_components/grabbable.js index a590d0d..e0cbf2e 100644 --- a/reaction_components/grabbable.js +++ b/reaction_components/grabbable.js @@ -38,33 +38,38 @@ AFRAME.registerComponent('grabbable', inherit(base, { this.zFactor = (this.data.invert) ? -1 : 1 this.yFactor = ((this.data.invert) ? -1 : 1) * !this.data.suppressY }, - tick: function () { - var entityPosition - if (this.grabber) { - // reflect on z-axis to point in same direction as the laser - this.targetPosition.copy(this.grabDirection) - this.targetPosition - .applyQuaternion(this.grabber.object3D.getWorldQuaternion()) - .setLength(this.grabDistance) - .add(this.grabber.object3D.getWorldPosition()) - .add(this.grabOffset) - if (this.deltaPositionIsValid) { - // relative position changes work better with nested entities - this.deltaPosition.sub(this.targetPosition) - entityPosition = this.el.getAttribute('position') - this.destPosition.x = - entityPosition.x - this.deltaPosition.x * this.xFactor - this.destPosition.y = - entityPosition.y - this.deltaPosition.y * this.yFactor - this.destPosition.z = - entityPosition.z - this.deltaPosition.z * this.zFactor - this.el.setAttribute('position', this.destPosition) - } else { - this.deltaPositionIsValid = true + tick: (function () { + var q = new THREE.Quaternion() + var v = new THREE.Vector3() + + return function(){ + var entityPosition + if (this.grabber) { + // reflect on z-axis to point in same direction as the laser + this.targetPosition.copy(this.grabDirection) + this.targetPosition + .applyQuaternion(this.grabber.object3D.getWorldQuaternion(q)) + .setLength(this.grabDistance) + .add(this.grabber.object3D.getWorldPosition(v)) + .add(this.grabOffset) + if (this.deltaPositionIsValid) { + // relative position changes work better with nested entities + this.deltaPosition.sub(this.targetPosition) + entityPosition = this.el.getAttribute('position') + this.destPosition.x = + entityPosition.x - this.deltaPosition.x * this.xFactor + this.destPosition.y = + entityPosition.y - this.deltaPosition.y * this.yFactor + this.destPosition.z = + entityPosition.z - this.deltaPosition.z * this.zFactor + this.el.setAttribute('position', this.destPosition) + } else { + this.deltaPositionIsValid = true + } + this.deltaPosition.copy(this.targetPosition) } - this.deltaPosition.copy(this.targetPosition) } - }, + })(), remove: function () { this.el.removeEventListener(this.GRAB_EVENT, this.start) this.el.removeEventListener(this.UNGRAB_EVENT, this.end) @@ -110,21 +115,25 @@ AFRAME.registerComponent('grabbable', inherit(base, { } if (evt.preventDefault) { evt.preventDefault() } }, - resetGrabber: function () { - let raycaster - if (!this.grabber) { - return false - } - raycaster = this.grabber.getAttribute('raycaster') - this.deltaPositionIsValid = false - this.grabDistance = this.el.object3D.getWorldPosition() - .distanceTo(this.grabber.object3D.getWorldPosition()) - if (raycaster) { - this.grabDirection = raycaster.direction - this.grabOffset = raycaster.origin + resetGrabber: (function () { + var objPos = new THREE.Vector3() + var grabPos = new THREE.Vector3() + return function(){ + let raycaster + if (!this.grabber) { + return false + } + raycaster = this.grabber.getAttribute('raycaster') + this.deltaPositionIsValid = false + this.grabDistance = this.el.object3D.getWorldPosition(objPos) + .distanceTo(this.grabber.object3D.getWorldPosition(grabPos)) + if (raycaster) { + this.grabDirection = raycaster.direction + this.grabOffset = raycaster.origin + } + return true } - return true - }, + })(), lostGrabber: function (evt) { let i = this.grabbers.indexOf(evt.relatedTarget) // if a queued, non-physics grabber leaves the collision zone, forget it From df3c05538cc0be2d1cf715ef845b5a6b8b43d6d7 Mon Sep 17 00:00:00 2001 From: Kevin Lee Date: Wed, 18 Jul 2018 18:04:13 -0700 Subject: [PATCH 10/14] activatable reaction component provides bindings for secondary activations while an object is being grabbed. configurable to allow specifying a specific button event, to allow you to have multiple activatable components on an object (this may not be the best way to do this) --- index.js | 58 ++++++++++++++++++++++++++++++ reaction_components/activatable.js | 35 ++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 reaction_components/activatable.js diff --git a/index.js b/index.js index e14068d..f377913 100644 --- a/index.js +++ b/index.js @@ -12,6 +12,7 @@ require('./reaction_components/drag-droppable.js') require('./reaction_components/draggable.js') require('./reaction_components/droppable.js') require('./reaction_components/clickable.js') +require('./reaction_components/activatable.js') /** * Super Hands component for A-Frame. @@ -58,6 +59,18 @@ AFRAME.registerComponent('super-hands', { 'pointdown', 'thumbdown', 'pointingend', 'pistolend', 'thumbstickup', 'mouseup', 'touchend'] }, + activateStartButtons: { + default: ['gripdown', 'trackpaddown', 'triggerdown', 'gripclose', + 'abuttondown', 'bbuttondown', 'xbuttondown', 'ybuttondown', + 'pointup', 'thumbup', 'pointingstart', 'pistolstart', + 'thumbstickdown', 'mousedown', 'touchstart'] + }, + activateEndButtons: { + default: ['gripup', 'trackpadup', 'triggerup', 'gripopen', + 'abuttonup', 'bbuttonup', 'xbuttonup', 'ybuttonup', + 'pointdown', 'thumbdown', 'pointingend', 'pistolend', + 'thumbstickup', 'mouseup', 'touchend'] + }, interval: { default: 0 } }, @@ -106,6 +119,8 @@ AFRAME.registerComponent('super-hands', { this.onStretchEndButton = this.onStretchEndButton.bind(this) this.onDragDropStartButton = this.onDragDropStartButton.bind(this) this.onDragDropEndButton = this.onDragDropEndButton.bind(this) + this.onActivateStartButton = this.onActivateStartButton.bind(this) + this.onActivateEndButton = this.onActivateEndButton.bind(this) this.system.registerMe(this) }, @@ -281,6 +296,37 @@ AFRAME.registerComponent('super-hands', { } } }, + onActivateStartButton: function (evt) { + const carried = this.state.get(this.GRAB_EVENT) + if (carried) { + const activatable = carried.getAttribute('activatable') + const activateEvent = activatable.activateEvent + const validButton = activatable.buttonStartEvent == '' || activatable.buttonStartEvent == evt.type; + let activated = this.state.get(activateEvent) + if (validButton && !activated && !this.emitCancelable(carried, activateEvent, {hand: this.el, buttonEvent: evt})) { + activated = this.state.get(activateEvent) + } + if (activated) { + this.state.set(activateEvent, activated) + } + } + }, + onActivateEndButton: function (evt) { + const carried = this.state.get(this.GRAB_EVENT) + if (carried) { + const activatable = carried.getAttribute('activatable') + const activateEvent = activatable.activateEvent + const unactivateEvent = activatable.unactivateEvent + const validButton = activatable.buttonEndEvent == '' || activatable.buttonEndEvent == evt.type; + let unactivated = this.state.get(unactivateEvent) + if (validButton && !unactivated && !this.emitCancelable(carried, unactivateEvent, {hand: this.el, buttonEvent: evt})) { + unactivated = this.state.get(unactivateEvent) + } + if (unactivated) { + this.state.delete(activateEvent, unactivated) + } + } + }, processHitEl: function (hitEl, intersection) { const dist = intersection && intersection.distance const sects = this.hoverElsIntersections @@ -434,6 +480,9 @@ AFRAME.registerComponent('super-hands', { this.data.dragDropStartButtons.forEach(b => { this.el.addEventListener(b, this.onDragDropStartButton) }) + this.data.activateStartButtons.forEach(b => { + this.el.addEventListener(b, this.onActivateStartButton) + }) this.data.dragDropEndButtons.forEach(b => { this.el.addEventListener(b, this.onDragDropEndButton) }) @@ -443,6 +492,9 @@ AFRAME.registerComponent('super-hands', { this.data.grabEndButtons.forEach(b => { this.el.addEventListener(b, this.onGrabEndButton) }) + this.data.activateEndButtons.forEach(b => { + this.el.addEventListener(b, this.onActivateEndButton) + }) }, unRegisterListeners: function (data) { data = data || this.data @@ -463,6 +515,9 @@ AFRAME.registerComponent('super-hands', { data.stretchStartButtons.forEach(b => { this.el.removeEventListener(b, this.onStretchStartButton) }) + data.activateStartButtons.forEach(b => { + this.el.removeEventListener(b, this.onActivateStartButton) + }) data.stretchEndButtons.forEach(b => { this.el.removeEventListener(b, this.onStretchEndButton) }) @@ -472,6 +527,9 @@ AFRAME.registerComponent('super-hands', { data.dragDropEndButtons.forEach(b => { this.el.removeEventListener(b, this.onDragDropEndButton) }) + data.activateEndButtons.forEach(b => { + this.el.removeEventListener(b, this.onActivateEndButton) + }) }, emitCancelable: function (target, name, detail) { var data, evt diff --git a/reaction_components/activatable.js b/reaction_components/activatable.js new file mode 100644 index 0000000..4cdbdfd --- /dev/null +++ b/reaction_components/activatable.js @@ -0,0 +1,35 @@ +/* global AFRAME */ +const inherit = AFRAME.utils.extendDeep +const buttonCore = require('./prototypes/buttons-proto.js') + +AFRAME.registerComponent('activatable', inherit({}, buttonCore, { + multiple: true, + schema: { + buttonStartEvent: {default: ''}, + buttonEndEvent: {default: ''}, + activatedState: {default: 'activated'}, + activateEvent: {default: 'activate-start'}, + unactivateEvent: {default: 'activate-end'} + }, + init: function () { + this.activateStart = this.activateStart.bind(this) + this.activateEnd = this.activateEnd.bind(this) + + this.el.addEventListener(this.data.activateEvent, this.activateStart) + this.el.addEventListener(this.data.unactivateEvent, this.activateEnd) + }, + remove: function () { + this.el.removeEventListener(this.data.activateEvent, this.activateStart) + this.el.removeEventListener(this.data.unactivateEvent, this.activateEnd) + }, + activateStart: function (evt) { + if (evt.defaultPrevented || !this.startButtonOk(evt)) { return } + this.el.addState(this.data.activatedState) + if (evt.preventDefault) { evt.preventDefault() } + }, + activateEnd: function (evt) { + if (evt.defaultPrevented || !this.endButtonOk(evt)) { return } + this.el.removeState(this.data.activatedState) + if (evt.preventDefault) { evt.preventDefault() } + } +})) From 667560b0eda9a37a6759e76de0b040d2d5cc9e1c Mon Sep 17 00:00:00 2001 From: Kevin Lee Date: Wed, 18 Jul 2018 18:11:51 -0700 Subject: [PATCH 11/14] add property maxGrabBehavior to specify the behavior to follow when maxGrabbers is reached. Default is what it does now, which is nothing. Also added 'drop' which ends the grab with the the first hand currently grabbing so that the new hand can grab. --- reaction_components/grabbable.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/reaction_components/grabbable.js b/reaction_components/grabbable.js index 157ba3a..270429d 100644 --- a/reaction_components/grabbable.js +++ b/reaction_components/grabbable.js @@ -7,6 +7,7 @@ const base = inherit({}, physicsCore, buttonsCore) AFRAME.registerComponent('grabbable', inherit(base, { schema: { maxGrabbers: {type: 'int', default: NaN}, + maxGrabBehavior: {default: 'nothing', oneOf: ['nothing', 'drop']}, invert: {default: false}, suppressY: {default: false} }, @@ -74,9 +75,13 @@ AFRAME.registerComponent('grabbable', inherit(base, { return } // room for more grabbers? - const grabAvailable = !Number.isFinite(this.data.maxGrabbers) || + let grabAvailable = !Number.isFinite(this.data.maxGrabbers) || this.grabbers.length < this.data.maxGrabbers - + if (Number.isFinite(this.data.maxGrabbers) && !grabAvailable && + this.grabbed && this.data.maxGrabBehavior == 'drop') { + this.grabbers[0].components['super-hands'].onGrabEndButton() + grabAvailable = true + } if (this.grabbers.indexOf(evt.detail.hand) === -1 && grabAvailable) { if (!evt.detail.hand.object3D) { console.warn('grabbable entities must have an object3D') From 2b8c3414888962a5b9c25eb4c6590e5d5f7a9257 Mon Sep 17 00:00:00 2001 From: Kevin Lee Date: Wed, 18 Jul 2018 18:25:04 -0700 Subject: [PATCH 12/14] lint fixes --- reaction_components/grabbable.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reaction_components/grabbable.js b/reaction_components/grabbable.js index 270429d..4f5bbfb 100644 --- a/reaction_components/grabbable.js +++ b/reaction_components/grabbable.js @@ -77,8 +77,8 @@ AFRAME.registerComponent('grabbable', inherit(base, { // room for more grabbers? let grabAvailable = !Number.isFinite(this.data.maxGrabbers) || this.grabbers.length < this.data.maxGrabbers - if (Number.isFinite(this.data.maxGrabbers) && !grabAvailable && - this.grabbed && this.data.maxGrabBehavior == 'drop') { + if (Number.isFinite(this.data.maxGrabbers) && !grabAvailable && + this.grabbed && this.data.maxGrabBehavior === 'drop') { this.grabbers[0].components['super-hands'].onGrabEndButton() grabAvailable = true } From 04aa99a80d73a4846ebdfd1194ce5a2601a9ceaa Mon Sep 17 00:00:00 2001 From: Kevin Lee Date: Thu, 19 Jul 2018 18:49:48 -0700 Subject: [PATCH 13/14] getting multiple to work correctly. --- index.js | 51 ++++++++++++++++++------------ reaction_components/activatable.js | 1 + 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/index.js b/index.js index f377913..522ecb1 100644 --- a/index.js +++ b/index.js @@ -299,32 +299,41 @@ AFRAME.registerComponent('super-hands', { onActivateStartButton: function (evt) { const carried = this.state.get(this.GRAB_EVENT) if (carried) { - const activatable = carried.getAttribute('activatable') - const activateEvent = activatable.activateEvent - const validButton = activatable.buttonStartEvent == '' || activatable.buttonStartEvent == evt.type; - let activated = this.state.get(activateEvent) - if (validButton && !activated && !this.emitCancelable(carried, activateEvent, {hand: this.el, buttonEvent: evt})) { - activated = this.state.get(activateEvent) - } - if (activated) { - this.state.set(activateEvent, activated) - } + for (let key in carried.components) { + if (carried.components.hasOwnProperty(key) && carried.components[key].data.componentType === 'activatable') { + let activatable = carried.getAttribute(key) + let activateEvent = activatable.activateEvent + let validButton = activatable.buttonStartEvent == '' || activatable.buttonStartEvent == evt.type + let activated = this.state.get(activateEvent) + if (validButton && !activated && !this.emitCancelable(carried, activateEvent, {hand: this.el, buttonEvent: evt})) { + activated = this.state.get(activateEvent) + } + if (activated) { + this.state.set(activateEvent, activated) + } + } + } } }, onActivateEndButton: function (evt) { const carried = this.state.get(this.GRAB_EVENT) if (carried) { - const activatable = carried.getAttribute('activatable') - const activateEvent = activatable.activateEvent - const unactivateEvent = activatable.unactivateEvent - const validButton = activatable.buttonEndEvent == '' || activatable.buttonEndEvent == evt.type; - let unactivated = this.state.get(unactivateEvent) - if (validButton && !unactivated && !this.emitCancelable(carried, unactivateEvent, {hand: this.el, buttonEvent: evt})) { - unactivated = this.state.get(unactivateEvent) - } - if (unactivated) { - this.state.delete(activateEvent, unactivated) - } + + for (let key in carried.components) { + if (carried.components.hasOwnProperty(key) && carried.components[key].data.componentType === 'activatable') { + let activatable = carried.getAttribute(key) + let activateEvent = activatable.activateEvent + let unactivateEvent = activatable.unactivateEvent + let validButton = activatable.buttonEndEvent == '' || activatable.buttonEndEvent == evt.type + let unactivated = this.state.get(unactivateEvent) + if (validButton && !unactivated && !this.emitCancelable(carried, unactivateEvent, {hand: this.el, buttonEvent: evt})) { + unactivated = this.state.get(unactivateEvent) + } + if (unactivated) { + this.state.delete(activateEvent, unactivated) + } + } + } } }, processHitEl: function (hitEl, intersection) { diff --git a/reaction_components/activatable.js b/reaction_components/activatable.js index 4cdbdfd..3dbcb04 100644 --- a/reaction_components/activatable.js +++ b/reaction_components/activatable.js @@ -5,6 +5,7 @@ const buttonCore = require('./prototypes/buttons-proto.js') AFRAME.registerComponent('activatable', inherit({}, buttonCore, { multiple: true, schema: { + componentType: {default: 'activatable'}, buttonStartEvent: {default: ''}, buttonEndEvent: {default: ''}, activatedState: {default: 'activated'}, From e979d1cb683f7f3b8175be8a15679aa42cb548f3 Mon Sep 17 00:00:00 2001 From: Kevin Lee Date: Fri, 20 Jul 2018 16:16:02 -0700 Subject: [PATCH 14/14] fixed and simplified the activatable component. --- index.js | 46 +++++++++++------------------- reaction_components/activatable.js | 18 ++++++------ 2 files changed, 26 insertions(+), 38 deletions(-) diff --git a/index.js b/index.js index 522ecb1..3c58c91 100644 --- a/index.js +++ b/index.js @@ -95,6 +95,8 @@ AFRAME.registerComponent('super-hands', { this.DRAGOVER_EVENT = 'dragover-start' this.UNDRAGOVER_EVENT = 'dragover-end' this.DRAGDROP_EVENT = 'drag-drop' + this.ACTIVATE_EVENT = 'activate-start' + this.DEACTIVATE_EVENT = 'activate-end' // links to other systems/components this.otherSuperHand = null @@ -298,42 +300,26 @@ AFRAME.registerComponent('super-hands', { }, onActivateStartButton: function (evt) { const carried = this.state.get(this.GRAB_EVENT) + let activated = this.state.get(this.ACTIVATE_EVENT) if (carried) { - for (let key in carried.components) { - if (carried.components.hasOwnProperty(key) && carried.components[key].data.componentType === 'activatable') { - let activatable = carried.getAttribute(key) - let activateEvent = activatable.activateEvent - let validButton = activatable.buttonStartEvent == '' || activatable.buttonStartEvent == evt.type - let activated = this.state.get(activateEvent) - if (validButton && !activated && !this.emitCancelable(carried, activateEvent, {hand: this.el, buttonEvent: evt})) { - activated = this.state.get(activateEvent) - } - if (activated) { - this.state.set(activateEvent, activated) - } - } - } + if (!activated && !this.emitCancelable(carried, this.ACTIVATE_EVENT, {hand: this.el, buttonEvent: evt})) { + activated = this.state.get(this.ACTIVATE_EVENT) + } + if (activated) { + this.state.set(this.ACTIVATE_EVENT, activated) + } } }, onActivateEndButton: function (evt) { const carried = this.state.get(this.GRAB_EVENT) + let deactivated = this.state.get(this.DEACTIVATE_EVENT) if (carried) { - - for (let key in carried.components) { - if (carried.components.hasOwnProperty(key) && carried.components[key].data.componentType === 'activatable') { - let activatable = carried.getAttribute(key) - let activateEvent = activatable.activateEvent - let unactivateEvent = activatable.unactivateEvent - let validButton = activatable.buttonEndEvent == '' || activatable.buttonEndEvent == evt.type - let unactivated = this.state.get(unactivateEvent) - if (validButton && !unactivated && !this.emitCancelable(carried, unactivateEvent, {hand: this.el, buttonEvent: evt})) { - unactivated = this.state.get(unactivateEvent) - } - if (unactivated) { - this.state.delete(activateEvent, unactivated) - } - } - } + if (!deactivated && !this.emitCancelable(carried, this.DEACTIVATE_EVENT, {hand: this.el, buttonEvent: evt})) { + deactivated = this.state.get(this.DEACTIVATE_EVENT) + } + if (deactivated) { + this.state.set(this.DEACTIVATE_EVENT, deactivated) + } } }, processHitEl: function (hitEl, intersection) { diff --git a/reaction_components/activatable.js b/reaction_components/activatable.js index 3dbcb04..f82485d 100644 --- a/reaction_components/activatable.js +++ b/reaction_components/activatable.js @@ -5,31 +5,33 @@ const buttonCore = require('./prototypes/buttons-proto.js') AFRAME.registerComponent('activatable', inherit({}, buttonCore, { multiple: true, schema: { - componentType: {default: 'activatable'}, buttonStartEvent: {default: ''}, buttonEndEvent: {default: ''}, - activatedState: {default: 'activated'}, - activateEvent: {default: 'activate-start'}, - unactivateEvent: {default: 'activate-end'} + activatedState: {default: 'activated'} }, init: function () { + this.ACTIVATE_EVENT = 'activate-start' + this.DEACTIVATE_EVENT = 'activate-end' + this.activateStart = this.activateStart.bind(this) this.activateEnd = this.activateEnd.bind(this) - this.el.addEventListener(this.data.activateEvent, this.activateStart) - this.el.addEventListener(this.data.unactivateEvent, this.activateEnd) + this.el.addEventListener(this.ACTIVATE_EVENT, this.activateStart) + this.el.addEventListener(this.DEACTIVATE_EVENT, this.activateEnd) }, remove: function () { - this.el.removeEventListener(this.data.activateEvent, this.activateStart) - this.el.removeEventListener(this.data.unactivateEvent, this.activateEnd) + this.el.removeEventListener(this.ACTIVATE_EVENT, this.activateStart) + this.el.removeEventListener(this.DEACTIVATE_EVENT, this.activateEnd) }, activateStart: function (evt) { if (evt.defaultPrevented || !this.startButtonOk(evt)) { return } + if (evt.detail.buttonEvent.type !== this.data.buttonStartEvent) { return } this.el.addState(this.data.activatedState) if (evt.preventDefault) { evt.preventDefault() } }, activateEnd: function (evt) { if (evt.defaultPrevented || !this.endButtonOk(evt)) { return } + if (evt.detail.buttonEvent.type !== this.data.buttonEndEvent) { return } this.el.removeState(this.data.activatedState) if (evt.preventDefault) { evt.preventDefault() } }