aframe-babia-components
Version:
A data visualization set of components for A-Frame.
468 lines (405 loc) • 18 kB
HTML
<html>
<head>
<meta charset="utf-8" />
<title>Simple Example — Networked-Aframe in BabiaXr</title>
<meta name="description" content="Simple Example — Networked-Aframe in BabiaXr" />
<script src="https://aframe.io/releases/1.5.0/aframe.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.slim.js"></script>
<script src="./easyrtc.js"></script>
<script src="https://unpkg.com/networked-aframe@^0.8.0/dist/networked-aframe.js"></script>
<script
src="https://unpkg.com/aframe-environment-component@1.3.3/dist/aframe-environment-component.min.js"></script>
<script src="../../dist/aframe-babia-components.js"></script>
<script src="https://cdn.jsdelivr.net/gh/donmccurdy/aframe-extras@v7.2.0/dist/aframe-extras.min.js"></script>
</head>
<body>
<a-scene id="AframeScene" networked-scene="
room: room_demo;
adapter: easyrtc;
debug: true;
audio: false;
serverURL: empty_server;
">
<!-- serverURL:http://10.1.130.131:8080/; -->
<a-assets>
<!-- Dummy asset to make the scene sync (WIP)-->
<img src="https://wallpapercave.com/wp/wp2345390.jpg?dummy=8484744">
<!-- Templates -->
<!-- Box -->
<template id="box-template">
<a-box class="box"></a-box>
</template>
<!-- Box Button -->
<template id="box-button-template">
<a-plane class="box_button"></a-plane>
</template>
<!-- Box Label-->
<template id="box-label-template">
<a-text class="box_label"></a-text>
</template>
<!-- Cyls -->
<template id="cyls-template">
<a-entity class="cyls"></a-entity>
</template>
<!-- Interface -->
<template id="interface-template">
<a-entity class="interface"></a-entity>
</template>
<!-- Avatar -->
<template id="rig-template">
<a-entity class="rig"></a-entity>
</template>
<template id="camera-template">
<a-entity class="camera"></a-entity>
</template>
<template id="avatar-template">
<a-sphere class="avatar" networked-audio-source></a-sphere>
</template>
<template id="username-tag-template">
<a-text class="username-tag"></a-text>
</template>
</a-assets>
<a-entity environment="preset: yavapai; skyType: color; skyColor: #358DF8 "></a-entity>
<a-entity light="color: #95E0FF; intensity: 1; type: ambient;" visible="true"></a-entity>
<a-entity id="rig" position="0 2.5 3" networked="template:#rig-template; attachTemplateToLocal:false">
<a-entity id="camera" camera look-controls wasd-controls="fly: false"
networked="template:#camera-template;attachTemplateToLocal:false;">
<a-sphere id="avatar" color="#D3FFE4" scale="0.25 0.25 0.25"
networked="template:#avatar-template;attachTemplateToLocal:false;">
<a-text id="username-tag" networked="template:#username-tag-template; attachTemplateToLocal:false"
position="-0.5 1.5 0" width="5" color="black" value="username"></a-text>
</a-sphere>
</a-entity>
<!-- Hand Controls -->
<a-entity id="leftHand" laser-controls="hand: left"></a-entity>
<a-entity id="rightHand" laser-controls="hand: right"></a-entity>
<a-entity id="cursor" cursor="rayOrigin:mouse"></a-entity>
</a-entity>
<a-box id="box" color="#22B8F6"
networked="template:#box-template; networkId:box; persistent: true; owner: scene" position="-7 1 -5"
rotation="0 -45 0"></a-box>
<a-plane id="box_button"
networked="template:#box-button-template; networkId:box_button; persistent: true; owner: scene"
position="-7 3 -5" rotation="0 0 0" height="1" width="2" color="#F8F6F2">
<a-text id="box_label"
networked="template:#box-label-template; networkId:box_label; persistent: true; owner: scene"
value="Start" color="#0582B5" width="10" position="-0.5 0 0" rotation="0 0 0"></a-text>
</a-plane>
<a-entity id="cyls" babia-queryjson="url: ./data.json;" babia-cyls='x_axis:city; height: population; radius: size; legend: true; palette: flat;
radiusMax: 2; heightMax: 45; animation: true;' position="0 0.5 -10" scale="0.25 0.25 0.25"
networked="template:#cyls-template; networkId:cyls; persistent: true; owner: scene"></a-entity>
<a-entity id="interface" babia-ui="target: cyls"
networked="template:#interface-template; networkId:interface; persistent: true; owner: scene"
position="7 1 -5" rotation="0 -45 0" scale="0.5 0.5 0.5"></a-entity>
<a-plane id="cyls_palette_button" position="7 6 -5" rotation="0 -45 0" height="1" width="4" color="#F8F6F2">
<a-text id="cyls_palette_label" value="Change palette" color="#0582B5" width="10" position="-1.5 0 0"
rotation="0 0 0"></a-text>
</a-plane>
<a-plane id="cyls_scale_button" position="7 4 -5" rotation="0 -45 0" height="1" width="2" color="#F8F6F2">
<a-text id="cyls_scale_label" value="Resize" color="#0582B5" width="10" position="-0.75 0 0"
rotation="0 0 0"></a-text>
</a-plane>
<a-plane id="audio_button" position="-2.5 1 -5" rotation="0 45 0" height="1" width="2" color="#E44B00">
<a-text id="audio_label" value="Stop Audio" color="#0582B5" width="6" position="-0.75 0 0" rotation="0 0 0">
</a-text>
</a-plane>
</a-scene>
<script>
/* GET DOM ELEMENTS */
let scene = document.getElementById('AframeScene')
let avatar = document.getElementById('avatar')
let usernameTag = document.getElementById('username-tag')
let hand_right = document.getElementById('rightHand')
let box = document.getElementById('box')
let boxButton = document.getElementById("box_button")
let boxLabel = document.getElementById("box_label")
let cyls = document.getElementById('cyls')
let cylsScaleButton = document.getElementById('cyls_scale_button')
let cylsPaletteButton = document.getElementById('cyls_palette_button')
let interface = document.getElementById('interface')
let audioButton = document.getElementById('audio_button')
let audioLabel = document.getElementById('audio_label')
/* SET SERVER URL FROM QUERY STRING */
let serverURL = getValueFromQueryString('serverURL');
console.log("Empty server URL, networked-scene: ", scene.getAttribute('networked-scene'));
if (serverURL) {
scene.setAttribute('networked-scene', 'serverURL', serverURL);
scene.setAttribute('networked-scene', 'audio', 'true')
}
/* SET USERNAME AND AVATAR COLOR FROM QUERY STRING*/
let username = getValueFromQueryString('username');
let color = "#" + getValueFromQueryString('color');
if (username) { usernameTag.setAttribute('value', username) }
if (color != "#") { avatar.setAttribute('color', color) }
/* STORE CLIENTS AND USERNAMES */
let users = [];
// UI Event Listeners
document.addEventListener('controllerconnected', (event) => {
document.querySelector('#rig').setAttribute('position', { x: 0, y: 1.6, z: 0 })
});
boxButton.addEventListener('click', function (event) {
NAF.utils.takeOwnership(boxButton)
NAF.utils.takeOwnership(boxLabel)
NAF.utils.takeOwnership(box)
if (boxLabel.getAttribute('value') === 'Stop') {
stopBox();
} else {
moveBox();
}
});
cylsScaleButton.addEventListener('click', function (event) {
NAF.utils.takeOwnership(cyls)
changeCylsScale();
});
cylsPaletteButton.addEventListener('click', function (event) {
NAF.utils.takeOwnership(cyls)
changeCylsColor();
});
interface.addEventListener('click', function (event) {
NAF.utils.takeOwnership(cyls)
NAF.utils.takeOwnership(interface)
});
function addSayHelloEventListener(clientId) {
let sayHelloButton = document.getElementById('sayHello')
sayHelloButton.addEventListener('click', function (event) {
let username = "";
users.forEach(user => {
if (user.clientId === clientId) {
username = user.username
}
})
sendMessage(clientId, 'hello_message', `Hello, ${username}`)
scene.removeChild(sayHelloButton)
});
}
audioButton.addEventListener('click', function (event) {
if (audioLabel.getAttribute('value') === 'Stop Audio') {
stopAudio();
} else {
turnOnAudio();
}
});
// NAF Subscriptions
NAF.connection.subscribeToDataChannel('hello_message', function (senderId, dataType, data, targetId) {
console.log('senderId: ', senderId)
console.log('dataType: ', dataType)
console.log('data: ', data)
console.log('targetId: ', targetId)
showMessage(data)
})
// NAF Event Listeners
document.body.addEventListener('connected', function (event) {
console.log('connected event. clientId =', event.detail.clientId);
console.log("Filled serverURL, networked-scene: ", scene.getAttribute('networked-scene'))
});
document.body.addEventListener('clientConnected', function (event) {
let clientId = event.detail.clientId;
console.log('clientConnected event. clientId =', clientId);
let sayHelloButton = document.getElementById("sayHello")
if (sayHelloButton) {
scene.removeChild(sayHelloButton)
}
sayHelloButton = document.createElement('a-plane');
sayHelloButton.setAttribute('id', 'sayHello')
sayHelloButton.setAttribute('position', { x: -3, y: 2, z: -2 });
sayHelloButton.setAttribute('rotation', { x: 0, y: 0, z: 0 });
sayHelloButton.setAttribute('height', '1');
sayHelloButton.setAttribute('width', 3);
sayHelloButton.setAttribute('color', 'white');
let username = clientId;
users.forEach(user => {
if (user.clientId === clientId) {
username = user.username
}
})
sayHelloButton.setAttribute('text', {
'value': `${username} is now connected. Click here to say HELLO.`,
'align': 'center',
'width': 3,
'color': 'black'
});
scene.appendChild(sayHelloButton)
addSayHelloEventListener(clientId)
});
document.body.addEventListener('clientDisconnected', function (event) {
let clientId = event.detail.clientId;
console.log('clientDisconnected event. clientId =', clientId);
let sayHelloButton = document.getElementById("sayHello")
if (sayHelloButton) {
scene.removeChild(sayHelloButton)
}
users = users.filter(user => user.clientId != clientId)
console.log(users)
});
document.body.addEventListener('entityCreated', function (event) {
console.log(event.detail.el)
if (event.detail.el.getAttribute('class') === "username-tag") {
let user = {
clientId: event.detail.el.components.networked.data.owner,
username: event.detail.el.getAttribute('value')
};
users.push(user);
console.log(users);
if (document.getElementById('sayHello')) {
document.getElementById('sayHello').setAttribute('text', {
'value': `${event.detail.el.getAttribute('value')} is now connected. Click here to say HELLO.`,
});
}
};
});
// NAF senders
function sendMessage(client, dataType, data) {
NAF.connection.sendDataGuaranteed(client, dataType, data)
console.log(`message sent to ${client}`)
};
// Other methods
function getValueFromQueryString(string) {
string = string.replace(/[\[\]]/g, '\\$&');
var regex = new RegExp('[?&]' + string + '(=([^&#]*)|&|#|$)'),
results = regex.exec(window.location.href);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' '));
}
function moveBox() {
box.setAttribute('animation', { 'property': 'position', 'from': '-7 1 -5', 'to': '-2 3 -5', 'dur': '2000', 'easing': 'linear', 'loop': 'true' })
boxButton.setAttribute('color', '#E44B00')
boxLabel.setAttribute('value', 'Stop')
}
function stopBox() {
let x = box.getAttribute('position').x;
let y = box.getAttribute('position').y;
let z = box.getAttribute('position').z;
let pos = `${x} ${y} ${z}`
box.setAttribute('animation', { 'property': 'position', 'from': pos, 'to': pos, 'loop': 'false' })
boxButton.setAttribute('color', '#F8F6F2')
boxLabel.setAttribute('value', 'Start')
}
function turnOnAudio() {
NAF.connection.adapter.enableMicrophone(true)
audioButton.setAttribute('color', '#E44B00')
audioLabel.setAttribute('value', 'Stop Audio')
}
function stopAudio() {
NAF.connection.adapter.enableMicrophone(false)
audioButton.setAttribute('color', '#F8F6F2')
audioLabel.setAttribute('value', 'Turn on Audio')
}
function changeCylsScale() {
if (cyls.getAttribute('scale').x === 0.25) {
cyls.setAttribute('scale', '0.15 0.15 0.15')
} else {
cyls.setAttribute('scale', '0.25 0.25 0.25')
}
}
function changeCylsColor() {
if (cyls.getAttribute('babia-cyls').palette === 'flat') {
cyls.setAttribute('babia-cyls', 'palette', 'bussiness')
} else {
cyls.setAttribute('babia-cyls', 'palette', 'flat')
}
}
async function showMessage(data) {
let showMessage = document.createElement('a-plane');
showMessage.setAttribute('position', { x: 3, y: 2, z: -2 });
showMessage.setAttribute('rotation', { x: 0, y: 0, z: 0 });
showMessage.setAttribute('height', '1');
showMessage.setAttribute('width', 5);
showMessage.setAttribute('color', 'white');
showMessage.setAttribute('text', {
'value': data,
'align': 'center',
'width': 6,
'color': 'black'
});
scene.appendChild(showMessage)
await delay();
scene.removeChild(showMessage)
}
function delay() {
return new Promise(resolve => setTimeout(resolve, 3000));
}
</script>
<script>
// Schemas with components and attributes for syncronization
NAF.schemas.add({
template: '#box-template',
components: [
'position',
'rotation',
'color',
'animation'
]
});
NAF.schemas.add({
template: '#box-button-template',
components: [
'position',
'rotation',
'height',
'width',
'color'
]
});
NAF.schemas.add({
template: '#box-label-template',
components: [
'value',
'color',
'width',
'position',
'rotation'
]
});
NAF.schemas.add({
template: '#cyls-template',
components: [
'babia-queryjson',
'position',
'rotation',
'scale',
'babia-cyls'
]
});
NAF.schemas.add({
template: '#interface-template',
components: [
'babia-ui',
]
});
NAF.schemas.add({
template: '#rig-template',
components: [
'position',
'rotation'
]
});
NAF.schemas.add({
template: '#camera-template',
components: [
'position',
'rotation'
]
});
NAF.schemas.add({
template: '#avatar-template',
components: [
'position',
'rotation',
'color',
'scale'
]
});
NAF.schemas.add({
template: '#username-tag-template',
components: [
'value',
'color',
'width',
'position',
'rotation'
]
});
</script>
</body>
</html>