ray-input
Advanced tools
Comparing version 0.1.1 to 0.1.2
{ | ||
"name": "ray-input", | ||
"version": "0.1.1", | ||
"version": "0.1.2", | ||
"description": "Cross platform VR input capabilities. For desktop, mobile, Cardboard, Daydream and Vive.", | ||
"main": "src/ray-input.js", | ||
"scripts": { | ||
"build": "browserify --standalone RayInput -vdt [ babelify --presets [ es2015 ] ] src/ray-input.js -o build/ray.js", | ||
"start": "watchify --standalone RayInput -vdt [ babelify --presets [ es2015 ] ] src/example/main.js -o build/example.js", | ||
"build": "browserify --standalone RayInput -vdt [ babelify --presets [ es2015 ] ] src/ray-input.js -o build/ray.js && uglify -s build/ray.js -o build/ray.min.js", | ||
"start": "watchify -vdt [ babelify --presets [ es2015 ] ] src/example/main.js -o build/example.js", | ||
"watch-simulator": "watchify -vdt [ babelify --presets [ es2015 ] ] src/simulator/main.js -o build/simulator.js" | ||
@@ -10,0 +10,0 @@ }, |
@@ -16,7 +16,7 @@ Ray Input: default WebVR interaction | ||
- `action`: an object is activated (eg. clicked) | ||
- `release`: an object is deactivated (eg. finger lifted) | ||
- `cancel`: something stops activation (eg. you mouse-scroll to look around) | ||
- `select`: an object is selected (eg. hovered on, looked at) | ||
- `deselect`: an object is no longer selected (eg. blurred, looked away from) | ||
- `raydown`: an object is activated (eg. clicked) | ||
- `rayup`: an object is deactivated (eg. finger lifted) | ||
- `raycancel`: something stops activation (eg. you mouse-scroll to look around) | ||
- `rayover`: an object is selected (eg. hovered on, looked at) | ||
- `rayout`: an object is no longer selected (eg. blurred, looked away from) | ||
@@ -30,7 +30,15 @@ | ||
Then, in your code, import the ES6 module (require and standalone mode should | ||
also work): | ||
Then, in your code, import the ES6 module: | ||
import RayInput from 'ray-input' | ||
You can also use require.js: | ||
require('./ray-input') | ||
Or you can use the script standalone, but you may need to use `new | ||
RayInput.default()`: | ||
<script src="build/ray.min.js"></script> | ||
## API | ||
@@ -40,3 +48,4 @@ | ||
var input = new RayInput(); | ||
// Here, camera is an instance of THREE.Camera. | ||
var input = new RayInput(camera); | ||
@@ -48,3 +57,3 @@ How to register objects that can be interacted with: | ||
// Register a callback whenever an object is acted on. | ||
input.on('action', (opt_mesh) => { | ||
input.on('raydown', (opt_mesh) => { | ||
// Called when an object was activated. If there is a selected object, | ||
@@ -55,3 +64,3 @@ // opt_mesh is that object. | ||
// Register a callback when an object is selected. | ||
input.on('select', (mesh) => { | ||
input.on('rayover', (mesh) => { | ||
// Called when an object was selected. | ||
@@ -82,1 +91,4 @@ }); | ||
- Support for left handed Daydream arm models. | ||
- Support a mode where only the closest object gets ray events. This has some | ||
implications. For example, when ray moves from background to foreground | ||
object, the background gets a `rayout`, while the foreground gets a `rayover`. |
@@ -51,7 +51,7 @@ /* | ||
rayInput.setSize(renderer.getSize()); | ||
rayInput.on('action', (opt_mesh) => { this.handleAction_(opt_mesh) }); | ||
rayInput.on('release', (opt_mesh) => { this.handleRelease_(opt_mesh) }); | ||
rayInput.on('cancel', (opt_mesh) => { this.handleCancel_(opt_mesh) }); | ||
rayInput.on('select', (mesh) => { this.setSelected_(mesh, true) }); | ||
rayInput.on('deselect', (mesh) => { this.setSelected_(mesh, false) }); | ||
rayInput.on('raydown', (opt_mesh) => { this.handleRayDown_(opt_mesh) }); | ||
rayInput.on('rayup', (opt_mesh) => { this.handleRayUp_(opt_mesh) }); | ||
rayInput.on('raycancel', (opt_mesh) => { this.handleRayCancel_(opt_mesh) }); | ||
rayInput.on('rayover', (mesh) => { this.setSelected_(mesh, true) }); | ||
rayInput.on('rayout', (mesh) => { this.setSelected_(mesh, false) }); | ||
@@ -78,3 +78,3 @@ // Add the ray input mesh to the scene. | ||
menu.children.forEach(function(menuItem) { | ||
console.log('menuItem', menuItem); | ||
//console.log('menuItem', menuItem); | ||
rayInput.add(menuItem); | ||
@@ -98,11 +98,11 @@ }); | ||
handleAction_(opt_mesh) { | ||
handleRayDown_(opt_mesh) { | ||
this.setAction_(opt_mesh, true); | ||
} | ||
handleRelease_(opt_mesh) { | ||
handleRayUp_(opt_mesh) { | ||
this.setAction_(opt_mesh, false); | ||
} | ||
handleCancel_(opt_mesh) { | ||
handleRayCancel_(opt_mesh) { | ||
this.setAction_(opt_mesh, false); | ||
@@ -112,2 +112,3 @@ } | ||
setSelected_(mesh, isSelected) { | ||
//console.log('setSelected_', isSelected); | ||
var newColor = isSelected ? HIGHLIGHT_COLOR : DEFAULT_COLOR; | ||
@@ -118,2 +119,3 @@ mesh.material.color = newColor; | ||
setAction_(opt_mesh, isActive) { | ||
//console.log('setAction_', !!opt_mesh, isActive); | ||
if (opt_mesh) { | ||
@@ -120,0 +122,0 @@ var newColor = isActive ? ACTIVE_COLOR : HIGHLIGHT_COLOR; |
@@ -50,5 +50,2 @@ /* | ||
// Listen to mouse events, set to true on first touch event. | ||
this.isTouchSupported = false; | ||
// The position of the pointer. | ||
@@ -140,6 +137,6 @@ this.pointer = new THREE.Vector2(); | ||
if (isGamepadPressed && !this.wasGamepadPressed) { | ||
this.emit('action'); | ||
this.emit('raydown'); | ||
} | ||
if (!isGamepadPressed && this.wasGamepadPressed) { | ||
this.emit('release'); | ||
this.emit('rayup'); | ||
} | ||
@@ -166,25 +163,18 @@ this.wasGamepadPressed = isGamepadPressed; | ||
onMouseDown_(e) { | ||
if(!this.isTouchSupported) { | ||
this.startDragging_(e); | ||
this.emit('action'); | ||
} | ||
this.startDragging_(e); | ||
this.emit('raydown'); | ||
} | ||
onMouseMove_(e) { | ||
if(!this.isTouchSupported) { | ||
this.updatePointer_(e); | ||
this.updateDragDistance_(); | ||
this.emit('pointermove', this.pointerNdc); | ||
} | ||
this.updatePointer_(e); | ||
this.updateDragDistance_(); | ||
this.emit('pointermove', this.pointerNdc); | ||
} | ||
onMouseUp_(e) { | ||
if(!this.isTouchSupported) { | ||
this.endDragging_(); | ||
} | ||
this.endDragging_(); | ||
} | ||
onTouchStart_(e) { | ||
this.isTouchSupported = true; | ||
this.isTouchActive = true; | ||
var t = e.touches[0]; | ||
@@ -194,5 +184,7 @@ this.startDragging_(t); | ||
this.isTouchActive = true; | ||
this.emit('pointermove', this.pointerNdc); | ||
this.emit('action'); | ||
this.emit('raydown'); | ||
// Prevent synthetic mouse event from being created. | ||
e.preventDefault(); | ||
} | ||
@@ -203,7 +195,13 @@ | ||
this.updateDragDistance_(); | ||
// Prevent synthetic mouse event from being created. | ||
e.preventDefault(); | ||
} | ||
onTouchEnd_(e) { | ||
this.endDragging_(); | ||
// Prevent synthetic mouse event from being created. | ||
e.preventDefault(); | ||
this.isTouchActive = false; | ||
this.endDragging_(); | ||
} | ||
@@ -235,5 +233,5 @@ | ||
console.log('dragDistance', this.dragDistance); | ||
//console.log('dragDistance', this.dragDistance); | ||
if (this.dragDistance > DRAG_DISTANCE_PX) { | ||
this.emit('cancel'); | ||
this.emit('raycancel'); | ||
this.isDragging = false; | ||
@@ -251,3 +249,3 @@ } | ||
if (this.dragDistance < DRAG_DISTANCE_PX) { | ||
this.emit('release'); | ||
this.emit('rayup'); | ||
} | ||
@@ -254,0 +252,0 @@ this.dragDistance = 0; |
@@ -36,8 +36,8 @@ /* | ||
this.controller.on('action', this.onAction_.bind(this)); | ||
this.controller.on('release', this.onRelease_.bind(this)); | ||
this.controller.on('cancel', this.onCancel_.bind(this)); | ||
this.controller.on('raydown', this.onRayDown_.bind(this)); | ||
this.controller.on('rayup', this.onRayUp_.bind(this)); | ||
this.controller.on('raycancel', this.onRayCancel_.bind(this)); | ||
this.controller.on('pointermove', this.onPointerMove_.bind(this)); | ||
this.renderer.on('select', (mesh) => { this.emit('select', mesh) }); | ||
this.renderer.on('deselect', (mesh) => { this.emit('deselect', mesh) }); | ||
this.renderer.on('rayover', (mesh) => { this.emit('rayover', mesh) }); | ||
this.renderer.on('rayout', (mesh) => { this.emit('rayout', mesh) }); | ||
@@ -65,3 +65,3 @@ // By default, put the pointer offscreen. | ||
let mode = this.controller.getInteractionMode() | ||
let mode = this.controller.getInteractionMode(); | ||
switch (mode) { | ||
@@ -197,8 +197,9 @@ case InteractionModes.MOUSE: | ||
onAction_(e) { | ||
console.log('onAction_'); | ||
this.fireActiveMeshEvent_('onAction'); | ||
onRayDown_(e) { | ||
//console.log('onRayDown_'); | ||
// Force the renderer to raycast. | ||
this.renderer.update(); | ||
let mesh = this.renderer.getSelectedMesh(); | ||
this.emit('action', mesh); | ||
this.emit('raydown', mesh); | ||
@@ -208,8 +209,6 @@ this.renderer.setActive(true); | ||
onRelease_(e) { | ||
console.log('onRelease_'); | ||
this.fireActiveMeshEvent_('onRelease'); | ||
onRayUp_(e) { | ||
//console.log('onRayUp_'); | ||
let mesh = this.renderer.getSelectedMesh(); | ||
this.emit('release', mesh); | ||
this.emit('rayup', mesh); | ||
@@ -219,26 +218,8 @@ this.renderer.setActive(false); | ||
onCancel_(e) { | ||
console.log('onCancel_'); | ||
onRayCancel_(e) { | ||
//console.log('onRayCancel_'); | ||
let mesh = this.renderer.getSelectedMesh(); | ||
this.emit('cancel', mesh); | ||
this.emit('raycancel', mesh); | ||
} | ||
fireActiveMeshEvent_(eventName) { | ||
let mesh = this.renderer.getSelectedMesh(); | ||
if (!mesh) { | ||
//console.info('No mesh selected.'); | ||
return; | ||
} | ||
let handlers = this.handlers[mesh.id]; | ||
if (!handlers) { | ||
//console.info('No handlers for mesh with id %s.', mesh.id); | ||
return; | ||
} | ||
if (!handlers[eventName]) { | ||
//console.info('No handler named %s for mesh.', eventName); | ||
return; | ||
} | ||
handlers[eventName](mesh); | ||
} | ||
onPointerMove_(ndc) { | ||
@@ -245,0 +226,0 @@ this.pointerNdc.copy(ndc); |
@@ -37,4 +37,4 @@ /* | ||
* Emits selection events: | ||
* select(mesh): This mesh was selected. | ||
* deselect(mesh): This mesh was unselected. | ||
* rayover(mesh): This mesh was selected. | ||
* rayout(mesh): This mesh was unselected. | ||
*/ | ||
@@ -55,5 +55,2 @@ export default class RayRenderer extends EventEmitter { | ||
// Event handlers for interactive objects (keyed on id). | ||
this.handlers = {}; | ||
// The raycaster. | ||
@@ -82,12 +79,5 @@ this.raycaster = new THREE.Raycaster(); | ||
* Register an object so that it can be interacted with. | ||
* @param {Object} handlers The event handlers to process for selection, | ||
* deselection, and activation. | ||
*/ | ||
add(object, opt_handlers) { | ||
add(object) { | ||
this.meshes[object.id] = object; | ||
// TODO(smus): Validate the handlers, making sure only valid handlers are | ||
// provided (ie. onSelect, onDeselect, onAction, etc). | ||
var handlers = opt_handlers || {}; | ||
this.handlers[object.id] = handlers; | ||
} | ||
@@ -103,10 +93,5 @@ | ||
delete this.meshes[id]; | ||
delete this.handlers[id]; | ||
} | ||
// If the object is currently selected, remove it. | ||
if (this.selected[id]) { | ||
var handlers = this.handlers[id] | ||
if (handlers.onDeselect) { | ||
handlers.onDeselect(object); | ||
} | ||
delete this.selected[object.id]; | ||
@@ -117,46 +102,32 @@ } | ||
update() { | ||
if(this.isActive){ | ||
// Do the raycasting and issue various events as needed. | ||
for (let id in this.meshes) { | ||
let mesh = this.meshes[id]; | ||
let handlers = this.handlers[id]; | ||
let intersects = this.raycaster.intersectObject(mesh, true); | ||
let isIntersected = (intersects.length > 0); | ||
let isSelected = this.selected[id]; | ||
// If it's newly selected, send onSelect. | ||
if (isIntersected && !isSelected) { | ||
this.selected[id] = true; | ||
if (handlers.onSelect) { | ||
handlers.onSelect(mesh); | ||
} | ||
this.emit('select', mesh); | ||
} | ||
// Do the raycasting and issue various events as needed. | ||
for (let id in this.meshes) { | ||
let mesh = this.meshes[id]; | ||
let intersects = this.raycaster.intersectObject(mesh, true); | ||
if (intersects.length > 1) { | ||
console.warn('Unexpected: multiple meshes intersected.'); | ||
} | ||
let isIntersected = (intersects.length > 0); | ||
let isSelected = this.selected[id]; | ||
// If it's no longer intersected, send onDeselect. | ||
if (!isIntersected && isSelected) { | ||
delete this.selected[id]; | ||
if (handlers.onDeselect) { | ||
handlers.onDeselect(mesh); | ||
} | ||
this.moveReticle_(null); | ||
this.emit('deselect', mesh); | ||
// If it's newly selected, send rayover. | ||
if (isIntersected && !isSelected) { | ||
this.selected[id] = true; | ||
if (this.isActive) { | ||
this.emit('rayover', mesh); | ||
} | ||
if (isIntersected) { | ||
this.moveReticle_(intersects); | ||
} | ||
} | ||
} else { | ||
// Ray not active, deselect selected meshes. | ||
for (let id in this.selected) { | ||
let handlers = this.handlers[id]; | ||
let mesh = this.meshes[id]; | ||
// If it's no longer intersected, send rayout. | ||
if (!isIntersected && isSelected) { | ||
delete this.selected[id]; | ||
if (handlers.onDeselect) { | ||
handlers.onDeselect(mesh); | ||
this.moveReticle_(null); | ||
if (this.isActive) { | ||
this.emit('rayout', mesh); | ||
} | ||
this.moveReticle_(null); | ||
this.emit('deselect', mesh); | ||
} | ||
if (isIntersected) { | ||
this.moveReticle_(intersects); | ||
} | ||
} | ||
@@ -246,7 +217,21 @@ } | ||
/** | ||
* Sets whether or not there is currently action. | ||
* Enables and disables the raycaster. For touch, where finger up means we | ||
* shouldn't be raycasting. | ||
*/ | ||
setActive(isActive) { | ||
// If nothing changed, do nothing. | ||
if (this.isActive == isActive) { | ||
return; | ||
} | ||
// TODO(smus): Show the ray or reticle adjust in response. | ||
this.isActive = isActive; | ||
if (!isActive) { | ||
this.moveReticle_(null); | ||
for (let id in this.selected) { | ||
let mesh = this.meshes[id]; | ||
delete this.selected[id]; | ||
this.emit('rayout', mesh); | ||
} | ||
} | ||
} | ||
@@ -253,0 +238,0 @@ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
1444216
24
16811
89
3
17