From 9049b7a176035999dc5938ce75958b218fc80d51 Mon Sep 17 00:00:00 2001 From: Leon van Kammen Date: Tue, 18 Feb 2025 14:50:47 +0100 Subject: [PATCH] various tweaks (timeline, href) --- src/3rd/js/aframe/index.js | 6 +-- src/3rd/js/aframe/xrf-hands.js | 1 + src/3rd/js/plugin/frontend/tab-to-href.js | 52 +++++++++++++++++++++++ src/3rd/js/three/xrf/href.js | 11 +++-- src/3rd/js/three/xrf/t.js | 7 +-- 5 files changed, 68 insertions(+), 9 deletions(-) create mode 100644 src/3rd/js/plugin/frontend/tab-to-href.js diff --git a/src/3rd/js/aframe/index.js b/src/3rd/js/aframe/index.js index e8e004d..879ddae 100644 --- a/src/3rd/js/aframe/index.js +++ b/src/3rd/js/aframe/index.js @@ -162,9 +162,9 @@ window.AFRAME.registerComponent('xrf', { el.setAttribute("class","ray") // expose to raycaster // respond to cursor via laser-controls (https://aframe.io/docs/1.4.0/components/laser-controls.html) - el.addEventListener("click", clickHandler ) - el.addEventListener("mouseenter", mesh.userData.XRF.href.selected(true) ) - el.addEventListener("mouseleave", mesh.userData.XRF.href.selected(false) ) + el.addEventListener("click", (e) => xrf.renderer.xr.isPresenting && clickHandler(e) ) + el.addEventListener("mouseenter", (e) => xrf.renderer.xr.isPresenting && mesh.userData.XRF.href.selected(true) ) + el.addEventListener("mouseleave", (e) => xrf.renderer.xr.isPresenting && mesh.userData.XRF.href.selected(false) ) $('a-scene').appendChild(el) } createEl(mesh) diff --git a/src/3rd/js/aframe/xrf-hands.js b/src/3rd/js/aframe/xrf-hands.js index 46c87dd..61f0c6c 100644 --- a/src/3rd/js/aframe/xrf-hands.js +++ b/src/3rd/js/aframe/xrf-hands.js @@ -37,6 +37,7 @@ AFRAME.registerSystem('xrf-hands',{ // wait for bones get initialized setTimeout( () => { let bones = handEl.components['hand-tracking-controls'].bones + if( !bones ) return // dont bother let indexFinger for( let j = 0; j < bones.length; j++){ if( bones[j].name == "index-finger-tip" ){ diff --git a/src/3rd/js/plugin/frontend/tab-to-href.js b/src/3rd/js/plugin/frontend/tab-to-href.js new file mode 100644 index 0000000..c455216 --- /dev/null +++ b/src/3rd/js/plugin/frontend/tab-to-href.js @@ -0,0 +1,52 @@ + +window.hrefCycle = (e) => { + if( !xrf || !xrf.scene || e.key != "Tab" && e.key != "Enter" ) return + console.log("ja") + + let subScene = xrf.scene.getObjectByName( xrf.frag.pos.last ) + if( !subScene ) subScene = xrf.scene + let cache = window.hrefCycle.cache = window.hrefCycle.cache || {current: -1} + let objects = [] + subScene.traverse( (n) => (n.userData.href || n.userData['aria-description']) && objects.push(n) ) + + const highlight = (n) => { + if( this.helper){ + if( this.helper.selected == n.uuid ) return // already selected + xrf.scene.remove(this.helper) + } + this.selected = n + this.helper = new THREE.BoxHelper( n, 0xFF00FF ) + this.helper.computeLineDistances() + this.helper.material.linewidth = 8 + this.helper.material.color = xrf.focusLine.material.color + this.helper.material.dashSize = xrf.focusLine.material.dashSize + this.helper.material.gapSize = xrf.focusLine.material.gapSize + this.helper.selected = n.uuid + xrf.scene.add(this.helper) + + const isAction = n.userData.href + + if( typeof notify != 'undefined'){ + notify(`${n.userData['aria-description']||''}` + (n.userData.href ? `
name: ${n.name}
href: ${n.userData['href']}` :'') ) + } + if( typeof term != 'undefined'){ + term.send(`\n\r${isAction?'press enter for option ':''}${n.userData['aria-description']||n.userData['aria-label']||n.name}`) + } + } + + if( e.key == 'Enter' && objects[cache.current]?.userData.href ){ + xrf.navigator.to( objects[cache.current].userData.href ) + } + + // increment to next + cache.current = (cache.current + 1) % objects.length + + if( e.key == 'Tab'){ + highlight( objects[cache.current] ) + } + + e.preventDefault() + return false +} + +window.addEventListener('keydown', window.hrefCycle ) diff --git a/src/3rd/js/three/xrf/href.js b/src/3rd/js/three/xrf/href.js index d8a7016..8741475 100644 --- a/src/3rd/js/three/xrf/href.js +++ b/src/3rd/js/three/xrf/href.js @@ -46,7 +46,7 @@ xrf.frag.href = function(v, opts){ let URI = xrf.URI.template( mesh.userData.href, xrf.URI.vars.__object ) xrf.Parser.parse( "href", URI, frag ) const v = frag.href - + // bubble up! mesh.traverseAncestors( (n) => n.userData && n.userData.href && n.dispatchEvent({type:e.type,data:{}}) ) @@ -68,10 +68,14 @@ xrf.frag.href = function(v, opts){ .catch( console.error ) } + let selected = mesh.userData.XRF.href.selected = (state) => () => { - if( (!mesh.material && !mesh.material.visible) && !mesh.isSRC ) return // ignore invisible nodes + if( !mesh.material || !mesh.material?.visible || mesh.isSRC ) return // ignore invisible nodes if( mesh.selected == state ) return // nothing changed + console.dir({state, mselected:mesh.selected}) + + xrf.interactive.objects.map( (o) => { let newState = o.name == mesh.name ? state : false if( o.material ){ @@ -80,7 +84,7 @@ xrf.frag.href = function(v, opts){ if( o.material.emissive ){ if( !o.material.emissive.original ) o.material.emissive.original = o.material.emissive.clone() o.material.emissive.r = o.material.emissive.g = o.material.emissive.b = - newState ? o.material.emissive.original.r + 0.5 : o.material.emissive.original.r + newState ? o.material.emissive.original.r + 0.2 : o.material.emissive.original.r } } }) @@ -141,6 +145,7 @@ xrf.addEventListener('audioInited', function(opts){ }) xrf.addEventListener('navigateLoading', (e) => { + if( !e.url || !e.url.match(/.*#.*pos=/) ) return xrf.frag.href.audio.click.stop() xrf.frag.href.audio.teleport.stop() xrf.frag.href.audio.teleport.play() diff --git a/src/3rd/js/three/xrf/t.js b/src/3rd/js/three/xrf/t.js index d060a41..54659c3 100644 --- a/src/3rd/js/three/xrf/t.js +++ b/src/3rd/js/three/xrf/t.js @@ -73,6 +73,8 @@ xrf.addEventListener('parseModel', (opts) => { mixer.loop.timeStart = t.x != undefined ? t.x : mixer.loop.timeStart mixer.loop.timeStop = t.y != undefined ? t.y : mixer.loop.timeStop } + const singleShotEnded = mixer.loop.timeStop != 'undefined' &&mixer.time == mixer.loop.timeStop && !mixer.loop.enabled + if( singleShotEnded ) return // do nothing mixer.actions.map( (action) => { if( mixer.loop.timeStart != undefined ){ action.time = mixer.loop.timeStart @@ -92,15 +94,14 @@ xrf.addEventListener('parseModel', (opts) => { let update = mixer.update mixer.update = function(time){ + if( mixer.time == 0 || time == 0 ) return update.call(this,time) mixer.time = Math.abs(mixer.time) - if( time == 0 ) return update.call(this,time) // loop jump - if( mixer.loop.timeStop > 0 && mixer.time > mixer.loop.timeStop ){ + if( mixer.loop.timeStop > 0 && mixer.time != mixer.loop.timeStop && mixer.time >= mixer.loop.timeStop-0.02 ){ if( mixer.loop.enabled ){ setTimeout( () => mixer.updateLoop(), 0 ) // prevent recursion }else{ mixer.setTime( mixer.time = mixer.loop.timeStop ) - //mixer.update(mixer.time ) mixer.timeScale = 0 } }