wip: iconmenu is now an app too
This commit is contained in:
parent
f1254d7fed
commit
ad2fa285a0
|
@ -37,7 +37,7 @@ AFRAME.registerComponent('launcher', {
|
||||||
scale: 3,
|
scale: 3,
|
||||||
events: ['click'],
|
events: ['click'],
|
||||||
html: (me) => `<div>
|
html: (me) => `<div>
|
||||||
<div class="iconmenu"></div>
|
<div id="iconmenu"></div>
|
||||||
</div>`,
|
</div>`,
|
||||||
|
|
||||||
css: `#iconmenu {
|
css: `#iconmenu {
|
||||||
|
@ -53,6 +53,7 @@ AFRAME.registerComponent('launcher', {
|
||||||
padding-bottom: 72px;
|
padding-bottom: 72px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
visibility: visible !important;
|
||||||
}
|
}
|
||||||
#iconmenu > button {
|
#iconmenu > button {
|
||||||
pointer-events:all;
|
pointer-events:all;
|
||||||
|
@ -84,9 +85,8 @@ AFRAME.registerComponent('launcher', {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
border-radius: 0px;
|
border-radius: 0px;
|
||||||
}
|
}
|
||||||
#iconmenu > button > img:hover,
|
#iconmenu > button > img:hover{
|
||||||
#iconmenu > button.enable > img {
|
background: #AAA;
|
||||||
border:2px solid #444;
|
|
||||||
transition:0.gg3s;
|
transition:0.gg3s;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}`
|
}`
|
||||||
|
@ -110,24 +110,21 @@ AFRAME.registerComponent('launcher', {
|
||||||
clearTimeout(this.timeout)
|
clearTimeout(this.timeout)
|
||||||
this.timeout = setTimeout( () => {
|
this.timeout = setTimeout( () => {
|
||||||
AFRAME.app.foreach( (app) => {
|
AFRAME.app.foreach( (app) => {
|
||||||
console.dir(app)
|
|
||||||
if( !app.manifest ) return
|
if( !app.manifest ) return
|
||||||
|
|
||||||
console.log("--rendering button")
|
console.log(app.data.uri+" "+app.data.order)
|
||||||
return
|
|
||||||
let btn = app.btn = document.createElement('button')
|
let btn = app.btn = document.createElement('button')
|
||||||
if( app.manifest.icons?.length > 0){
|
if( app.manifest.icons?.length > 0){
|
||||||
let img = document.createElement('img')
|
let img = document.createElement('img')
|
||||||
img.src = app.manifest.icons[0].src
|
img.src = app.manifest.icons[0].src
|
||||||
img.alt = app.manifest.name
|
img.title = app.manifest.name + ": " + app.manifest.description
|
||||||
btn.appendChild(img)
|
btn.appendChild(img)
|
||||||
}else btn.innerText = app.manifest.short_name
|
}else btn.innerText = app.manifest.short_name
|
||||||
btn.addEventListener('click', () => {
|
btn.addEventListener('click', () => app.el.emit('launcher',app) )
|
||||||
app.el.emit('launcher',app)
|
|
||||||
})
|
|
||||||
this.el.dom.querySelector('#iconmenu').appendChild(btn)
|
this.el.dom.querySelector('#iconmenu').appendChild(btn)
|
||||||
})
|
})
|
||||||
},200)
|
},100)
|
||||||
},
|
},
|
||||||
|
|
||||||
manifest: { // HTML5 manifest to identify app to xrsh
|
manifest: { // HTML5 manifest to identify app to xrsh
|
||||||
|
|
|
@ -9,6 +9,17 @@ AFRAME.registerComponent('spatialize', {
|
||||||
document.querySelector('a-scene').addEventListener('exit-vr', () => this.toggle(false) )
|
document.querySelector('a-scene').addEventListener('exit-vr', () => this.toggle(false) )
|
||||||
// toggle immersive with ESCAPE
|
// toggle immersive with ESCAPE
|
||||||
document.body.addEventListener('keydown', (e) => e.key == 'Escape' && this.toggle() )
|
document.body.addEventListener('keydown', (e) => e.key == 'Escape' && this.toggle() )
|
||||||
|
|
||||||
|
document.head.innerHTML += `<style type="text/css">
|
||||||
|
.XR #toggle_overlay{
|
||||||
|
background: transparent;
|
||||||
|
color: #3aacff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.XR #overlay{
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
</style>`
|
||||||
},
|
},
|
||||||
|
|
||||||
requires:{
|
requires:{
|
||||||
|
@ -31,7 +42,8 @@ AFRAME.registerComponent('spatialize', {
|
||||||
state = state || !document.body.className.match(/XR/)
|
state = state || !document.body.className.match(/XR/)
|
||||||
document.body.classList[ state ? 'add' : 'remove'](['XR'])
|
document.body.classList[ state ? 'add' : 'remove'](['XR'])
|
||||||
AFRAME.scenes[0].emit( state ? 'apps:XR' : 'apps:2D')
|
AFRAME.scenes[0].emit( state ? 'apps:XR' : 'apps:2D')
|
||||||
this.btn.classList.toggle('enable')
|
this.btn.querySelector('img').src = state ? this.manifest.icons[0].src_2D
|
||||||
|
: this.manifest.icons[0].src
|
||||||
},
|
},
|
||||||
|
|
||||||
manifest: { // HTML5 manifest to identify app to xrsh
|
manifest: { // HTML5 manifest to identify app to xrsh
|
||||||
|
@ -39,7 +51,8 @@ AFRAME.registerComponent('spatialize', {
|
||||||
"name": "spatialize",
|
"name": "spatialize",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "https://css.gg/stack.svg",
|
"src": "https://css.gg/display-grid.svg",
|
||||||
|
"src_2D": "https://css.gg/stack.svg",
|
||||||
"type": "image/svg+xml",
|
"type": "image/svg+xml",
|
||||||
"sizes": "512x512"
|
"sizes": "512x512"
|
||||||
}
|
}
|
||||||
|
@ -66,7 +79,7 @@ AFRAME.registerComponent('spatialize', {
|
||||||
"icons": [{ "src": "/images/today.png", "sizes": "192x192" }]
|
"icons": [{ "src": "/images/today.png", "sizes": "192x192" }]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Hello world information",
|
"description": "use ESC-key to toggle between 2D / 3D",
|
||||||
"screenshots": [
|
"screenshots": [
|
||||||
{
|
{
|
||||||
"src": "/images/screenshot1.png",
|
"src": "/images/screenshot1.png",
|
||||||
|
|
130
com/app.js
130
com/app.js
|
@ -3,20 +3,37 @@
|
||||||
AFRAME.required = {}
|
AFRAME.required = {}
|
||||||
AFRAME.app = new Proxy({
|
AFRAME.app = new Proxy({
|
||||||
|
|
||||||
|
order:0,
|
||||||
|
|
||||||
add(component, entity){
|
add(component, entity){
|
||||||
|
// categorize by component to prevent similar apps loading duplicate dependencies simultaniously
|
||||||
this[component] = this[component] || []
|
this[component] = this[component] || []
|
||||||
this[component].push(entity)
|
this[component].push(entity)
|
||||||
|
entity.data.order = entity.data.order || this.count()
|
||||||
|
},
|
||||||
|
count(){
|
||||||
|
let n = 0
|
||||||
|
this.foreach( () => n++ )
|
||||||
|
return n
|
||||||
},
|
},
|
||||||
foreach(cb){
|
foreach(cb){
|
||||||
|
const isArray = (e) => e.push
|
||||||
|
let arr = []
|
||||||
for( let i in this ){
|
for( let i in this ){
|
||||||
if( typeof this[i] != 'function' ) this[i].map( (app) => cb({app,component:i}) )
|
if( isArray(this[i]) ) this[i].map( (app) => arr.push(app.el.app) )
|
||||||
}
|
}
|
||||||
|
arr.sort( (a,b) => a.data.order > b.data.order )
|
||||||
|
.map( cb )
|
||||||
}
|
}
|
||||||
},{
|
},{
|
||||||
get(me,k) { return me[k] },
|
get(me,k) { return me[k] },
|
||||||
set(me,k,v){ me[k] = v }
|
set(me,k,v){ me[k] = v }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the abstract 'app' component
|
||||||
|
*/
|
||||||
|
|
||||||
AFRAME.registerComponent('app', {
|
AFRAME.registerComponent('app', {
|
||||||
schema:{
|
schema:{
|
||||||
"uri":{ type:"string"}
|
"uri":{ type:"string"}
|
||||||
|
@ -57,7 +74,6 @@ AFRAME.registerComponent('app', {
|
||||||
type: String(uri).split(".").pop() // 'mycom.js' => 'js'
|
type: String(uri).split(".").pop() // 'mycom.js' => 'js'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// usage: require(["./app/foo.js"])
|
// usage: require(["./app/foo.js"])
|
||||||
// require({foo: "https://foo.com/foo.js"})
|
// require({foo: "https://foo.com/foo.js"})
|
||||||
require: AFRAME.AComponent.prototype.require = function(packages,readyEvent){
|
require: AFRAME.AComponent.prototype.require = function(packages,readyEvent){
|
||||||
|
@ -101,13 +117,17 @@ AFRAME.registerComponent('app', {
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// monkeypatching initComponent will trigger events when components
|
/*
|
||||||
// are initialized (that way apps can react to attached components)
|
* Here are monkeypatched AFRAME component prototype functions
|
||||||
// basically, in both situations:
|
*
|
||||||
// <a-entity foo="a:1"/>
|
* monkeypatching initComponent will trigger events when components
|
||||||
// <a-entity app="uri: myapp.js"/> <!-- myapp.js calls this.require(['foo.js']) -->
|
* are initialized (that way apps can react to attached components)
|
||||||
//
|
* basically, in both situations:
|
||||||
// event 'foo' will be triggered as both entities (in)directly require component 'foo'
|
* <a-entity foo="a:1"/>
|
||||||
|
* <a-entity app="uri: myapp.js"/> <!-- myapp.js calls this.require(['foo.js']) -->
|
||||||
|
*
|
||||||
|
* event 'foo' will be triggered as both entities (in)directly require component 'foo'
|
||||||
|
*/
|
||||||
|
|
||||||
AFRAME.AComponent.prototype.initComponent = function(initComponent){
|
AFRAME.AComponent.prototype.initComponent = function(initComponent){
|
||||||
return function(){
|
return function(){
|
||||||
|
@ -122,7 +142,7 @@ AFRAME.AComponent.prototype.updateProperties = function(updateProperties){
|
||||||
return function(){
|
return function(){
|
||||||
updateProperties.apply(this,arguments)
|
updateProperties.apply(this,arguments)
|
||||||
|
|
||||||
if( !this.data || !this.data.uri ) return // only deal with apps
|
if( !this.data || !this.data.uri || this.isApp ) return // only deal with apps (once)
|
||||||
|
|
||||||
// ensure overlay
|
// ensure overlay
|
||||||
let overlay = document.querySelector('#overlay')
|
let overlay = document.querySelector('#overlay')
|
||||||
|
@ -131,22 +151,22 @@ AFRAME.AComponent.prototype.updateProperties = function(updateProperties){
|
||||||
overlay.id = "overlay"
|
overlay.id = "overlay"
|
||||||
document.body.appendChild(overlay)
|
document.body.appendChild(overlay)
|
||||||
document.querySelector("a-scene").setAttribute("webxr","overlayElement:#overlay")
|
document.querySelector("a-scene").setAttribute("webxr","overlayElement:#overlay")
|
||||||
let menu = document.createElement('div')
|
// let menu = document.createElement('div')
|
||||||
menu.id = 'iconmenu'
|
// menu.id = 'iconmenu'
|
||||||
document.body.appendChild(menu)
|
// document.body.appendChild(menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
// add menu button
|
// // add menu button
|
||||||
if( this.manifest && this.manifest.icons ){
|
// if( this.manifest && this.manifest.icons ){
|
||||||
let btn = document.createElement('button')
|
// let btn = document.createElement('button')
|
||||||
btn.app = this
|
// btn.app = this
|
||||||
if( this.manifest.icons.length ){
|
// if( this.manifest.icons.length ){
|
||||||
btn.innerHTML = `<img src="${this.manifest.icons[0].src}"/>`
|
// btn.innerHTML = `<img src="${this.manifest.icons[0].src}"/>`
|
||||||
}else btn.innerText = this.manifest.short_name
|
// }else btn.innerText = this.manifest.short_name
|
||||||
btn.setAttribute("alt", this.manifest.name )
|
// btn.setAttribute("alt", this.manifest.name )
|
||||||
btn.addEventListener('click', (e) => this.el.emit('launcher',{}) )
|
// btn.addEventListener('click', (e) => this.el.emit('launcher',{}) )
|
||||||
document.querySelector("#iconmenu").appendChild(btn)
|
// document.querySelector("#iconmenu").appendChild(btn)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// reactify components with dom-definition
|
// reactify components with dom-definition
|
||||||
if( this.data.uri && this.dom && !this.el.dom ){
|
if( this.data.uri && this.dom && !this.el.dom ){
|
||||||
|
@ -220,9 +240,12 @@ AFRAME.AComponent.prototype.updateProperties = function(updateProperties){
|
||||||
// assign unique app id
|
// assign unique app id
|
||||||
if( !this.el.uid ) this.el.uid = '_'+String(Math.random()).substr(10)
|
if( !this.el.uid ) this.el.uid = '_'+String(Math.random()).substr(10)
|
||||||
|
|
||||||
// fetch requires
|
|
||||||
if( this.requires ) this.require( this.requires, 'requires:ready' )
|
if( this.requires ) this.require( this.requires, 'requires:ready' )
|
||||||
else this.el.emit('requires:ready')
|
else this.el.emit('requires:ready')
|
||||||
|
|
||||||
|
// mark app as being initialized
|
||||||
|
this.isApp = true
|
||||||
|
this.el.app = this
|
||||||
}
|
}
|
||||||
}( AFRAME.AComponent.prototype.updateProperties)
|
}( AFRAME.AComponent.prototype.updateProperties)
|
||||||
|
|
||||||
|
@ -249,62 +272,5 @@ document.head.innerHTML += `
|
||||||
#overlay.hide{
|
#overlay.hide{
|
||||||
z-index:-10;
|
z-index:-10;
|
||||||
}
|
}
|
||||||
|
|
||||||
#toggle_overlay{
|
|
||||||
display:none;
|
|
||||||
position: fixed;
|
|
||||||
right: 20px;
|
|
||||||
bottom: 73px;
|
|
||||||
width: 58px;
|
|
||||||
text-align: center;
|
|
||||||
height: 40px;
|
|
||||||
padding: 0;
|
|
||||||
z-index: 100;
|
|
||||||
border: 3px solid #3aacff;
|
|
||||||
border-radius:11px;
|
|
||||||
transition:0.3s;
|
|
||||||
padding: 0px;
|
|
||||||
font-weight: bold;
|
|
||||||
cursor:pointer;
|
|
||||||
font-family:sans-serif;
|
|
||||||
font-size:15px;
|
|
||||||
color: #FFF;
|
|
||||||
background: #3aacff;
|
|
||||||
transition:0.5s;
|
|
||||||
}
|
|
||||||
.XR #toggle_overlay{
|
|
||||||
background: transparent;
|
|
||||||
color: #3aacff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.XR #overlay{
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
`
|
`
|
||||||
|
|
||||||
// draw a button so we can toggle apps between 2D / XR
|
|
||||||
let toggle = (state) => {
|
|
||||||
state = state || !document.body.className.match(/XR/)
|
|
||||||
document.body.classList[ state ? 'add' : 'remove'](['XR'])
|
|
||||||
AFRAME.scenes[0].emit( state ? 'apps:XR' : 'apps:2D')
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", (event) => {
|
|
||||||
let btn = document.createElement("button")
|
|
||||||
btn.id = "toggle_overlay"
|
|
||||||
btn.innerHTML = "<i class='gg-stack'></i>"
|
|
||||||
btn.addEventListener('click', (e) => toggle() )
|
|
||||||
document.body.appendChild(btn)
|
|
||||||
|
|
||||||
document.querySelector('a-scene').addEventListener('enter-vr',() => toggle(true) )
|
|
||||||
document.querySelector('a-scene').addEventListener('exit-vr', () => toggle(false) )
|
|
||||||
document.querySelector('a-scene').addEventListener('loaded', () => {
|
|
||||||
let VRbtn = document.querySelector('a-scene .a-enter-vr')
|
|
||||||
let ARbtn = document.querySelector('a-scene .a-enter-ar')
|
|
||||||
if( VRbtn ) document.body.appendChild(VRbtn) // move to body
|
|
||||||
if( ARbtn ) document.body.appendChild(ARbtn) // so they will always be visible
|
|
||||||
})
|
|
||||||
// toggle immersive with ESCAPE
|
|
||||||
document.body.addEventListener('keydown', (e) => e.key == 'Escape' && toggle() )
|
|
||||||
})
|
|
||||||
|
|
Loading…
Reference in New Issue