class MENU{
constructor(){
let dom = document.getElementById('injected-block')
if(dom){
dom.remove()
}
dom = document.createElement('div')
dom.classList.add('menu-block')
dom.setAttribute('id', 'injected-block')
document.body.appendChild(dom)
let objectList = document.createElement('div')
objectList.classList.add('menu-object-list')
dom.appendChild(objectList)
let objectOptions = document.createElement('div')
objectOptions.classList.add('menu-object-options')
dom.appendChild(objectOptions)
let menuMain = document.createElement('div')
menuMain.classList.add('menu-main-options')
dom.appendChild(menuMain)
this._dom = dom
this._objectList = objectList
this._objectOptions = objectOptions
this._menuMain = menuMain
this._objects = []
}
mapper(item){
console.log('MAPPING', item)
let mappedOut = document.createElement('div')
mappedOut.classList.add('group')
let map = item.map
for(var k in map){
if(map[k]['type']=="group"){
this.grouper(map[k], item, mappedOut)
}else{
if(typeof map[k] === 'object' && map[k] !== null) {
this.itemizer(map[k], item, mappedOut)
}
}
}
return mappedOut
}
grouper(map, item, group){
console.log('FOUND GROUP!', map)
}
itemizer(map, item, group){
console.log('FOUND ITEM!', map)
let target = item.target
if(map.chain){
console.log('Following Chain', map.chain)
console.log('target was:', target)
let chain = map.chain.split(',')
for(let i=0; i<chain.length; i++){
target = target[chain[i]]
}
console.log('target is Now:', target)
}
let domObj = document.createElement('div')
if(map.name && map.name != ''){
let title = document.createElement('div')
title.classList.add('item-title')
title.innerHTML = map.name
domObj.appendChild(title)
}
switch(map.type){
case 'vector3' :
domObj.appendChild(new MENU.ITEMS.VECTOR3(map, item.target))
break
case 'number' :
domObj.appendChild(new MENU.ITEMS.NUMBER(map, item.target))
break
case 'bool' :
domObj.appendChild(new MENU.ITEMS.BOOL(map, item.target))
break
}
domObj.classList.add('item')
group.appendChild(domObj)
}
addObject(target, map){
let object = new MENU.OBJECT(target, map, this)
console.log(object)
}
addPane(target, map){
let pane = new MENU.PANE(target, map, this)
console.log(pane)
}
get dom(){
return this._dom
}
set dom(v){
this._dom = v
}
get objectList(){
return this._objectList
}
set objectList(v){
this._objectList = v
}
get objectOptions(){
return this._objectOptions
}
set objectOptions(v){
this._objectOptions = v
}
get menuMain(){
return this._menuMain
}
set menuMain(v){
this._menuMain = v
}
}
MENU.OBJECT = class{
constructor(target, map, parent){
this._map = map
this._target = target
this._parent = parent
let domObj = document.createElement('a')
domObj.setAttribute('href', '#')
domObj.classList.add('object')
domObj.innerHTML = target.name+':'+target.id
var self = this
domObj.addEventListener('click', (e)=>{
let mapped = parent.mapper(self)
while (parent.objectOptions.firstChild) {
parent.objectOptions.removeChild(parent.objectOptions.firstChild)
}
let title = document.createElement('div')
title.innerHTML = target.name+':'+target.id
title.classList.add('object-title')
parent.objectOptions.appendChild(title)
parent.objectOptions.appendChild(mapped)
})
parent.objectList.appendChild(domObj)
return this
}
get map(){
return this._map
}
get target(){
return this._target
}
get parent(){
return this._parent
}
}
MENU.PANE = class{
constructor(target, map, parent){
this._map = map
this._target = target
this._parent = parent
let mapped = parent.mapper(this)
mapped.classList.add('pane')
parent.menuMain.appendChild(mapped)
return this
}
get map(){
return this._map
}
get target(){
return this._target
}
get parent(){
return this._parent
}
}
MENU.ITEMS = {}
const cloneMap = (map)=>{
let t = {}
for (let prop in map) {
if (map.hasOwnProperty(prop)) {
t[prop] = map[prop]
}
}
return t
}
MENU.ITEMS.VECTOR3 = class{
constructor(map, target){
let group = document.createElement('div')
group.classList.add('vector3')
let tx = cloneMap(map), ty = cloneMap(map), tz = cloneMap(map)
tx.name = 'x'
group.appendChild( new MENU.ITEMS.NUMBER(tx, target[map.name]))
ty.name = 'y'
group.appendChild( new MENU.ITEMS.NUMBER(ty, target[map.name]))
tz.name = 'z'
group.appendChild( new MENU.ITEMS.NUMBER(tz, target[map.name]))
return group
}
}
MENU.ITEMS.NUMBER = class{
constructor(map, target){
console.log('Making Number Input:', map, target)
let input = document.createElement('input')
input.setAttribute('type', 'number')
if(map.values){
if(map.values.min){
input.setAttribute('min', map.values.min)
}
if(map.values.max){
input.setAttribute('max', map.values.max)
}
if(map.values.step){
input.setAttribute('step', map.values.step)
}
}
input.setAttribute('value', target[map['name']])
let update = ()=>{
target[map['name']] = parseFloat(input.value)
}
input.addEventListener('change', update)
input.addEventListener('input', update)
input.addEventListener('wheel', update)
return input
}
}
MENU.ITEMS.BOOL = class{
constructor(map, target){
console.log('Making Bool Input:', map, target)
let input = document.createElement('input')
input.setAttribute('type', 'checkbox')
input.checked = target[map['name']]
let update = ()=>{
target[map['name']] = input.checked
}
input.addEventListener('change', update)
return input
}
}
MENU.MAPS = {
'mesh' : {
type: 'group',
position : { name:"position", type:"vector3", values:{step:0.5} },
rotation : { name:"rotation", type:"vector3", values:{step:0.1 } },
scaling : { name:"scaling", type:"vector3", values:{step:0.1 } }
}
}
.menu-block{
position: absolute;
z-index: 1;
width: auto;
height: auto;
background: rgba(180,180,180, 0.8);
top: 1em;
right: 0.8em;
}
.menu-object-list{
position: relative;
min-height: 1em;
width: 320px;
padding: 0.12em;
margin: 0.2em;
border:1px solid rgba(0,0,0,0.5);
background: rgba(255,255,255, 0.5);
}
.menu-object-options{
position: relative;
padding: 0.12em;
margin: 0.2em;
border:1px solid rgba(255,255,255,0.5);
background: rgba(0,0,0, 0.5);
}
.menu-main-options{
position: relative;
background: rgba(180,180,180, 0.2);
border:1px solid rgba(255,255,255,0.5);
min-height: 1em;
padding: 0.12em;
margin: 0.2em;
}
.menu-object-list .object{
text-decoration: none;
width: 100%;
display: inline-block;
border: 1px solid rgba(0,0,0,0.2);
padding: 0.1em;
cursor:pointer;
}
.menu-object-list .object:hover, .menu-object-list .object:active{
text-decoration: none;
width: 100%;
display: inline-block;
border: 1px solid rgba(255,255,255,0.2);
background-color:rgba(0,0,0,0.2);
}
.menu-block input[type=number] {
display: block;
width:100%;
}
.vector3{
width: 320px;
}
.vector3 input{
width: 32% !important;
display: inline-block !important;
}
Usage:
var menu = new MENU()
var box = BABYLON.Mesh.CreateBox("box", 1, scene)
menu.addObject(cloudBox, MENU.MAPS['mesh'])
let options = {
op1: 0,
something: BABYLON.Vector3.Zero(),
something2: false
}
menu.addPane(options , {
type:'group',
name:'Options',
op1: { name:"Option1", type:"number", values:{ min: 0, step:0.1 } },
something: { name:"something1", type:"vector3", values:{step:0.1 } },
something2 : { name:"something2", type:"bool" },
})
If you need an explanation let me know.