aframe switching between mouse and entity controls - aframe

I'm having massive problems getting mouse to work after the player has been in VR.
Updating the cursor attributes didn't do anything, so I've tried removing and replacing them
getRayCasterAttributes: function(){
return this.data.isVR ?
{
cursorAttributes:{
fuse: true,
fuseTimeout: cursorFuseTimeout,
},
raycasterAttributes: {
objects: '[data-raycastable]',
},
} :
{cursorAttributes:{
fuse: true,
fuseTimeout: cursorFuseTimeout,
rayOrigin: 'mouse',
},
raycasterAttributes: {
objects: '[data-raycastable]',
},
}
}
if(oldData.isVR !== this.data.isVR){
this._recticle.object3D.visible = this.data.isVR
this._recticle.removeAttribute('raycaster')
this._recticle.removeAttribute('cursor')
setTimeout(() => {
console.log(this.getRayCasterAttributes().raycasterAttributes, this.getRayCasterAttributes().cursorAttributes)
this._recticle.setAttribute('raycaster', this.getRayCasterAttributes().raycasterAttributes)
this._recticle.setAttribute('cursor', this.getRayCasterAttributes().cursorAttributes)
},100)
This kind of works switching from 2D to VR with the timeout, but switching back is another major pain.
What is the best way to do this in aframe?
I've tried this, isn't helping. Works with mouse, does not switch to cursor controls when entering VR.
this._recticle.setAttribute('cursor', {fuse: false, rayOrigin: 'mouse'})
else
this._recticle.setAttribute('cursor', {fuse: true,rayOrigin: 'entity', fuseTimeout: 2000})

The opposite would be rayOrigin: entity.

Have a seperate cursor on the scene and in the camera, then you can have both
how separate the mouse click event and the courser click event in Aframe
https://glitch.com/edit/#!/winter-sagittarius

Related

animating a custom attribute in a custom component

I am attempting to animate a material property that is buried inside of a gltf-model (that has many objects). I can find the parameter and animate it with a tick event, and it looks like this
https://glitch.com/~uv-reveal-wave
It almost works, but animating with formulas is a nightmare. Instead I want to control it with the animation component. Unfortunately, exposing the parameter directly seems impossible, as I have to use getObject3D.traverse() just to locate the object, and then get the parameter.
Instead I have made a custom attribute (in schema) and and animating that attribute. And in the update function, I'm using that attribute to drive the buried parameter. It should work, but I can't seem to get a response in the update function. Iow, my custom attribute is not animating.
AFRAME.registerComponent('matclipplane', { // attached to gltf-model tree
schema:{
clipHeightA:{type: 'number', default: 0}
},
init: function () {
let el = this.el;
let comp = this;
comp.treeModels = [];
el.addEventListener('model-loaded', function(ev){
let mesh = el.getObject3D('mesh');
mesh.traverse(function(node){
if (node.isMesh){
comp.treeModels.push(node);
}
comp.modelLoaded = true;
});
...
update: function(){
console.log("update"); // returns nothing. no update from
animating attributes clipHeightA
let comp = this;
if (comp.modelLoaded){
comp.treeModels[1].material.map.offset.y =
this.data.clipHeightA;
}
}
...
AFRAME.registerComponent("click-listener", { // attached to box button
schema:{
dir:{type:"boolean", default: false}
},
init: function(){
let el=this.el;
let data = this.data;
el.addEventListener("click", function(evt){
let tree = document.querySelector('#tree');
data.dir = !data.dir;
if(data.dir){
el.setAttribute("material",'color', 'orange');
tree.emit("grow");
} else {
el.setAttribute('material','color','#332211');
tree.emit('shrink');
}
});
}
});
<a-entity id="tree" gltf-model="#tree" scale="5 5 5"
animation__grow="property: clipHeightA; from: 0; to: 1;
startEvents: grow; dur: 500"
matclipplane></a-entity>
<a-entity id="button" geometry="primitive: box" material="color:orange;
metalness: 0.5" scale="0.2 0.2 0.2" class="clickable" click-listener></a-
entity>
<a-entity id="mouseCursor" cursor="rayOrigin: mouse" raycaster="objects:
.clickable"></a-entity>
here is the glitch in progress
https://glitch.com/~uv-reveal
Clicking on the orange cube should launch the uv reveal animation. I expect that calling a custom component attribute should trigger an update event, but the update does not log in the console.
Not sure how to animate a parameter inside a gltf.
Do I have to implement the animejs component directly inside my custom component?
Or can this be done with the animate component?
According to the docs you can animate properties through
object3D like animation="property: object3D.x"
components like animation="property: components.myComp.myProp"
I don't see it mentioned (although it's used in the docs) but it also works when you provide the property as the components attribute:
animation__grow="property: matclipplane.clipHeightA;"
glitch here. You can see update is being called.
Also tree was an id of both the asset and the component, therefore grow was emitted on the asset item.

How can you detect a double click in a frame?

This event seems to be missing from the standard events. Lick click, I would need to set up a listener for it in a component.
Thanks to Piotr for getting me on the right track. As of this post, there is no double click event for aframe, but we can use js/jquery to get around this. Here is the start of my function:
el.addEventListener('click', function(evt) {
\$('#myEmbeddedSce').on('dblclick', function(event) {
event.stopPropagation();
event.stopImmediatePropagation();
.....
The key was to add the jquery listener inside the aframe listener, and add the stop propagations so the doubleclicks only registered once.
use stopPropagation() to detect the double click in the frame.
The stopPropagation() method prevents propagation of the same event from being called. Propagation means bubbling up to parent elements or capturing down to child elements.
Syntax
event.stopPropagation()
I've solved the issue of detecting by taking tips from existing answers. Ie, tracking the difference of time and distance between clicks. For whatever reason the click listener did not give me clientX and clientY coordinates, so I used the distance vector instead.
This is my solution:
let prevClickTime = Date.now();
let prevVector = new Vector3(0, 0, 0);
// let pointString;
AFRAME.registerComponent('bar', {
init: function () {
this.el.addEventListener('click', (e) => {
const currClickTime = Date.now();
const currVector = e.detail.intersection.point;
const distance = currVector.distanceTo(prevVector);
const timeDiff = currClickTime - prevClickTime;
if (timeDiff < 260 && distance < 0.4) {
console.log('double click');
}
prevClickTime = currClickTime;
prevVector = currVector;
});
},
});
This was pointed at this aframe-react entity.
<Entity
class="interactable"
id="arrow"
bar
geometry={{ primitive: 'cylinder', width: 1, height: 0.05 }}
material={{ color: 'blue', opacity: 0.6 }}
position={`2 0.5 ${adj}`}
rotation="0 0 0"
/>

Aframe How do I simulate a 6dof controller on the Oculus GO controller using the touchpad to move the controller forward, back, left, and right?

enter image description hereWhat if we could simulate 6dof control on the Oculus Go controller? Imagine that we turn the controller 3d model into a hand, it still just rotates, but imagine that we use the touchpad to move the hand foward, left, right, or backwards in space, the touch pad gives you movement along a z and x axis in space, but the accelerometer/gyro gives you a y and x axis. so the accelerometer/gyro serves as the arm, and the touch pad serves as the hand/wrist, a hand that can move forward and back and only twist left and right, and grip with the trigger, the hand can't tilt up or down but the arm can make up for that. So how do I build this?
There is https://www.npmjs.com/package/aframe-thumb-controls-component that provides events for pressing thumbpad in directions (e.g., thumbupstart, thumbleftend).
Write a component that listens to those events, sets a property (e.g., this.buttons.left = true, then the tick handler needs to update the this.el.object3D.position based on which buttons are held down.
Also need to take into consideration the direction the camera is facing. https://github.com/aframevr/aframe/blob/master/src/components/wasd-controls.js is a good starting point is it is similar, where it listens to key downs and translates position. Just need to modify to use thumb-controls instead.
More hints:
<script src="https://unpkg.com/aframe-thumb-controls-component#1.1.0/dist/aframe-thumb-controls-component.min.js">
AFRAME.registerComponent('thumb-movement-controls', {
init: function () {
this.buttons = {
left: false, right: false, up: false, down: false
};
this.el.addEventListener('thumbleftstart', () => {
this.buttons.left = true;
});
this.el.addEventListener('thumbleftend', () => {
this.buttons.left = false;
});
},
tick: function () {
// Really simplified movement. Does not take into account camera heading or velocity / time, but wasd-controls shows how.
if (this.buttons.left) {
this.el.position.x -= 0.001;
}
}
});
<a-entity daydream-controls thumb-controls thumb-movement-controls></a-entity>

Google vr view using click on hotspot to change content

Once I have an embedded vr view on my website, how do I implement clicking on a hotspot?
function onVrViewLoad() {
var v;
v = new VRView.Player('#vrview', {
image: '/images/firstImage.jpg',
is_stereo: false
});
v.on('ready', function(){
v.addHotspot('hotspotOne', {
pitch: 0, // In degrees. Up is positive.
yaw: 180, // In degrees. To the right is positive.
radius: 0.05, // Radius of the circular target in meters.
distance: 2 // Distance of target from camera in meters.
});
});
v.on('click', function(event) {
if (event.id == 'hotspotOne') {
v.setContentInfo({
image: '/images/secondImage.jpg',
is_stereo: false
});
}
});}
The hotspot shows up and can be clicked, but it does not change the image. If I replace the v.setContentInfo() to window.location.href='/secondImage.html' where I have set up another vr viewer with that image, it loads the page. So I know the click event is registering correctly, but the setContentInfo() is not.
Whilst the documentation says to use setContentInfo(), I've found it's actually setContent() that works. This gave me a headache for a while!
v.setContent({
image: '/images/secondImage.jpg',
is_stereo: false
});

fancybox-3 close button disable/enable delay not working

I have my fancybox close button diplay:none; when an iframe opens, I want the close button appears in a delay of x time. exactly like this DEMO.
Though it is solved in earlier version of fancy box in here, but in fancybox-3 It works for the first time and thereafter the close button doesn't appear until I refresh the page.
I use the following JS Code for delay:
$(document).ready(function() {
setTimeout(function() {
$(".fancybox-button--close").show();
}, 5000);
});
Any ideas? Thanks.
This is how you can access the toolbar and make it visible, if needed:
$('[data-fancybox="images"]').fancybox({
afterShow : function(instance, slide) {
setTimeout(function() {
instance.$refs.toolbar.show();
}, 3000);
}
});
Demo - https://codepen.io/anon/pen/oeWqrJ
But, if you want to toggle that small close button, here is an example:
$('[data-fancybox]').fancybox({
toolbar : false,
smallBtn : true,
afterShow : function(instance, slide) {
setTimeout(function() {
slide.$slide.find('.fancybox-close-small').show();
}, 3000);
}
});
Demo - https://codepen.io/anon/pen/oeWqRJ
Basically, you can access any element either from instance.$refs (collection of references to interface elements) or from slide.$slide (parent element of the content).

Resources