${me.data.foo}
${me.data.myvalue}
+
${me.data.foo} ${me.data.myvalue}
`,
css: (me) => `.helloworld-window div.pad { padding:11px; }`
@@ -26,41 +29,53 @@ AFRAME.registerComponent('helloworld-window', {
click: function(e){ }, //
keydown: function(e){ }, //
- // reactive events for this.data updates
- myvalue: function(e){ this.el.dom.querySelector('b').innerText = this.data.myvalue },
+ // reactive events for this.data updates (data2event.js)
+ myvalue: function(e){ this.el.dom.querySelector('b').innerText = this.data.myvalue },
+ foo: function(e){ this.el.dom.querySelector('span').innerText = this.data.foo },
launcher: async function(){
- let s = await AFRAME.utils.require({
- dom: "./com/dom.js", // interpret .dom object
- html: "https://unpkg.com/aframe-htmlmesh@2.1.0/build/aframe-html.js", // html to AFRAME
- winboxjs: "https://unpkg.com/winbox@0.2.82/dist/winbox.bundle.min.js", // deadsimple windows: https://nextapps-de.github.io/winbox
- winboxcss: "https://unpkg.com/winbox@0.2.82/dist/css/winbox.min.css", //
- })
- console.dir(s)
- this.el.setAttribute("dom","")
- this.el.setAttribute("data2event","")
- this.el.setAttribute("html","")
- this.el.dom.style.display = 'none'
- this.data.myvalue = 1
- return
- setInterval( () => this.data.myvalue++, 100 )
- new WinBox("Hello World",{
- width: 250,
- height: 150,
- x:"center",
- y:"center",
- id: this.el.uid, // important hint for html-mesh
- root: document.querySelector("#overlay"),
- mount: this.el.dom,
- onclose: () => { this.el.dom.style.display = 'none'; return false; }
- });
- this.el.dom.style.display = ''
+ let s = await AFRAME.utils.require(this.requires)
+
+ // instance this component
+ const instance = this.el.cloneNode(false)
+ this.el.sceneEl.appendChild( instance )
+ instance.setAttribute("dom", "")
+ instance.setAttribute("visible", AFRAME.utils.XD() == '3D' ? 'true' : 'false' )
+ instance.setAttribute("position", AFRAME.utils.XD.getPositionInFrontOfCamera(1.39) )
+ instance.object3D.quaternion.copy( AFRAME.scenes[0].camera.quaternion ) // face towards camera
+
+ const setupWindow = () => {
+ const com = instance.components['helloworld-window']
+ instance.dom.style.display = 'none'
+
+ new WinBox("Hello World",{
+ width: 250,
+ height: 150,
+ x:"center",
+ y:"center",
+ id: instance.uid, // important hint for html-mesh
+ root: document.querySelector("#overlay"),
+ mount: instance.dom,
+ onclose: () => { instance.dom.style.display = 'none'; return false; },
+ oncreate: () => instance.setAttribute("html",`html:#${instance.uid}; cursor:#cursor`)
+ });
+ instance.dom.style.display = '' // show
+
+ // data2event demo
+ instance.setAttribute("data2event","")
+ com.data.myvalue = 1
+ com.data.foo = `instance ${instance.uid}: `
+ setInterval( () => com.data.myvalue++, 200 )
+ }
+
+ setTimeout( () => setupWindow(), 10 ) // give new components time to init
+
},
},
manifest: { // HTML5 manifest to identify app to xrsh
- "short_name": "Hello world window",
+ "short_name": "window",
"name": "Hello world window",
"icons": [
{
diff --git a/com/launcher.js b/com/launcher.js
index 3db743d..ca012a3 100644
--- a/com/launcher.js
+++ b/com/launcher.js
@@ -49,6 +49,7 @@ AFRAME.registerComponent('launcher', {
})
this.el.setAttribute("dom","")
+ this.el.setAttribute("noxd","ignore") // hint to XD.js that we manage ourselve concerning 2D/3D switching
this.render()
if( this.data.attach ){
@@ -81,7 +82,7 @@ AFRAME.registerComponent('launcher', {
overflow:hidden;
position: fixed;
right: 162px;
- bottom: 0px;
+ bottom: 10px;
left:20px;
background: transparent;
padding-bottom: 54px;
@@ -345,13 +346,14 @@ AFRAME.registerSystem('launcher',{
getLaunchables: function(mutationsList,observer){
let searchEvent = 'launcher'
let els = [...this.sceneEl.getElementsByTagName("*")]
+ let seen = {}
this.components = els.filter( (el) => {
let hasEvent = false
if( el.components ){
for( let i in el.components ){
- if( el.components[i].events && el.components[i].events[searchEvent] ){
- hasEvent = true
+ if( el.components[i].events && el.components[i].events[searchEvent] && !seen[i] ){
+ hasEvent = seen[i] = true
}
}
}
diff --git a/com/paste.js b/com/paste.js
index 4e8a053..ddb308b 100644
--- a/com/paste.js
+++ b/com/paste.js
@@ -108,7 +108,7 @@ AFRAME.registerComponent('paste', {
return osbutton
},
- getPositionInFrontOfCamera: function(){
+ getPositionInFrontOfCamera: function(distance){
const camera = this.el.sceneEl.camera;
let pos = new THREE.Vector3()
let direction = new THREE.Vector3();
@@ -117,7 +117,8 @@ AFRAME.registerComponent('paste', {
camera.getWorldPosition(pos)
direction.normalize();
// Scale the direction by 1 meter
- direction.multiplyScalar(1.5);
+ if( !distance ) distance = 1.5
+ direction.multiplyScalar(distance);
// Add the camera's position to the scaled direction to get the target point
pos.add(direction);
return pos
diff --git a/com/require.js b/com/require.js
index fd90741..36ac00d 100644
--- a/com/require.js
+++ b/com/require.js
@@ -25,8 +25,11 @@ AFRAME.utils.require = function(arr_or_obj,opts){
packagesArr.map( (package) => {
try{
package = package.match(/\./) ? package : AFRAME.utils.require.baseURL+package+".js"
- let id = Object.keys(arr_or_obj)[i]
- if( id == i ) id = parseURI(package).component
+ let id = Object.keys(arr_or_obj)[i++]
+ if( id.match(/^[0-9]/) ){ // if AFRAME component.dependency -array was passed
+ id = parseURI(package).component
+ }
+
// prevent duplicate requests
if( AFRAME.required[id] ) return // already loaded before
AFRAME.required[id] = true
@@ -55,9 +58,9 @@ AFRAME.utils.require = function(arr_or_obj,opts){
}
}catch(e){
console.error(`package ${package} could not be retrieved..aborting :(`);
+ console.dir(e)
if( opts.halt ) throw e;
}
- i++
})
return Promise.all(deps)
}
diff --git a/app/spatialize.js b/com/xd.js
similarity index 56%
rename from app/spatialize.js
rename to com/xd.js
index badad40..4f86df0 100644
--- a/app/spatialize.js
+++ b/com/xd.js
@@ -1,12 +1,16 @@
-AFRAME.registerComponent('spatialize', {
+AFRAME.registerComponent('xd', {
schema: {
foo: { type:"string"}
},
init: function () {
+ if( Object.keys(this.el.components).length > 1 ) return // we collect a-entities which wish to be toggled in this.showElements()
+
+ this.el.sceneEl.addEventListener('enter-vr',() => this.toggle(true) )
+ this.el.sceneEl.addEventListener('exit-vr', () => this.toggle(false) )
+ this.el.sceneEl.addEventListener('2D', () => this.showElements(false) )
+ this.el.sceneEl.addEventListener('3D', () => this.showElements(true) )
- document.querySelector('a-scene').addEventListener('enter-vr',() => this.toggle(true) )
- document.querySelector('a-scene').addEventListener('exit-vr', () => this.toggle(false) )
// toggle immersive with ESCAPE
document.body.addEventListener('keydown', (e) => e.key == 'Escape' && this.toggle() )
@@ -21,43 +25,25 @@ AFRAME.registerComponent('spatialize', {
}
`
- this.el.sceneEl.addEventListener('launched',(e) => {
- console.dir(e)
- let appEl = e.detail.el.dom
- if( appEl && appEl.style && appEl.style.display != 'none' && appEl.innerHTML ){
- this.btn.style.display = '' // show button
- }
- })
+ this.events.launcher = () => this.toggle()
},
- requires:{
- // somecomponent: "https://unpkg.com/some-aframe-component/mycom.min.js"
- },
-
- events:{
-
- // component events
- ready: function(e){
- //this.btn.style.display = 'none'
- this.btn.style.background = 'var(--xrsh-primary)'
- this.btn.style.color = '#FFF'
- },
-
- launcher: function(e){ this.toggle() },
-
+ showElements: function(state){
+ let els = [...document.querySelectorAll('[xd]')]
+ els = els.filter( (el) => el != this.el ? el : null ) // filter out self
+ els.map( (el) => el.setAttribute("visible", state ? "true" : false ) )
},
// draw a button so we can toggle apps between 2D / XR
toggle: function(state){
state = state || !document.body.className.match(/XR/)
document.body.classList[ state ? 'add' : 'remove'](['XR'])
- AFRAME.scenes[0].emit( state ? 'apps:XR' : 'apps:2D')
- this.btn.innerHTML = state ? "
2D" : "2D"
+ AFRAME.scenes[0].emit( state ? '3D' : '2D')
},
manifest: { // HTML5 manifest to identify app to xrsh
- "short_name": "2D",
- "name": "spatialize",
+ "short_name": "XD",
+ "name": "2D/3D switcher",
"icons": [],
"id": "/?source=pwa",
"start_url": "/?source=pwa",
@@ -103,3 +89,23 @@ in above's case "\nHelloworld application\n" will qualify as header.
});
+AFRAME.utils.XD = function(){
+ return document.body.classList.contains('XR') ? '3D' : '2D'
+}
+
+
+AFRAME.utils.XD.getPositionInFrontOfCamera = function(distance){
+ const camera = AFRAME.scenes[0].camera;
+ let pos = new THREE.Vector3()
+ let direction = new THREE.Vector3();
+ // Get camera's forward direction (without rotation)
+ camera.getWorldDirection(direction);
+ camera.getWorldPosition(pos)
+ direction.normalize();
+ // Scale the direction by 1 meter
+ if( !distance ) distance = 1.5
+ direction.multiplyScalar(distance);
+ // Add the camera's position to the scaled direction to get the target point
+ pos.add(direction);
+ return pos
+}