diff --git a/dist/xrfragment.aframe.js b/dist/xrfragment.aframe.js index 77ab1fb..9052723 100644 --- a/dist/xrfragment.aframe.js +++ b/dist/xrfragment.aframe.js @@ -614,7 +614,6 @@ xrfragment.InteractiveGroup = function(THREE,renderer,camera){ super(); if( !renderer || !camera ) return - const scope = this; const raycaster = new Raycaster(); @@ -740,9 +739,8 @@ xrf.init = function(opts){ xrf.Parser.debug = xrf.debug if( opts.loaders ) Object.values(opts.loaders).map( xrf.patchLoader ) - xrf.interactive = xrf.InteractiveGroup( opts.THREE, opts.renderer, opts.camera) - xrf.scene.add( xrf.interactive) xrf.patchRenderer(opts.renderer) + xrf.navigator.init() return xrf } @@ -815,8 +813,6 @@ xrf.eval.fragment = (k, opts ) => { } xrf.reset = () => { - console.log("xrf.reset()") - const disposeObject = (obj) => { if (obj.children.length > 0) obj.children.forEach((child) => disposeObject(child)); if (obj.geometry) obj.geometry.dispose(); @@ -824,20 +820,22 @@ xrf.reset = () => { if (obj.material.map) obj.material.map.dispose(); obj.material.dispose(); } + obj.parent.remove(obj) + console.log("removing "+(obj.type)) return true }; - - for ( let i in xrf.scene.children ) { - const child = xrf.scene.children[i]; - if( child.xrf ){ // dont affect user objects - disposeObject(child); - xrf.scene.remove(child); + let nodes = xrf.scene.children + for ( let i in nodes ) { + const child = nodes[i]; + if( child.isXRF ){ + disposeObject(child) // dont affect user objects } + } - // remove interactive xrf objs like href-portals - xrf.interactive.traverse( (n) => { - if( disposeObject(n) ) xrf.interactive.remove(n) - }) + xrf.scene.remove(xrf.interactive) // why is this needed (again?) + xrf.interactive = xrf.InteractiveGroup( xrf.THREE, xrf.renderer, xrf.camera) + xrf.add( xrf.interactive) + console.dir(xrf.scene) } xrf.parseUrl = (url) => { @@ -848,25 +846,30 @@ xrf.parseUrl = (url) => { const ext = file.split('.').pop() return {urlObj,dir,file,hash,ext} } + +xrf.add = (object) => { + object.isXRF = true // mark for easy deletion when replacing scene + xrf.scene.add(object) +} xrf.navigator = {} -xrf.navigator.to = (url) => { +xrf.navigator.to = (url,event) => { return new Promise( (resolve,reject) => { console.log("xrfragment: navigating to "+url) let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url) if( xrf.model && xrf.model.scene ) xrf.model.scene.visible = false - console.log("ext="+ext) const Loader = xrf.loaders[ext] if( !Loader ) throw 'xrfragment: no loader passed to xrfragment for extension .'+ext + xrf.reset() // clear xrf objects from scene // force relative path if( dir ) dir = dir[0] == '.' ? dir : `.${dir}` const loader = new Loader().setPath( dir ) loader.load( file, function(model){ - xrf.reset() - model.scene.xrf = true // leave mark for reset() - xrf.scene.add( model.scene ) + xrf.add( model.scene ) xrf.model = model - xrf.navigator.commit( file, hash ) + // if( event && event.type == "popstate" ){ + xrf.navigator.commit( file, hash ) + // } resolve(model) }) }) @@ -875,20 +878,14 @@ xrf.navigator.to = (url) => { xrf.navigator.init = () => { if( xrf.navigator.init.inited ) return window.addEventListener('popstate', function (event){ - console.log(event.target.document.location.search) - console.log(event.currentTarget.document.location.search) - console.log(document.location.search) - xrf.navigator.to( document.location.search.substr(1) + document.location.hash ) + xrf.navigator.to( document.location.search.substr(1) + document.location.hash, event) }) - let {url,urlObj,dir,file,hash,ext} = xrf.parseUrl(document.location.href) - //console.dir({file,hash}) - xrf.navigator.commit(file,document.location.hash) xrf.navigator.init.inited = true } xrf.navigator.commit = (file,hash) => { - console.log("hash="+hash) - window.history.pushState({},null, document.location.pathname + `?${file}#${hash}` ) + if( file == document.location.search.substr(1) ) return // page is in its default state + window.history.pushState({},`${file}#${hash}`, document.location.pathname + `?${file}#${hash}` ) } xrf.frag.env = function(v, opts){ let { mesh, model, camera, scene, renderer, THREE} = opts @@ -933,7 +930,6 @@ xrf.frag.href = function(v, opts){ mesh.getWorldScale(world.scale) mesh.position.copy(world.pos) mesh.scale.copy(world.scale) - console.log("HREF: "+(model.recursive ?"src-instanced":"original")) // convert texture if needed let texture = mesh.material.map @@ -1030,7 +1026,7 @@ xrf.frag.href = function(v, opts){ // lazy remove mesh (because we're inside a traverse) setTimeout( (mesh) => { xrf.interactive.add(mesh) - }, 300, mesh ) + }, 20, mesh ) } xrf.frag.pos = function(v, opts){ let { frag, mesh, model, camera, scene, renderer, THREE} = opts @@ -1094,7 +1090,7 @@ xrf.frag.src = function(v, opts){ } // Add the instance to the scene model.scene.add(sceneInstance); - },200) + },10) } } window.AFRAME.registerComponent('xrf', { @@ -1114,16 +1110,8 @@ window.AFRAME.registerComponent('xrf', { initXRFragments: function(){ - // clear all current xrf-get entities when click back button or href - let clear = () => { - console.log("CLEARING!") - let els = [...document.querySelectorAll('[xrf-get]')] - console.dir(els) - els.map( (el) => el.parentNode.remove(el) ) - console.log( document.querySelectorAll('[xrf-get]').length ) - } - window.addEventListener('popstate', clear ) - window.addEventListener('pushstate', clear ) + //window.addEventListener('popstate', clear ) + //window.addEventListener('pushstate', clear ) // enable XR fragments let aScene = document.querySelector('a-scene') @@ -1155,6 +1143,14 @@ window.AFRAME.registerComponent('xrf', { el.addEventListener("click", mesh.userData.XRF.href.exec ) $('a-scene').appendChild(el) } + + // cleanup xrf-get objects when resetting scene + XRF.reset = ((reset) => () => { + console.log("aframe reset") + let els = [...document.querySelectorAll('[xrf-get]')] + els.map( (el) => document.querySelector('a-scene').removeChild(el) ) + reset() + })(XRF.reset) }, }) @@ -1181,6 +1177,7 @@ window.AFRAME.registerComponent('xrf-get', { ////mesh.updateMatrixWorld(); this.el.object3D.position.setFromMatrixPosition(scene.matrixWorld); this.el.object3D.quaternion.setFromRotationMatrix(scene.matrixWorld); + mesh.xrf = true // mark for deletion by xrf this.el.setObject3D('mesh', mesh ); if( !this.el.id ) this.el.setAttribute("id",`xrf-${mesh.name}`) diff --git a/dist/xrfragment.three.js b/dist/xrfragment.three.js index 380328a..c9ceda2 100644 --- a/dist/xrfragment.three.js +++ b/dist/xrfragment.three.js @@ -614,7 +614,6 @@ xrfragment.InteractiveGroup = function(THREE,renderer,camera){ super(); if( !renderer || !camera ) return - const scope = this; const raycaster = new Raycaster(); @@ -740,9 +739,8 @@ xrf.init = function(opts){ xrf.Parser.debug = xrf.debug if( opts.loaders ) Object.values(opts.loaders).map( xrf.patchLoader ) - xrf.interactive = xrf.InteractiveGroup( opts.THREE, opts.renderer, opts.camera) - xrf.scene.add( xrf.interactive) xrf.patchRenderer(opts.renderer) + xrf.navigator.init() return xrf } @@ -815,8 +813,6 @@ xrf.eval.fragment = (k, opts ) => { } xrf.reset = () => { - console.log("xrf.reset()") - const disposeObject = (obj) => { if (obj.children.length > 0) obj.children.forEach((child) => disposeObject(child)); if (obj.geometry) obj.geometry.dispose(); @@ -824,20 +820,22 @@ xrf.reset = () => { if (obj.material.map) obj.material.map.dispose(); obj.material.dispose(); } + obj.parent.remove(obj) + console.log("removing "+(obj.type)) return true }; - - for ( let i in xrf.scene.children ) { - const child = xrf.scene.children[i]; - if( child.xrf ){ // dont affect user objects - disposeObject(child); - xrf.scene.remove(child); + let nodes = xrf.scene.children + for ( let i in nodes ) { + const child = nodes[i]; + if( child.isXRF ){ + disposeObject(child) // dont affect user objects } + } - // remove interactive xrf objs like href-portals - xrf.interactive.traverse( (n) => { - if( disposeObject(n) ) xrf.interactive.remove(n) - }) + xrf.scene.remove(xrf.interactive) // why is this needed (again?) + xrf.interactive = xrf.InteractiveGroup( xrf.THREE, xrf.renderer, xrf.camera) + xrf.add( xrf.interactive) + console.dir(xrf.scene) } xrf.parseUrl = (url) => { @@ -848,25 +846,30 @@ xrf.parseUrl = (url) => { const ext = file.split('.').pop() return {urlObj,dir,file,hash,ext} } + +xrf.add = (object) => { + object.isXRF = true // mark for easy deletion when replacing scene + xrf.scene.add(object) +} xrf.navigator = {} -xrf.navigator.to = (url) => { +xrf.navigator.to = (url,event) => { return new Promise( (resolve,reject) => { console.log("xrfragment: navigating to "+url) let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url) if( xrf.model && xrf.model.scene ) xrf.model.scene.visible = false - console.log("ext="+ext) const Loader = xrf.loaders[ext] if( !Loader ) throw 'xrfragment: no loader passed to xrfragment for extension .'+ext + xrf.reset() // clear xrf objects from scene // force relative path if( dir ) dir = dir[0] == '.' ? dir : `.${dir}` const loader = new Loader().setPath( dir ) loader.load( file, function(model){ - xrf.reset() - model.scene.xrf = true // leave mark for reset() - xrf.scene.add( model.scene ) + xrf.add( model.scene ) xrf.model = model - xrf.navigator.commit( file, hash ) + // if( event && event.type == "popstate" ){ + xrf.navigator.commit( file, hash ) + // } resolve(model) }) }) @@ -875,20 +878,14 @@ xrf.navigator.to = (url) => { xrf.navigator.init = () => { if( xrf.navigator.init.inited ) return window.addEventListener('popstate', function (event){ - console.log(event.target.document.location.search) - console.log(event.currentTarget.document.location.search) - console.log(document.location.search) - xrf.navigator.to( document.location.search.substr(1) + document.location.hash ) + xrf.navigator.to( document.location.search.substr(1) + document.location.hash, event) }) - let {url,urlObj,dir,file,hash,ext} = xrf.parseUrl(document.location.href) - //console.dir({file,hash}) - xrf.navigator.commit(file,document.location.hash) xrf.navigator.init.inited = true } xrf.navigator.commit = (file,hash) => { - console.log("hash="+hash) - window.history.pushState({},null, document.location.pathname + `?${file}#${hash}` ) + if( file == document.location.search.substr(1) ) return // page is in its default state + window.history.pushState({},`${file}#${hash}`, document.location.pathname + `?${file}#${hash}` ) } xrf.frag.env = function(v, opts){ let { mesh, model, camera, scene, renderer, THREE} = opts @@ -933,7 +930,6 @@ xrf.frag.href = function(v, opts){ mesh.getWorldScale(world.scale) mesh.position.copy(world.pos) mesh.scale.copy(world.scale) - console.log("HREF: "+(model.recursive ?"src-instanced":"original")) // convert texture if needed let texture = mesh.material.map @@ -1030,7 +1026,7 @@ xrf.frag.href = function(v, opts){ // lazy remove mesh (because we're inside a traverse) setTimeout( (mesh) => { xrf.interactive.add(mesh) - }, 300, mesh ) + }, 20, mesh ) } xrf.frag.pos = function(v, opts){ let { frag, mesh, model, camera, scene, renderer, THREE} = opts @@ -1094,7 +1090,7 @@ xrf.frag.src = function(v, opts){ } // Add the instance to the scene model.scene.add(sceneInstance); - },200) + },10) } } export default xrfragment; diff --git a/example/aframe/sandbox/index.html b/example/aframe/sandbox/index.html index 74879ad..7854c18 100644 --- a/example/aframe/sandbox/index.html +++ b/example/aframe/sandbox/index.html @@ -46,10 +46,18 @@ $('a-scene').addEventListener('loaded', () => { setupConsole( $('textarea') ) + let nav = window.AFRAME.XRF.navigator + nav.to = ((to) => (url,e) => { + to(url,e) + reflectUrl() + })(nav.to) + + const reflectUrl = () => $('#uri').value = document.location.search.substr(1) + document.location.hash + reflectUrl() // update url when sandbox-url is updated - window.addEventListener('hashchange', () => { - window.AFRAME.XRF.eval( $('#uri').value = document.location.hash ) - }) + //window.addEventListener('hashchange', () => { + // window.AFRAME.XRF.eval( $('#uri').value = document.location.hash ) + //}) //if( document.location.hash.length < 2 ) document.location.hash = $('#uri').value // add look-controls at last (otherwise it'll be buggy after scene-updates) diff --git a/example/threejs/sandbox/index.html b/example/threejs/sandbox/index.html index 5e1fb1f..b78d965 100644 --- a/example/threejs/sandbox/index.html +++ b/example/threejs/sandbox/index.html @@ -212,7 +212,6 @@ gui.domElement.style.visibility = 'hidden'; XRF.interactive.add( mesh ); XRF.interactive.add( statsMesh ); - scene.add( XRF.interactive ); }) let fileLoaders = loadFile({ diff --git a/src/3rd/aframe/index.js b/src/3rd/aframe/index.js index 457a423..1a2a121 100644 --- a/src/3rd/aframe/index.js +++ b/src/3rd/aframe/index.js @@ -15,16 +15,8 @@ window.AFRAME.registerComponent('xrf', { initXRFragments: function(){ - // clear all current xrf-get entities when click back button or href - let clear = () => { - console.log("CLEARING!") - let els = [...document.querySelectorAll('[xrf-get]')] - console.dir(els) - els.map( (el) => el.parentNode.remove(el) ) - console.log( document.querySelectorAll('[xrf-get]').length ) - } - window.addEventListener('popstate', clear ) - window.addEventListener('pushstate', clear ) + //window.addEventListener('popstate', clear ) + //window.addEventListener('pushstate', clear ) // enable XR fragments let aScene = document.querySelector('a-scene') @@ -56,6 +48,14 @@ window.AFRAME.registerComponent('xrf', { el.addEventListener("click", mesh.userData.XRF.href.exec ) $('a-scene').appendChild(el) } + + // cleanup xrf-get objects when resetting scene + XRF.reset = ((reset) => () => { + console.log("aframe reset") + let els = [...document.querySelectorAll('[xrf-get]')] + els.map( (el) => document.querySelector('a-scene').removeChild(el) ) + reset() + })(XRF.reset) }, }) @@ -82,6 +82,7 @@ window.AFRAME.registerComponent('xrf-get', { ////mesh.updateMatrixWorld(); this.el.object3D.position.setFromMatrixPosition(scene.matrixWorld); this.el.object3D.quaternion.setFromRotationMatrix(scene.matrixWorld); + mesh.xrf = true // mark for deletion by xrf this.el.setObject3D('mesh', mesh ); if( !this.el.id ) this.el.setAttribute("id",`xrf-${mesh.name}`) diff --git a/src/3rd/three/InteractiveGroup.js b/src/3rd/three/InteractiveGroup.js index f0ebf20..597e629 100644 --- a/src/3rd/three/InteractiveGroup.js +++ b/src/3rd/three/InteractiveGroup.js @@ -19,7 +19,6 @@ xrfragment.InteractiveGroup = function(THREE,renderer,camera){ super(); if( !renderer || !camera ) return - const scope = this; const raycaster = new Raycaster(); diff --git a/src/3rd/three/index.js b/src/3rd/three/index.js index e1916d8..a10d6fe 100644 --- a/src/3rd/three/index.js +++ b/src/3rd/three/index.js @@ -12,9 +12,8 @@ xrf.init = function(opts){ xrf.Parser.debug = xrf.debug if( opts.loaders ) Object.values(opts.loaders).map( xrf.patchLoader ) - xrf.interactive = xrf.InteractiveGroup( opts.THREE, opts.renderer, opts.camera) - xrf.scene.add( xrf.interactive) xrf.patchRenderer(opts.renderer) + xrf.navigator.init() return xrf } @@ -87,8 +86,6 @@ xrf.eval.fragment = (k, opts ) => { } xrf.reset = () => { - console.log("xrf.reset()") - const disposeObject = (obj) => { if (obj.children.length > 0) obj.children.forEach((child) => disposeObject(child)); if (obj.geometry) obj.geometry.dispose(); @@ -96,20 +93,22 @@ xrf.reset = () => { if (obj.material.map) obj.material.map.dispose(); obj.material.dispose(); } + obj.parent.remove(obj) + console.log("removing "+(obj.type)) return true }; - - for ( let i in xrf.scene.children ) { - const child = xrf.scene.children[i]; - if( child.xrf ){ // dont affect user objects - disposeObject(child); - xrf.scene.remove(child); + let nodes = xrf.scene.children + for ( let i in nodes ) { + const child = nodes[i]; + if( child.isXRF ){ + disposeObject(child) // dont affect user objects } + } - // remove interactive xrf objs like href-portals - xrf.interactive.traverse( (n) => { - if( disposeObject(n) ) xrf.interactive.remove(n) - }) + xrf.scene.remove(xrf.interactive) // why is this needed (again?) + xrf.interactive = xrf.InteractiveGroup( xrf.THREE, xrf.renderer, xrf.camera) + xrf.add( xrf.interactive) + console.dir(xrf.scene) } xrf.parseUrl = (url) => { @@ -120,3 +119,8 @@ xrf.parseUrl = (url) => { const ext = file.split('.').pop() return {urlObj,dir,file,hash,ext} } + +xrf.add = (object) => { + object.isXRF = true // mark for easy deletion when replacing scene + xrf.scene.add(object) +} diff --git a/src/3rd/three/navigator.js b/src/3rd/three/navigator.js index 719cb12..0031e13 100644 --- a/src/3rd/three/navigator.js +++ b/src/3rd/three/navigator.js @@ -1,22 +1,22 @@ xrf.navigator = {} -xrf.navigator.to = (url) => { +xrf.navigator.to = (url,event) => { return new Promise( (resolve,reject) => { console.log("xrfragment: navigating to "+url) let {urlObj,dir,file,hash,ext} = xrf.parseUrl(url) if( xrf.model && xrf.model.scene ) xrf.model.scene.visible = false - console.log("ext="+ext) const Loader = xrf.loaders[ext] if( !Loader ) throw 'xrfragment: no loader passed to xrfragment for extension .'+ext + xrf.reset() // clear xrf objects from scene // force relative path if( dir ) dir = dir[0] == '.' ? dir : `.${dir}` const loader = new Loader().setPath( dir ) loader.load( file, function(model){ - xrf.reset() - model.scene.xrf = true // leave mark for reset() - xrf.scene.add( model.scene ) + xrf.add( model.scene ) xrf.model = model - xrf.navigator.commit( file, hash ) + // if( event && event.type == "popstate" ){ + xrf.navigator.commit( file, hash ) + // } resolve(model) }) }) @@ -25,18 +25,12 @@ xrf.navigator.to = (url) => { xrf.navigator.init = () => { if( xrf.navigator.init.inited ) return window.addEventListener('popstate', function (event){ - console.log(event.target.document.location.search) - console.log(event.currentTarget.document.location.search) - console.log(document.location.search) - xrf.navigator.to( document.location.search.substr(1) + document.location.hash ) + xrf.navigator.to( document.location.search.substr(1) + document.location.hash, event) }) - let {url,urlObj,dir,file,hash,ext} = xrf.parseUrl(document.location.href) - //console.dir({file,hash}) - xrf.navigator.commit(file,document.location.hash) xrf.navigator.init.inited = true } xrf.navigator.commit = (file,hash) => { - console.log("hash="+hash) - window.history.pushState({},null, document.location.pathname + `?${file}#${hash}` ) + if( file == document.location.search.substr(1) ) return // page is in its default state + window.history.pushState({},`${file}#${hash}`, document.location.pathname + `?${file}#${hash}` ) } diff --git a/src/3rd/three/xrf/href.js b/src/3rd/three/xrf/href.js index 7558335..fbf1c8e 100644 --- a/src/3rd/three/xrf/href.js +++ b/src/3rd/three/xrf/href.js @@ -6,7 +6,6 @@ xrf.frag.href = function(v, opts){ mesh.getWorldScale(world.scale) mesh.position.copy(world.pos) mesh.scale.copy(world.scale) - console.log("HREF: "+(model.recursive ?"src-instanced":"original")) // convert texture if needed let texture = mesh.material.map @@ -103,5 +102,5 @@ xrf.frag.href = function(v, opts){ // lazy remove mesh (because we're inside a traverse) setTimeout( (mesh) => { xrf.interactive.add(mesh) - }, 300, mesh ) + }, 20, mesh ) } diff --git a/src/3rd/three/xrf/src.js b/src/3rd/three/xrf/src.js index 7e86b42..6723173 100644 --- a/src/3rd/three/xrf/src.js +++ b/src/3rd/three/xrf/src.js @@ -33,6 +33,6 @@ xrf.frag.src = function(v, opts){ } // Add the instance to the scene model.scene.add(sceneInstance); - },200) + },10) } }