Skip to content

Commit e4900e1

Browse files
Ryan Bettsngokevin
authored andcommitted
make cursor mouseleave with multiple objects more reliable (fixes aframevr#1882)
1 parent b944c3a commit e4900e1

File tree

2 files changed

+97
-24
lines changed

2 files changed

+97
-24
lines changed

examples/test/cursor/index.html

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,37 @@
2626

2727
<a-entity position="0 .6 4">
2828
<a-camera>
29-
<a-entity cursor
29+
<a-entity raycaster="far: 30; objects: .intersectable"
30+
cursor
3031
geometry="primitive: ring; radiusOuter: 0.015;
3132
radiusInner: 0.01; segmentsTheta: 32"
3233
material="color: #283644; shader: flat"
33-
raycaster="far: 30"
3434
position="0 0 -0.75"></a-entity>
3535
</a-camera>
3636
</a-entity>
3737

3838
<a-entity position="-3.5 1 0">
39-
<a-entity mixin="red cube">
39+
<a-entity mixin="red cube"
40+
class="intersectable">
4041
<a-animation begin="click" attribute="position" from="0 0 0"
4142
to="0 0 -10" dur="2000" fill="both"></a-animation>
4243
</a-entity>
4344
</a-entity>
4445

45-
<a-entity position="-1 1 0">
46-
<a-entity mixin="green cube"
46+
<a-entity position="0 1 1">
47+
<a-entity id="invisibleCube"
48+
mixin="cube"
49+
material="color: grey; opacity: 0.3; transparent: true"
50+
scale="1 1 0.1">
51+
<a-animation begin="click" attribute="rotation" to="0 360 0"
52+
easing="linear" dur="2000" fill="backwards"></a-animation>
53+
</a-entity>
54+
</a-entity>
55+
56+
<a-entity position="0 1 0">
57+
<a-entity id="foregroundCube"
58+
class="intersectable"
59+
mixin="green cube"
4760
sound__1="on: click; src: #blip1;"
4861
sound__2="on: mouseenter; src: #blip2;">
4962
<a-animation begin="click" attribute="rotation" to="0 360 0"
@@ -60,15 +73,25 @@
6073
</a-entity>
6174
</a-entity>
6275

76+
<a-entity position="0 1 -3">
77+
<a-entity id="backgroundCube"
78+
class="intersectable"
79+
mixin="green cube">
80+
<a-animation begin="click" attribute="rotation" to="0 360 0"
81+
easing="linear" dur="2000" fill="backwards"></a-animation>
82+
</a-entity>
83+
</a-entity>
84+
6385
<a-entity position="3.5 1 0" rotation="0 45 0">
64-
<a-entity mixin="blue cube">
86+
<a-entity mixin="blue cube"
87+
class="intersectable">
6588
<a-animation begin="click" fill="forwards" repeat="1"
6689
direction="alternate" attribute="position" from="0 0 0"
6790
to="15 0 0" dur="2000"></a-animation>
6891
</a-entity>
6992
</a-entity>
7093

71-
<a-entity mixin="yellow cube" position="0 3 0" class="clickable"
94+
<a-entity mixin="yellow cube" position="0 3 -3" class="intersectable clickable"
7295
rotation="0 45 0" scale=".5 .5 .5"></a-entity>
7396
</a-scene>
7497

@@ -98,6 +121,46 @@
98121
window.top.postMessage({type: 'navigate', data: {url: href}}, '*');
99122
})
100123
}
124+
125+
// testing mouseenter and mouseleave
126+
var foregroundCube = document.querySelector('#foregroundCube');
127+
foregroundCube.addEventListener('mouseenter', function (evt) {
128+
foregroundCube.setAttribute('mixin','cube cube-hovered')
129+
})
130+
foregroundCube.addEventListener('mouseleave', function (evt) {
131+
foregroundCube.setAttribute('mixin','green cube')
132+
})
133+
foregroundCube.addEventListener('mousedown', function (evt) {
134+
foregroundCube.setAttribute('mixin','cube cube-selected')
135+
})
136+
foregroundCube.addEventListener('mouseup', function (evt) {
137+
foregroundCube.setAttribute('mixin','cube cube-hovered')
138+
})
139+
foregroundCube.addEventListener('click', function (evt) {
140+
var scene = document.querySelector('a-scene');
141+
var clickRing = document.createElement('a-entity');
142+
clickRing.id = 'clickRing-'+new Date().getTime();
143+
clickRing.setAttribute('material','color: magenta; transparent: true; opacity: 0.6');
144+
clickRing.setAttribute('geometry','primitive: ring; radius-inner: 0.5; radius-outer: 0.6');
145+
clickRing.setAttribute('position',evt.detail.intersection.point);
146+
var opacityAnimation = document.createElement('a-animation');
147+
opacityAnimation.setAttribute('attribute','material.opacity');
148+
opacityAnimation.setAttribute('to',0);
149+
opacityAnimation.setAttribute('duration','250');
150+
opacityAnimation.setAttribute('easing','ease-out-quad');
151+
var scaleAnimation = document.createElement('a-animation');
152+
scaleAnimation.setAttribute('attribute','scale');
153+
scaleAnimation.setAttribute('to','3 3 3');
154+
scaleAnimation.setAttribute('duration','250');
155+
scaleAnimation.setAttribute('easing','ease-out-quad');
156+
var onAnimationEnd = function () {
157+
scene.removeChild(document.querySelector('#'+clickRing.id))
158+
}
159+
scaleAnimation.addEventListener('animationend', onAnimationEnd.bind(this))
160+
clickRing.appendChild(opacityAnimation);
161+
clickRing.appendChild(scaleAnimation);
162+
scene.appendChild(clickRing);
163+
})
101164
})();
102165
</script>
103166
</body>

src/components/cursor.js

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ module.exports.Component = registerComponent('cursor', {
7373
* - Currently-intersected entity is the same as the one when mousedown was triggered,
7474
* in case user mousedowned one entity, dragged to another, and mouseupped.
7575
*/
76-
onMouseUp: function () {
76+
onMouseUp: function (evt) {
7777
this.twoWayEmit(EVENTS.MOUSEUP);
7878
if (this.data.fuse || !this.intersectedEl ||
7979
this.mouseDownEl !== this.intersectedEl) { return; }
@@ -87,17 +87,25 @@ module.exports.Component = registerComponent('cursor', {
8787
var self = this;
8888
var cursorEl = this.el;
8989
var data = this.data;
90+
var index;
91+
var intersectedEl;
92+
var intersection;
9093

91-
// Select closest object, other than the cursor.
92-
var index = evt.detail.els[0] === cursorEl ? 1 : 0;
93-
var intersection = evt.detail.intersections[index];
94-
var intersectedEl = evt.detail.els[index];
94+
// Select closest object, excluding the cursor.
95+
index = evt.detail.els[0] === cursorEl ? 1 : 0;
96+
intersection = evt.detail.intersections[index];
97+
intersectedEl = evt.detail.els[index];
9598

9699
// If cursor is the only intersected object, ignore the event.
97100
if (!intersectedEl) { return; }
98101

99-
// Set intersected entity if not already intersecting.
102+
// Already intersecting this entity.
100103
if (this.intersectedEl === intersectedEl) { return; }
104+
105+
// Unset current intersection.
106+
if (this.intersectedEl) { this.leaveCurrentIntersection(); }
107+
108+
// Set new intersection.
101109
this.intersection = intersection;
102110
this.intersectedEl = intersectedEl;
103111

@@ -125,11 +133,17 @@ module.exports.Component = registerComponent('cursor', {
125133
// Ignore the cursor.
126134
if (cursorEl === intersectedEl) { return; }
127135

128-
// Not intersecting.
129-
if (!intersectedEl || !this.intersectedEl) { return; }
136+
// ignore if the event didn't occur on the current intersection
137+
if (intersectedEl !== this.intersectedEl) { return; }
138+
139+
this.clearCurrentIntersection(intersectedEl);
140+
},
141+
142+
clearCurrentIntersection: function () {
143+
var cursorEl = this.el;
130144

131145
// No longer hovering (or fusing).
132-
intersectedEl.removeState(STATES.HOVERED);
146+
this.intersectedEl.removeState(STATES.HOVERED);
133147
cursorEl.removeState(STATES.HOVERING);
134148
cursorEl.removeState(STATES.FUSING);
135149
this.twoWayEmit(EVENTS.MOUSELEAVE);
@@ -147,14 +161,10 @@ module.exports.Component = registerComponent('cursor', {
147161
*/
148162
twoWayEmit: function (evtName) {
149163
var intersectedEl = this.intersectedEl;
150-
this.el.emit(evtName, {
151-
intersection: this.intersection,
152-
intersectedEl: this.intersectedEl
153-
});
164+
var cursorEvtDetail = { intersectedEl: this.intersectedEl, intersection: this.intersection };
165+
var intersectedElEvtDetail = { cursorEl: this.el, intersection: this.intersection };
166+
this.el.emit(evtName, cursorEvtDetail);
154167
if (!intersectedEl) { return; }
155-
intersectedEl.emit(evtName, {
156-
intersection: this.intersection,
157-
cursorEl: this.el
158-
});
168+
intersectedEl.emit(evtName, intersectedElEvtDetail);
159169
}
160170
});

0 commit comments

Comments
 (0)