aframe-babia-components
Version:
A data visualization set of components for A-Frame.
189 lines (174 loc) • 6.91 kB
JavaScript
const colors = require('../others/common').colors;
/*
* BabiaXR Cyl component
*
* Builds a cylinder (usually for the cyls chart)
*/
AFRAME.registerComponent('babia-cyl', {
schema: {
// Height of the cylinder
height: { type: 'number' },
// Width of the cylinder
radius: { type: 'number' },
// Color for axis and labels
color: { type: 'color', default: '#000' },
// Should this be animated
animation: { type: 'boolean', default: true},
// Duration of animations
dur: { type: 'number', default: 2000},
// Label for the cylinder ('', 'fixed', 'events')
label: { type: 'string', default: ''},
// Label text (valid if label is not empty)
labelText: { type: 'string', default: ''},
// Label lookat for following
labelLookat: { type: 'string', default: "[camera]" }
},
init: function() {
console.log("Starting cyl:", this.data.height, this.data.color);
let data = this.data;
this.cylinder = document.createElement('a-entity');
this.cylinder.classList.add("babiaxraycasterclass");
this.el.appendChild(this.cylinder);
let props = {}
if (data.animation) {
props = {'height': 0, 'radius': data.radius};
} else {
props = {'height': data.height,
'radius': data.radius};
}
this.cylinder.setAttribute('geometry', {
'primitive': 'cylinder',
'height': props.height,
'radius': props.radius
});
this.cylinder.setAttribute('material', {
'color': data.color
});
},
update: function (oldData) {
let data = this.data;
let cylinder = this.cylinder;
this.updateProperty(cylinder, 'geometry', 'height', data.animation,
data['height'], oldData.height);
// Update height
if (data.height != oldData.height) {
// If there is change in height, update position
if (data.animation) {
cylinder.setAttribute('animation__pos', {
'property': 'position',
'to': { x: 0, y: data.height/2, z:0 },
'dur': data.dur
});
if (data.height <= 0 && oldData.height > 0){
cylinder.setAttribute('animation__opacity', {
'property': 'material.opacity',
'to': 0,
'dur': data.dur
});
} else if (oldData.height <= 0 && data.height > 0){
cylinder.setAttribute('animation__opacity', {
'property': 'material.opacity',
'to': 100,
'dur': data.dur
});
}
} else {
cylinder.setAttribute('position', { x: 0, y: data.height/2, z: 0 });
if (data.height <= 0 && oldData.height > 0){
cylinder.setAttribute('material', 'opacity', 0);
} else if (oldData.height <= 0 && data.height > 0){
cylinder.setAttribute('material', 'opacity', 100);
}
};
};
this.updateProperty(cylinder, 'geometry', 'radius', data.animation,
data.radius, oldData.radius);
this.updateProperty(cylinder, 'material', 'color', data.animation,
data.color, oldData.color);
if (this.data.label === 'events') {
cylinder.addEventListener('mouseenter', this.showLabel.bind(this));
cylinder.addEventListener('mouseleave', this.hideLabel.bind(this));
} else if (this.data.label === 'fixed') {
this.showLabel(oldData);
};
},
/*
* Update a property in an element, having animation into account
*
* @param el Element
* @param component Component in which to update property
* @param property Property to update in element
* @param name: Property name in data, oldData
* @param oldValue: Old value
*/
updateProperty: function (el, component, property, anim, newValue, oldValue) {
let data = this.data;
if (newValue !== oldValue) {
if (anim) {
let prop = component;
if (property) { prop = prop + '.' + property };
el.setAttribute('animation__'+component+'_'+property, {
'property': prop,
'to': newValue,
'dur': data.dur
});
} else {
if (property) {
el.setAttribute(component, { [property]: newValue });
} else {
el.setAttribute(component, newValue);
}
};
};
},
showLabel: function (oldData) {
let data = this.data;
if (data.label === 'events') {
this.el.setAttribute('scale', { x: 1.1, y: 1.1, z: 1.1 });
};
text = data.labelText;
let width = 2;
if (text.length > 16) { width = text.length / 8 };
let height = 1;
oldHeight = oldData.height || 0;
let oldPosition = {
x: 0, y: oldHeight + 0.6 * height,
z: 0
}
if (!this.labelEl) {
this.labelEl = document.createElement('a-entity');
this.labelEl.setAttribute('babia-label', {
'width': width, 'textWidth': 6
});
if (data.animation && (data.label === 'fixed')) {
this.labelEl.setAttribute('position', oldPosition);
};
this.el.appendChild(this.labelEl);
};
let position = {
x: 0, y: data.height + 0.7 * height,
z: 0.7 * data.radius
};
let anim = data.animation && (data.label === 'fixed');
this.updateProperty(this.labelEl, 'position', '', anim, position, oldPosition);
this.labelEl.setAttribute('rotation', {x: 0, y: 0, z: 0});
if (text != oldData.labelText) {
this.labelEl.setAttribute('babia-label', { 'text': data.labelText });
}
if(data.labelLookat && oldData.labelLookat !== data.labelLookat){
this.labelEl.setAttribute('babia-lookat', data.labelLookat);
}
if(data.labelScale && oldData.labelScale !== data.labelScale){
this.labelEl.setAttribute('scale',{x: data.labelScale, y: data.labelScale, z: data.labelScale});
}
},
hideLabel: function () {
if (this.data.label === 'events') {
this.el.setAttribute('scale', { x: 1, y: 1, z: 1 });
};
if (this.labelEl) {
this.el.removeChild(this.labelEl);
this.labelEl = null;
}
}
});