aframe-babia-components
Version:
A data visualization set of components for A-Frame.
339 lines (288 loc) • 11.9 kB
JavaScript
/* global AFRAME */
if (typeof AFRAME === 'undefined') {
throw new Error('Component attempted to register before AFRAME was available.');
}
AFRAME.registerComponent('babia-slider', {
schema: {
color: { type: 'color', default: '#fff' },
size: { type: 'number', default: 0.5 },
min: { type: 'number', default: -6 },
max: { type: 'number', default: -4 },
value: { type: 'number', default: -5 },
innerSize: { type: 'number', default: 0.8 },
precision: { type: 'number', default: 2 },
vertical: {type: 'boolean', default: false},
label: {type: 'string'}
},
multiple: true,
init: function () {
this.loader = new THREE.FontLoader();
let material = new THREE.MeshBasicMaterial({color: this.data.color });
this.material = material
let lever= new THREE.Mesh(new THREE.BoxGeometry( 0.05, 0.15, 0.05 ), material);
let track = new THREE.Mesh(new THREE.CylinderGeometry(0.015,0.015, this.data.size, 12), material);
track.rotateZ(Math.PI / 2);
let chassis = new THREE.Group();
this.lever = lever;
chassis.add(track);
chassis.add(lever);
if (this.data.vertical){
chassis.rotateZ(Math.PI / 2)
}
this.el.setObject3D('mesh', chassis);
this.el.classList.add("babiaxraycasterclass");
this.controllers = Array.prototype.slice.call(document.querySelectorAll('a-entity[hand-controls]'));
this.fontURL = 'https://threejsfundamentals.org/threejs/resources/threejs/fonts/helvetiker_regular.typeface.json'
this.loader.load(this.fontURL, (font) => {
this.font = font
let minText = this.createTextGeometry(this.data.min, -this.data.size / 2 - .15, -.025)
let maxText = this.createTextGeometry(this.data.max, this.data.size / 2 + .08, -.025)
chassis.add(minText)
chassis.add(maxText)
})
},
createTextGeometry: function(text, x, y) {
let textGeometry = new THREE.TextGeometry(text.toString(), {
font: this.font,
size: .07,
height: .01,
curveSegments: 12,
bevelEnabled: false,
});
let textMesh = new THREE.Mesh(textGeometry, this.material)
textMesh.position.x = x
textMesh.position.y = y
if (this.data.vertical){
textMesh.rotation.z = - Math.PI / 2
textMesh.position.y += .05
}
return textMesh
},
setTextGeometry: function(text) {
if (this.textmesh) {
this.lever.children = []
}
this.loader.load(this.fontURL, (font) => {
this.font = font
if (!this.data.vertical){
this.textmesh = this.createTextGeometry(text, -.025, .15)
} else {
this.textmesh = this.createTextGeometry(text, -.025, -.2)
}
this.lever.add(this.textmesh)
})
},
play: function () {
this.grabbed = false;
this.el.addEventListener('rangeout', this.onTriggerUp.bind(this));
this.controllers.forEach(function (controller){
controller.addEventListener('triggerdown', this.onTriggerDown.bind(this));
controller.addEventListener('triggerup', this.onTriggerUp.bind(this));
}.bind(this));
},
pause: function () {
this.el.removeEventListener('rangeout', this.onTriggerUp.bind(this));
this.controllers.forEach(function (controller){
controller.removeEventListener('triggerdown', this.onTriggerDown.bind(this));
controller.removeEventListener('triggerup', this.onTriggerUp.bind(this));
}.bind(this));
},
onTriggerDown: function(e) {
var hand = e.target.object3D;
var lever = this.lever;
var handBB = new THREE.Box3().setFromObject(hand);
var leverBB = new THREE.Box3().setFromObject(lever);
var collision = handBB.intersectsBox(leverBB);
if (collision) {
let handWorld = new THREE.Vector3();
hand.getWorldPosition(handWorld);
let knobWorld = new THREE.Vector3();;
lever.getWorldPosition(knobWorld);
let distance = handWorld.distanceTo(knobWorld);
if (distance < 0.1) {
this.grabbed = hand;
this.grabbed.visible = false;
this.knob.material = this.knobGrabbedMaterial;
}
};
},
onTriggerUp: function() {
if (this.grabbed) {
this.grabbed.visible = true;
this.grabbed = false;
this.knob.material = this.knobMaterial;
}
},
setValue: function(value) {
var lever = this.lever;
if (value < this.data.min) {
value = this.data.min;
} else if (value > this.data.max) {
value = this.data.max;
}
this.value = value;
lever.position.x = this.valueToLeverPosition(value);
if (!this.data.label){
this.setTextGeometry(value)
} else {
this.setTextGeometry(this.data.label)
}
},
valueToLeverPosition: function(value) {
var sliderRange = this.data.size * this.data.innerSize;
var valueRange = Math.abs(this.data.max - this.data.min);
let sliderMin = -1 * sliderRange / 2;
return (((value - this.data.min) * sliderRange) / valueRange) + sliderMin
},
leverPositionToValue: function(position) {
var sliderRange = this.data.size * this.data.innerSize;
var valueRange = Math.abs(this.data.max - this.data.min);
let sliderMin = -1 * sliderRange / 2;
return (((position - sliderMin) * valueRange) / sliderRange) + this.data.min
},
tick: function() {
if (this.grabbed) {
var hand = this.grabbed;
var lever = this.lever;
var sliderSize = this.data.size;
var sliderRange = (sliderSize * this.data.innerSize);
var handWorld = new THREE.Vector3().setFromMatrixPosition(hand.matrixWorld);
lever.parent.worldToLocal(handWorld);
if (Math.abs(handWorld.x) > sliderRange / 2) {
lever.position.x = sliderRange / 2 * Math.sign(lever.position.x);
} else {
lever.position.x = handWorld.x;
}
var value = this.leverPositionToValue(lever.position.x);
if (Math.abs(this.value - value) >= Math.pow(10, -this.data.precision)) {
value = Math.round(value)
this.value = value;
this.setTextGeometry(value)
// this.el.parentEl.components['babia-navigator'].controlNavigator('babiaSetPosition', this.value)
if (this.el.parentEl.components['babia-navigator']){
this.el.parentEl.components['babia-navigator'].controlNavigator('babiaSetPosition', Math.round(value))
} else if (this.el.parentEl.components['babia-step-controller']){
this.el.parentEl.components['babia-step-controller'].controlStep(Math.round(value))
} else if (this.el.parentEl.components['babia-speed-controller']){
this.el.parentEl.components['babia-speed-controller'].controlSpeed(Math.round(value))
}
}
}
},
mousexPositionToValue: function(x){
let sliderCenter = this.el.object3D.getWorldPosition().x
let sliderWidth = this.data.size * this.data.innerSize * this.el.object3D.getWorldScale().x
let sliderRange = Math.abs(this.data.max - this.data.min)
let sliderMin = sliderCenter - (sliderWidth / 2)
let value = (((x - sliderMin) * sliderRange) / sliderWidth) + this.data.min
if (value < this.data.min){
return this.data.min
} else if (value > this.data.max){
return this.data.max
} else {
return value
}
},
mouseyPositionToValue: function(y){
let sliderCenter = this.el.object3D.getWorldPosition().y
let sliderWidth = this.data.size * this.data.innerSize * this.el.object3D.getWorldScale().y
let sliderRange = Math.abs(this.data.max - this.data.min)
let sliderMin = sliderCenter - (sliderWidth / 2)
let value = (((y - sliderMin) * sliderRange) / sliderWidth) + this.data.min
if (value < this.data.min){
return this.data.min
} else if (value > this.data.max){
return this.data.max
} else {
return value
}
},
update: function(old) {
if(this.data.value !== old.value) {
this.setValue(this.data.value);
}
this.el.addEventListener('click', _listener = (e) => {
let mouse = e.detail.intersection.point
let value
if (!this.data.vertical){
value = this.mousexPositionToValue(mouse.x);
} else {
value = this.mouseyPositionToValue(mouse.y);
}
//this.setValue(Math.round(value));
if (this.el.parentEl.components['babia-navigator']){
this.el.parentEl.components['babia-navigator'].controlNavigator('babiaSetPosition', Math.round(value))
} else if (this.el.parentEl.components['babia-step-controller']){
this.el.parentEl.components['babia-step-controller'].controlStep(Math.round(value))
} else if (this.el.parentEl.components['babia-speed-controller']){
this.el.parentEl.components['babia-speed-controller'].controlSpeed(Math.round(value))
}
})
}
})
AFRAME.registerComponent('babia-step-controller', {
schema: {
value: { type: 'number', default: -5 },
},
multiple: true,
sliderEl: undefined,
step: undefined,
init: function () {
this.createSlider()
},
update: function(old) {
if(this.data.value !== old.value) {
this.sliderEl.setAttribute('babia-slider','value', this.data.value);
}
},
createSlider: function(){
this.sliderEl = document.createElement('a-entity');
this.sliderEl.setAttribute('babia-slider', {
size: 1,
min: 1,
max: 10,
value: 1,
vertical: true
}); // When implement with selector, add the attributes
this.sliderEl.classList.add("babiaxraycasterclass");
this.sliderEl.id = "step-controller"
this.el.appendChild(this.sliderEl);
},
controlStep: function(value){
this.step = value
this.el.parentEl.components['babia-navigator'].controlNavigator('babiaSetStep', this.step)
}
})
AFRAME.registerComponent('babia-speed-controller', {
schema: {
value: { type: 'number', default: -5 },
},
multiple: true,
sliderEl: undefined,
speed: undefined,
init: function () {
this.createSlider()
},
update: function(old) {
if(this.data.value !== old.value) {
this.sliderEl.setAttribute('babia-slider','value', this.data.value);
}
},
createSlider: function(){
this.sliderEl = document.createElement('a-entity');
this.sliderEl.setAttribute('babia-slider', {
size: 1,
min: 1,
max: 3,
value: 1,
vertical: true
}); // When implement with selector, add the attributes
this.sliderEl.classList.add("babiaxraycasterclass");
this.sliderEl.id = "speed-controller"
this.el.appendChild(this.sliderEl);
},
controlSpeed: function(value){
this.speed = value
this.el.parentEl.components['babia-navigator'].controlNavigator('babiaSetSpeed', this.speed)
}
})