Skip to content

Instantly share code, notes, and snippets.

@richplastow
Last active September 18, 2018 03:09
Show Gist options
  • Save richplastow/30172223a074110eadf2ca752b48a040 to your computer and use it in GitHub Desktop.
Save richplastow/30172223a074110eadf2ca752b48a040 to your computer and use it in GitHub Desktop.
Vue plus A-Frame tests
<!DOCTYPE html>
<html lang="en-GB">
<head>
<!-- Technical meta -->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Search engine meta -->
<title>Vue plus A-Frame test 1</title>
<script src="//unpkg.com/vue"></script>
<script src="//unpkg.com/aframe"></script>
<script src="//stemkoski.github.io/Three.js/js/polyhedra.js"></script>
<script>
AFRAME.registerComponent('ui-event', {
init: function () {
var el = this.el // <a-entity>
var listener = function (evt) {
window.dispatchEvent(
new CustomEvent('ui-event', { detail: { el:el, type:evt.type } })
)
}
el.addEventListener('mouseenter', listener)
el.addEventListener('mouseleave', listener)
}
})
AFRAME.registerGeometry('example', {
schema: {
vertices: {
default: ['-10 10 0', '-10 -10 0', '10 -10 0'],
}
},
init: function (data) {
var geometry = new THREE.Geometry();
geometry.vertices = data.vertices.map(function (vertex) {
var points = vertex.split(' ').map(function(x){return parseInt(x);});
return new THREE.Vector3(points[0], points[1], points[2]);
});
geometry.computeBoundingBox();
geometry.faces.push(new THREE.Face3(0, 1, 2));
geometry.mergeVertices();
geometry.computeFaceNormals();
geometry.computeVertexNormals();
this.geometry = geometry;
}
})
</script>
</head>
<body style="background:#000">
<h2 style="position:fixed; left:0.5em; z-index:999; color:#fff; font-family:sans-serif">
Vue plus A-Frame test 1:<br>
Use the arrow keys to navigate.<br>
Shapes react to white-circle rollover.
</h2>
<a-scene>
<a-sky color="#222"></a-sky>
<a-camera>
<a-cursor color="white"></a-cursor>
</a-camera>
<a-entity v-for="(poly, i) in polys">
<a-entity
v-bind:rotation="poly.arc">
<a-entity
ui-event
v-bind:id="i">
<a-entity
v-bind:geometry="poly.geometry"
v-bind:material="poly.material"
v-bind:scale ="poly.scale"
v-bind:rotation="poly.rotation"
position="0 2 -3"
></a-entity>
</a-entity>
<a-entity
position="0 1.25 -2.4"
v-bind:scale="poly.hover">
<a-entity
v-bind:text="poly.name"
></a-entity>
</a-entity>
</a-entity>
</a-entity>
</a-scene>
<script>!function () {
const colors = [
'#123456'
, '#987654'
, '#891234'
, '#678912'
, '#219876'
]
const polys = [
{
name: 'Cube'
, geometry: 'primitive: box; width: 1; height: 1; depth: 1'
}
, {
name: 'Dodecahedron'
, geometry: 'primitive: dodecahedron; radius: 0.6'
}
, {
name: 'Octahedron'
, geometry: 'primitive: octahedron; radius: 0.6'
}
, {
name: 'Tetrahedron'
, geometry: 'primitive: tetrahedron; radius: 0.6'
}
, {
name: 'Example'
, geometry: 'primitive: example; vertices: 1 1 -3, 3 1 -3, 2 2 -3'
}
]
for (let i=0, poly; poly=polys[i]; i++) {
poly.arc = `0 ${30*i} 0`
poly.rotation = '0 -15 0'
poly.hover = '0 0 0'
poly.scale = '1 1 1'
poly.scaleTarget = '1 1 1'
poly.material = `flatShading: true; color: ${colors[i]}`
poly.name = `color: white; align: center; width: 3; value: ${poly.name};`
}
Vue.config.ignoredElements = [
'a-scene', 'a-sky', 'a-camera', 'a-cursor', 'a-entity'
]
const app = new Vue({
el: 'a-scene'
, data: { polys }
})
//// Deal with UI events.
window.addEventListener('ui-event', function (evt) {
if (! evt.detail || ! evt.detail.el || null == evt.detail.el.id) return
const el = evt.detail.el
, id = +el.id
, type = evt.detail.type
, poly = app.polys[id]
if ('mouseenter' === type) {
poly.scaleTarget = '1.2 1.2 1.2'
poly.hover = '1 1 1'
}
if ('mouseleave' === type) {
poly.scaleTarget = '1 1 1'
poly.hover = '0 0 0'
}
})
//// Perform tweening and animation.
function step () {
for (let i=0, poly; poly=app.polys[i]; i++) {
//// Rotate hovered poly.
if ('1 1 1' === poly.hover) {
const rotation = poly.rotation.split(' ')
rotation[1] = ++ rotation[1] % 360
poly.rotation = rotation.join(' ')
}
//// Tween scale.
if (poly.scale !== poly.scaleTarget) {
const value = poly.scale.split(' ').map(Number)
, valueTarget = poly.scaleTarget.split(' ').map(Number)
, diff = [
Math.abs(valueTarget[0] - value[0])
, Math.abs(valueTarget[1] - value[1])
, Math.abs(valueTarget[2] - value[2])
]
if (
0.01 > diff[0]
&& 0.01 > diff[1]
&& 0.01 > diff[2]
) {
poly.scale = poly.scaleTarget
} else {
value[0] = (value[0] * 3 + valueTarget[0]) / 4
value[1] = (value[1] * 3 + valueTarget[1]) / 4
value[2] = (value[2] * 3 + valueTarget[2]) / 4
poly.scale = value.join(' ')
}
}
}
window.requestAnimationFrame(step)
}
window.requestAnimationFrame(step)
//// See view-source:https://stemkoski.github.io/Three.js/Polyhedra.html
function polyhedronDataToMesh(data)
{
var polyhedron = new THREE.Object3D();
// convert vertex data to THREE.js vectors
var vertex = []
for (var i = 0; i < data.vertex.length; i++)
vertex.push( new THREE.Vector3( data.vertex[i][0], data.vertex[i][1], data.vertex[i][2] ).multiplyScalar(100) );
var vertexGeometry = new THREE.SphereGeometry( 6, 12, 6 );
var vertexMaterial = new THREE.MeshLambertMaterial( { color: 0x222244 } );
var vertexSingleMesh = new THREE.Mesh( vertexGeometry );
var vertexAmalgam = new THREE.Geometry();
for (var i = 0; i < data.vertex.length; i++)
{
var vMesh = vertexSingleMesh.clone();
vMesh.position = vertex[i];
THREE.GeometryUtils.merge( vertexAmalgam, vMesh );
}
var vertexMesh = new THREE.Mesh( vertexAmalgam, vertexMaterial );
polyhedron.add( vertexMesh );
// convert edge data to cylinders
var edgeMaterial = new THREE.MeshLambertMaterial( {color: 0x666666} );
var edgeAmalgam = new THREE.Geometry();
for (var i = 0; i < data.edge.length; i++)
{
var index0 = data.edge[i][0];
var index1 = data.edge[i][1];
var eMesh = cylinderMesh( vertex[index0], vertex[index1], edgeMaterial );
THREE.GeometryUtils.merge( edgeAmalgam, eMesh );
}
var edgeMesh = new THREE.Mesh( edgeAmalgam, edgeMaterial );
polyhedron.add( edgeMesh );
// convert face data to a single (triangulated) geometry
var faceMaterial = new THREE.MeshBasicMaterial( { color: 0xffffff, vertexColors: THREE.FaceColors, side: THREE.FrontSide, transparent:parameters.transparent, opacity:0.8 } );
var faceColors =
{
3: new THREE.Color( 0xcc0000 ),
4: new THREE.Color( 0x00cc00 ),
5: new THREE.Color( 0x0000cc ),
6: new THREE.Color( 0xcccc00 ),
7: new THREE.Color( 0x999999 ),
8: new THREE.Color( 0x990099 ),
9: new THREE.Color( 0xff6600 ),
10: new THREE.Color( 0x6666ff )
};
var geometry = new THREE.Geometry();
geometry.vertices = vertex;
var faceIndex = 0;
for (var faceNum = 0; faceNum < data.face.length; faceNum++)
{
for (var i = 0; i < data.face[faceNum].length - 2; i++)
{
geometry.faces[faceIndex] = new THREE.Face3( data.face[faceNum][0], data.face[faceNum][i+1], data.face[faceNum][i+2] );
geometry.faces[faceIndex].color = faceColors[data.face[faceNum].length];
faceIndex++;
}
}
geometry.computeFaceNormals();
geometry.computeVertexNormals();
faces = new THREE.Mesh(geometry, faceMaterial);
faces.scale.multiplyScalar(1.01);
polyhedron.add(faces);
var interiorMaterial = new THREE.MeshBasicMaterial( { color: 0xffffff, vertexColors: THREE.FaceColors, side: THREE.BackSide } );
var interiorFaces = new THREE.Mesh(geometry, interiorMaterial);
interiorFaces.scale.multiplyScalar(0.99);
polyhedron.add( interiorFaces );
return polyhedron;
}
}()</script>
</body>
<!DOCTYPE html>
<html lang="en-GB">
<head>
<!-- Technical meta -->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Search engine meta -->
<title>Vue plus A-Frame test 2</title>
<script src="//unpkg.com/vue"></script>
<script src="//unpkg.com/aframe"></script>
<script>
AFRAME.registerComponent('ui-event', {
init: function () {
var el = this.el // <a-entity>
var listener = function (evt) {
window.dispatchEvent(
new CustomEvent('ui-event', { detail: { el:el, type:evt.type } })
)
}
el.addEventListener('mouseenter', listener)
el.addEventListener('mouseleave', listener)
el.addEventListener('mousedown' , listener)
el.addEventListener('mouseup' , listener)
}
})
//// Deal with UI events.
window.addEventListener('ui-event', function (evt) {
if (! evt.detail || ! evt.detail.el || null == evt.detail.el.id) return
const el = evt.detail.el
, id = +el.id
, type = evt.detail.type
if ('mouseenter' === type) {
window.data.color = '#'
+ (~~(Math.random()*5+5))
+ (~~(Math.random()*5+5))
+ (~~(Math.random()*2))
} else if ('mouseleave' === type) {
window.data.color = '#'
+ (~~(Math.random()*2))
+ (~~(Math.random()*5+5))
+ (~~(Math.random()*5+5))
} else if ('mousedown' === type) {
var num = ~~(Math.random()*5+5)
window.data.color = '#'
+ num
+ num
+ num
} else if ('mouseup' === type) {
window.data.color = '#'
+ (~~(Math.random()*5+5))
+ (~~(Math.random()*2))
+ (~~(Math.random()*5+5))
}
})
</script>
</head>
<body style="background:#000">
<h2 style="position:fixed; left:0.5em; z-index:999; color:#fff; font-family:sans-serif">
Vue plus A-Frame test 2:<br>
Mouse-drag to look around.<br>
Shape reacts to white-circle rollover AND ALSO mouse-cursor rollover.<br>
Also, mouse-down/up-anywhere when the white-circle is over the shape, <br>
<em>AND</em> directly mouse-down/up on the shape.
</h2>
<a-scene cursor="rayOrigin: mouse">
<a-sky color="#222"></a-sky>
<a-camera position="0 -1 2">
<a-cursor color="white"></a-cursor>
</a-camera>
<a-box ui-event v-bind:color="color"></a-box>
</a-scene>
<script>!function () {
Vue.config.ignoredElements = [
'a-scene', 'a-sky', 'a-camera', 'a-cursor', 'a-box'
]
Vue.component('my-thing', {
template: '<div>A custom component!</div>'
})
window.data = { color: 'blue' }
const app = new Vue({
el: 'a-box'
, data: window.data
})
}()</script>
</body>
<!DOCTYPE html>
<html lang="en-GB">
<head>
<!-- Technical meta -->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Search engine meta -->
<title>Vue plus A-Frame test 3</title>
<script src="//unpkg.com/vue"></script>
<script src="//unpkg.com/aframe"></script>
<script src="//unpkg.com/aframe-html-shader@0.2.0/dist/aframe-html-shader.min.js"></script>
<script>
AFRAME.registerComponent('ui-event', {
init: function () {
var el = this.el // <a-entity>
var listener = function (evt) {
window.dispatchEvent(
new CustomEvent('ui-event', { detail: { el:el, type:evt.type } })
)
}
el.addEventListener('mouseenter', listener)
el.addEventListener('mouseleave', listener)
}
})
AFRAME.registerGeometry('example', {
schema: {
vertices: {
default: ['-10 10 0', '-10 -10 0', '10 -10 0'],
}
},
init: function (data) {
var geometry = new THREE.Geometry();
geometry.vertices = data.vertices.map(function (vertex) {
var points = vertex.split(' ').map(function(x){return parseInt(x);});
return new THREE.Vector3(points[0], points[1], points[2]);
});
geometry.computeBoundingBox();
geometry.faces.push(new THREE.Face3(0, 1, 2));
geometry.mergeVertices();
geometry.computeFaceNormals();
geometry.computeVertexNormals();
this.geometry = geometry;
}
})
</script>
</head>
<body style="background:#000">
<h2 style="position:fixed; left:410px; z-index:999; color:#fff; font-family:sans-serif">
Vue plus A-Frame test 3:<br>
Clicking the buttons makes Vue change the 2D square.<br>
The ‘aframe-html-shader’ component converts the 2D square to a 3D material.<br><br>
<button
style="font-size:1em;"
onclick="window.data.color='#'+(~~(Math.random()*10))+(~~(Math.random()*10))+(~~(Math.random()*10))">
Random Color</button><br><br>
<button
style="font-size:1em;"
onclick="window.data.text=String.fromCharCode(
~~(Math.random()*26+65),~~(Math.random()*26+65),~~(Math.random()*26+65)
)">Random Text</button>
</h2>
<div
style="width:400px; height:400px; position:fixed; left:0; top:0;
z-index:50; overflow:hidden; text-align:center;">
<div id="htmlElement"
v-bind:style="'background:'+color+'; color:#fff; height:400px; font-size:72px'">
<br>{{ text }}
</div>
</div>
<a-scene>
<a-sky color="#222"></a-sky>
<a-camera position="0 -1 2"></a-camera>
<a-entity laser-controls line="color: red; opacity: 0.75"></a-entity>
<a-entity geometry="primitive:box" material="shader:html; target:#htmlElement; fps:60"></a-entity>
</a-scene>
<script>!function () {
Vue.config.ignoredElements = [
'a-scene', 'a-sky', 'a-camera', 'a-cursor', 'a-entity'
]
Vue.component('my-thing', {
template: '<div>A custom component!</div>'
})
window.data = {
color: '#890'
, text: 'Ready'
}
const app = new Vue({
el: '#htmlElement'
, data: window.data
})
}()</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment