diff --git a/dist/xrfragment.aframe.js b/dist/xrfragment.aframe.js index 8f93ca7..c4a6dd6 100644 --- a/dist/xrfragment.aframe.js +++ b/dist/xrfragment.aframe.js @@ -922,6 +922,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ const _pointer = new Vector2(); const _event = { type: '', data: _pointer }; + let object = {selected:false} class InteractiveGroup extends Group { @@ -944,7 +945,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ if( nocollide.tid ) return // ratelimit _event.type = "nocollide" scope.objects.map( (c) => c.dispatchEvent(_event) ) - nocollide.tid = setTimeout( () => nocollide.tid = null, 100 ) + nocollide.tid = setTimeout( () => nocollide.tid = null, 10 ) } // Pointer Events @@ -968,15 +969,19 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ const intersection = intersects[ 0 ]; - const object = intersection.object; + object = intersection.object; const uv = intersection.uv; _event.type = event.type; _event.data.set( uv.x, 1 - uv.y ); - object.dispatchEvent( _event ); - }else nocollide() + }else{ + if( object.selected ) { + _event.type = 'mouseleave' + object.dispatchEvent(_event) + } + } } @@ -1013,7 +1018,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ const intersection = intersections[ 0 ]; - const object = intersection.object; + object = intersection.object; const uv = intersection.uv; _event.type = events[ event.type ]; @@ -1021,7 +1026,12 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ object.dispatchEvent( _event ); - }else nocollide() + }else{ + if( object.selected ) { + _event.type = 'mouseleave' + object.dispatchEvent(_event) + } + } } @@ -1435,7 +1445,7 @@ xrf.frag.href = function(v, opts){ .catch( console.error ) } - let selected = (state) => () => { + let selected = mesh.userData.XRF.href.selected = (state) => () => { if( mesh.selected == state ) return // nothing changed xrf.interactive.objects.map( (o) => { let newState = o.name == mesh.name ? state : false @@ -1456,7 +1466,7 @@ xrf.frag.href = function(v, opts){ mesh.addEventListener('click', click ) mesh.addEventListener('mousemove', selected(true) ) - mesh.addEventListener('nocollide', selected(false) ) + mesh.addEventListener('mouseleave', selected(false) ) // lazy add mesh (because we're inside a recursive traverse) setTimeout( (mesh) => { @@ -2020,6 +2030,10 @@ window.AFRAME.registerComponent('xrf', { }) aScene.emit('XRF',{}) + + // enable gaze-click on Mobile VR + aScene.setAttribute('xrf-gaze','') + }) } @@ -2139,6 +2153,66 @@ window.AFRAME.registerComponent('xrf-button', { }); } }); +// gaze click on mobile VR + +AFRAME.registerComponent('xrf-gaze',{ + schema:{ + spawn:{type:'boolean',default:false}, + }, + setGazer: function(state){ + let cam = document.querySelector("[camera]") + if( state ){ + if( cam.innerHTML.match(/cursor/) ) return; // avoid duplicate calls + cam.innerHTML = ` + ` + }else{ + cam.innerHTML = '' + } + }, + init:function(data){ + this.immersive = false; + let enabled = () => AFRAME.utils.device.isMobile() + let setVisible = () => this.el.setAttribute('visible', enabled() ) + this.setGazer(enabled()) + setVisible(); + + document.querySelector("a-scene").addEventListener('exit-vr', () => { + this.immersive = false; + setVisible() + }) + document.querySelector("a-scene").addEventListener('enter-vr', () => { + this.immersive = true; + setVisible() + if( !document.querySelector("#cursor") ) return + }) + + + let highlightMesh = (state) => (e) => { + if( !e.target.object3D ) return + let obj = e.target.object3D.children[0] + if( obj.userData && obj.userData.XRF && obj.userData.XRF.href ) + obj.userData.XRF.href.selected( state )() + } + this.el.addEventListener("mouseenter", highlightMesh(true) ) + this.el.addEventListener("mouseleave", highlightMesh(false ) ) + + //this.el.addEventListener('click',function(evt){ + // document.querySelector('a-scene').querySelector('#player').setAttribute('position',{ + // x:this.getAttribute('position').x, + // y:this.getAttribute('position').y, + // z:this.getAttribute('position').z + // }); + //}); + } +}); window.AFRAME.registerComponent('xrf-get', { schema: { name: {type: 'string'}, diff --git a/dist/xrfragment.three.js b/dist/xrfragment.three.js index 5ba8af5..ba3a382 100644 --- a/dist/xrfragment.three.js +++ b/dist/xrfragment.three.js @@ -922,6 +922,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ const _pointer = new Vector2(); const _event = { type: '', data: _pointer }; + let object = {selected:false} class InteractiveGroup extends Group { @@ -944,7 +945,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ if( nocollide.tid ) return // ratelimit _event.type = "nocollide" scope.objects.map( (c) => c.dispatchEvent(_event) ) - nocollide.tid = setTimeout( () => nocollide.tid = null, 100 ) + nocollide.tid = setTimeout( () => nocollide.tid = null, 10 ) } // Pointer Events @@ -968,15 +969,19 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ const intersection = intersects[ 0 ]; - const object = intersection.object; + object = intersection.object; const uv = intersection.uv; _event.type = event.type; _event.data.set( uv.x, 1 - uv.y ); - object.dispatchEvent( _event ); - }else nocollide() + }else{ + if( object.selected ) { + _event.type = 'mouseleave' + object.dispatchEvent(_event) + } + } } @@ -1013,7 +1018,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ const intersection = intersections[ 0 ]; - const object = intersection.object; + object = intersection.object; const uv = intersection.uv; _event.type = events[ event.type ]; @@ -1021,7 +1026,12 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ object.dispatchEvent( _event ); - }else nocollide() + }else{ + if( object.selected ) { + _event.type = 'mouseleave' + object.dispatchEvent(_event) + } + } } @@ -1435,7 +1445,7 @@ xrf.frag.href = function(v, opts){ .catch( console.error ) } - let selected = (state) => () => { + let selected = mesh.userData.XRF.href.selected = (state) => () => { if( mesh.selected == state ) return // nothing changed xrf.interactive.objects.map( (o) => { let newState = o.name == mesh.name ? state : false @@ -1456,7 +1466,7 @@ xrf.frag.href = function(v, opts){ mesh.addEventListener('click', click ) mesh.addEventListener('mousemove', selected(true) ) - mesh.addEventListener('nocollide', selected(false) ) + mesh.addEventListener('mouseleave', selected(false) ) // lazy add mesh (because we're inside a recursive traverse) setTimeout( (mesh) => { diff --git a/dist/xrfragment.three.module.js b/dist/xrfragment.three.module.js index 373b9b9..c4d9923 100644 --- a/dist/xrfragment.three.module.js +++ b/dist/xrfragment.three.module.js @@ -922,6 +922,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ const _pointer = new Vector2(); const _event = { type: '', data: _pointer }; + let object = {selected:false} class InteractiveGroup extends Group { @@ -944,7 +945,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ if( nocollide.tid ) return // ratelimit _event.type = "nocollide" scope.objects.map( (c) => c.dispatchEvent(_event) ) - nocollide.tid = setTimeout( () => nocollide.tid = null, 100 ) + nocollide.tid = setTimeout( () => nocollide.tid = null, 10 ) } // Pointer Events @@ -968,15 +969,19 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ const intersection = intersects[ 0 ]; - const object = intersection.object; + object = intersection.object; const uv = intersection.uv; _event.type = event.type; _event.data.set( uv.x, 1 - uv.y ); - object.dispatchEvent( _event ); - }else nocollide() + }else{ + if( object.selected ) { + _event.type = 'mouseleave' + object.dispatchEvent(_event) + } + } } @@ -1013,7 +1018,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ const intersection = intersections[ 0 ]; - const object = intersection.object; + object = intersection.object; const uv = intersection.uv; _event.type = events[ event.type ]; @@ -1021,7 +1026,12 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ object.dispatchEvent( _event ); - }else nocollide() + }else{ + if( object.selected ) { + _event.type = 'mouseleave' + object.dispatchEvent(_event) + } + } } @@ -1435,7 +1445,7 @@ xrf.frag.href = function(v, opts){ .catch( console.error ) } - let selected = (state) => () => { + let selected = mesh.userData.XRF.href.selected = (state) => () => { if( mesh.selected == state ) return // nothing changed xrf.interactive.objects.map( (o) => { let newState = o.name == mesh.name ? state : false @@ -1456,7 +1466,7 @@ xrf.frag.href = function(v, opts){ mesh.addEventListener('click', click ) mesh.addEventListener('mousemove', selected(true) ) - mesh.addEventListener('nocollide', selected(false) ) + mesh.addEventListener('mouseleave', selected(false) ) // lazy add mesh (because we're inside a recursive traverse) setTimeout( (mesh) => { diff --git a/example/assets/js/utils.js b/example/assets/js/utils.js index 6802058..d9e4879 100644 --- a/example/assets/js/utils.js +++ b/example/assets/js/utils.js @@ -209,7 +209,6 @@ function SnackBar(userOptions) { if (userOptions.status !== undefined) { _Options.status = userOptions.status; } - console.dir(_Options) } snackbar.Open = function() { diff --git a/src/3rd/js/aframe/index.js b/src/3rd/js/aframe/index.js index cba3063..c62566d 100644 --- a/src/3rd/js/aframe/index.js +++ b/src/3rd/js/aframe/index.js @@ -85,6 +85,10 @@ window.AFRAME.registerComponent('xrf', { }) aScene.emit('XRF',{}) + + // enable gaze-click on Mobile VR + aScene.setAttribute('xrf-gaze','') + }) } diff --git a/src/3rd/js/aframe/xrf-gaze.js b/src/3rd/js/aframe/xrf-gaze.js new file mode 100644 index 0000000..151eeb9 --- /dev/null +++ b/src/3rd/js/aframe/xrf-gaze.js @@ -0,0 +1,60 @@ +// gaze click on mobile VR + +AFRAME.registerComponent('xrf-gaze',{ + schema:{ + spawn:{type:'boolean',default:false}, + }, + setGazer: function(state){ + let cam = document.querySelector("[camera]") + if( state ){ + if( cam.innerHTML.match(/cursor/) ) return; // avoid duplicate calls + cam.innerHTML = ` + ` + }else{ + cam.innerHTML = '' + } + }, + init:function(data){ + this.immersive = false; + let enabled = () => AFRAME.utils.device.isMobile() + let setVisible = () => this.el.setAttribute('visible', enabled() ) + this.setGazer(enabled()) + setVisible(); + + document.querySelector("a-scene").addEventListener('exit-vr', () => { + this.immersive = false; + setVisible() + }) + document.querySelector("a-scene").addEventListener('enter-vr', () => { + this.immersive = true; + setVisible() + if( !document.querySelector("#cursor") ) return + }) + + + let highlightMesh = (state) => (e) => { + if( !e.target.object3D ) return + let obj = e.target.object3D.children[0] + if( obj.userData && obj.userData.XRF && obj.userData.XRF.href ) + obj.userData.XRF.href.selected( state )() + } + this.el.addEventListener("mouseenter", highlightMesh(true) ) + this.el.addEventListener("mouseleave", highlightMesh(false ) ) + + //this.el.addEventListener('click',function(evt){ + // document.querySelector('a-scene').querySelector('#player').setAttribute('position',{ + // x:this.getAttribute('position').x, + // y:this.getAttribute('position').y, + // z:this.getAttribute('position').z + // }); + //}); + } +}); diff --git a/src/3rd/js/three/InteractiveGroup.js b/src/3rd/js/three/InteractiveGroup.js index 96a46ee..23b0260 100644 --- a/src/3rd/js/three/InteractiveGroup.js +++ b/src/3rd/js/three/InteractiveGroup.js @@ -11,6 +11,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ const _pointer = new Vector2(); const _event = { type: '', data: _pointer }; + let object = {selected:false} class InteractiveGroup extends Group { @@ -33,7 +34,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ if( nocollide.tid ) return // ratelimit _event.type = "nocollide" scope.objects.map( (c) => c.dispatchEvent(_event) ) - nocollide.tid = setTimeout( () => nocollide.tid = null, 100 ) + nocollide.tid = setTimeout( () => nocollide.tid = null, 10 ) } // Pointer Events @@ -57,15 +58,19 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ const intersection = intersects[ 0 ]; - const object = intersection.object; + object = intersection.object; const uv = intersection.uv; _event.type = event.type; _event.data.set( uv.x, 1 - uv.y ); - object.dispatchEvent( _event ); - }else nocollide() + }else{ + if( object.selected ) { + _event.type = 'mouseleave' + object.dispatchEvent(_event) + } + } } @@ -102,7 +107,7 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ const intersection = intersections[ 0 ]; - const object = intersection.object; + object = intersection.object; const uv = intersection.uv; _event.type = events[ event.type ]; @@ -110,7 +115,12 @@ xrf.InteractiveGroup = function(THREE,renderer,camera){ object.dispatchEvent( _event ); - }else nocollide() + }else{ + if( object.selected ) { + _event.type = 'mouseleave' + object.dispatchEvent(_event) + } + } } diff --git a/src/3rd/js/three/xrf/href.js b/src/3rd/js/three/xrf/href.js index 770f594..a7e8f80 100644 --- a/src/3rd/js/three/xrf/href.js +++ b/src/3rd/js/three/xrf/href.js @@ -106,7 +106,7 @@ xrf.frag.href = function(v, opts){ .catch( console.error ) } - let selected = (state) => () => { + let selected = mesh.userData.XRF.href.selected = (state) => () => { if( mesh.selected == state ) return // nothing changed xrf.interactive.objects.map( (o) => { let newState = o.name == mesh.name ? state : false @@ -127,7 +127,7 @@ xrf.frag.href = function(v, opts){ mesh.addEventListener('click', click ) mesh.addEventListener('mousemove', selected(true) ) - mesh.addEventListener('nocollide', selected(false) ) + mesh.addEventListener('mouseleave', selected(false) ) // lazy add mesh (because we're inside a recursive traverse) setTimeout( (mesh) => {