diff --git a/index.js b/index.js index e14068d..3ecc14f 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 } }, @@ -82,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 @@ -106,6 +121,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 +298,18 @@ AFRAME.registerComponent('super-hands', { } } }, + onActivateStartButton: function (evt) { + const target = this.state.get(this.GRAB_EVENT) || this.state.get(this.HOVER_EVENT) + if (target && !this.emitCancelable(target, this.ACTIVATE_EVENT, {hand: this.el, buttonEvent: evt})) { + this.state.set(this.ACTIVATE_EVENT, target) + } + }, + onActivateEndButton: function (evt) { + const target = this.state.get(this.GRAB_EVENT) || this.state.get(this.HOVER_EVENT) + if (target && !this.emitCancelable(target, this.DEACTIVATE_EVENT, {hand: this.el, buttonEvent: evt})) { + this.state.delete(this.ACTIVATE_EVENT) + } + }, processHitEl: function (hitEl, intersection) { const dist = intersection && intersection.distance const sects = this.hoverElsIntersections @@ -434,6 +463,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 +475,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 +498,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 +510,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..04a2db3 --- /dev/null +++ b/reaction_components/activatable.js @@ -0,0 +1,38 @@ +/* global AFRAME */ +const inherit = AFRAME.utils.extendDeep +const buttonCore = require('./prototypes/buttons-proto.js') + +AFRAME.registerComponent('activatable', inherit({}, buttonCore, { + multiple: true, + schema: { + buttonStartEvents: {default: []}, + buttonEndEvents: {default: []}, + 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.ACTIVATE_EVENT, this.activateStart) + this.el.addEventListener(this.DEACTIVATE_EVENT, this.activateEnd) + }, + remove: function () { + 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 (this.data.buttonStartEvents.indexOf(evt.detail.buttonEvent.type) === -1) { return } + this.el.addState(this.data.activatedState) + if (evt.preventDefault) { evt.preventDefault() } + }, + activateEnd: function (evt) { + if (evt.defaultPrevented || !this.endButtonOk(evt)) { return } + if (this.data.buttonEndEvents.indexOf(evt.detail.buttonEvent.type) === -1 || !this.el.is(this.data.activatedState)) { return } + this.el.removeState(this.data.activatedState) + if (evt.preventDefault) { evt.preventDefault() } + } +}))