Support dragging child entities
This commit is contained in:
parent
73c1d75f00
commit
877f0f12f1
4 changed files with 89 additions and 15 deletions
|
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
## [Unreleased][]
|
## [Unreleased][]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Support click and drag for children of entities and the camera
|
||||||
|
|
||||||
## [1.3.3][] - 2016-11-05
|
## [1.3.3][] - 2016-11-05
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
25
examples/children/index.html
Normal file
25
examples/children/index.html
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>A-Frame Click & Drag Component - Basic</title>
|
||||||
|
<script src="../build.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a-scene>
|
||||||
|
|
||||||
|
<a-cylinder click-drag position="1 0.75 1" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
|
||||||
|
<a-plane rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
|
||||||
|
|
||||||
|
<a-sky color="#ECECEC"></a-sky>
|
||||||
|
|
||||||
|
<a-entity position="0 0 3.8">
|
||||||
|
<a-camera look-controls-enabled="false" keyboard-controls="mode: fps">
|
||||||
|
|
||||||
|
<a-sphere click-drag position="0 0.5 -4" radius="1.25" color="#EF2D5E">
|
||||||
|
<a-box click-drag position="-1 0.5 1" rotation="0 45 0" width="1" height="1" depth="1" color="#4CC3D9"></a-box>
|
||||||
|
</a-sphere>
|
||||||
|
|
||||||
|
</a-camera>
|
||||||
|
</a-entity>
|
||||||
|
</a-scene>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -35,6 +35,12 @@
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
|
<a class="demo-link" href="children/">Children Demo</a>
|
||||||
|
<p>Child entities can be dragged around too!</p>
|
||||||
|
<p>In this example, the cube is a child of the sphere, which is a child of the camera.</p>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
<a class="demo-link" href="physics/">Physics Demo</a>
|
<a class="demo-link" href="physics/">Physics Demo</a>
|
||||||
<p>Calculating the velocity at the time of drag end.</p>
|
<p>Calculating the velocity at the time of drag end.</p>
|
||||||
<p>Combined with a physics library (for example; <a href="https://github.com/donmccurdy/aframe-extras/tree/master/src/physics">aframe-extras physics</a>), we get some very nice interactions.</p>
|
<p>Combined with a physics library (for example; <a href="https://github.com/donmccurdy/aframe-extras/tree/master/src/physics">aframe-extras physics</a>), we get some very nice interactions.</p>
|
||||||
|
|
69
src/index.js
69
src/index.js
|
@ -19,19 +19,31 @@ function forceWorldUpdate(threeElement) {
|
||||||
element.updateMatrixWorld(true);
|
element.updateMatrixWorld(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function forEachParent(element, lambda) {
|
||||||
|
while (element.attachedToParent) {
|
||||||
|
element = element.parentElement;
|
||||||
|
lambda(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function someParent(element, lambda) {
|
||||||
|
while (element.attachedToParent) {
|
||||||
|
element = element.parentElement;
|
||||||
|
if (lambda(element)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function cameraPositionToVec3(camera, vec3) {
|
function cameraPositionToVec3(camera, vec3) {
|
||||||
|
|
||||||
let element = camera;
|
|
||||||
|
|
||||||
vec3.set(
|
vec3.set(
|
||||||
element.components.position.data.x,
|
camera.components.position.data.x,
|
||||||
element.components.position.data.y,
|
camera.components.position.data.y,
|
||||||
element.components.position.data.z
|
camera.components.position.data.z
|
||||||
);
|
);
|
||||||
|
|
||||||
while (element.attachedToParent) {
|
forEachParent(camera, element => {
|
||||||
|
|
||||||
element = element.parentElement;
|
|
||||||
|
|
||||||
if (element.components && element.components.position) {
|
if (element.components && element.components.position) {
|
||||||
vec3.set(
|
vec3.set(
|
||||||
|
@ -41,7 +53,7 @@ function cameraPositionToVec3(camera, vec3) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,6 +322,10 @@ function dragItem(THREE, element, offset, camera, depth, mouseInfo, lockToLocalR
|
||||||
z: THREE.Math.radToDeg(rotationEuler.z),
|
z: THREE.Math.radToDeg(rotationEuler.z),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const activeCamera = element.sceneEl.systems.camera.activeCameraEl;
|
||||||
|
|
||||||
|
const isChildOfActiveCamera = someParent(element, parent => parent === activeCamera);
|
||||||
|
|
||||||
function onMouseMove({clientX, clientY}) {
|
function onMouseMove({clientX, clientY}) {
|
||||||
|
|
||||||
lastMouseInfo = {clientX, clientY};
|
lastMouseInfo = {clientX, clientY};
|
||||||
|
@ -330,26 +346,49 @@ function dragItem(THREE, element, offset, camera, depth, mouseInfo, lockToLocalR
|
||||||
|
|
||||||
if (lockToLocalRotation) {
|
if (lockToLocalRotation) {
|
||||||
|
|
||||||
|
let rotationDiff;
|
||||||
|
|
||||||
// Start by rotating backwards from the initial camera rotation
|
// Start by rotating backwards from the initial camera rotation
|
||||||
const rotationDiff = rotationQuaternion.copy(startCameraRotationInverse)
|
rotationDiff = rotationQuaternion.copy(startCameraRotationInverse);
|
||||||
// Then add the current camera rotation
|
|
||||||
.multiply(threeCamera.getWorldQuaternion());
|
|
||||||
|
|
||||||
// rotate the offset
|
// rotate the offset
|
||||||
offsetVector.set(offset.x, offset.y, offset.z);
|
offsetVector.set(offset.x, offset.y, offset.z);
|
||||||
|
|
||||||
|
// Then add the current camera rotation
|
||||||
|
rotationDiff = rotationQuaternion.multiply(threeCamera.getWorldQuaternion());
|
||||||
|
|
||||||
offsetVector.applyQuaternion(rotationDiff);
|
offsetVector.applyQuaternion(rotationDiff);
|
||||||
|
|
||||||
// And correctly offset rotation
|
if (!isChildOfActiveCamera) {
|
||||||
rotationDiff.multiply(startElementRotation);
|
// And correctly offset rotation
|
||||||
rotationEuler.setFromQuaternion(rotationDiff, elementRotationOrder);
|
rotationDiff.multiply(startElementRotation);
|
||||||
|
|
||||||
|
rotationEuler.setFromQuaternion(rotationDiff, elementRotationOrder);
|
||||||
|
}
|
||||||
|
|
||||||
nextRotation.x = THREE.Math.radToDeg(rotationEuler.x);
|
nextRotation.x = THREE.Math.radToDeg(rotationEuler.x);
|
||||||
nextRotation.y = THREE.Math.radToDeg(rotationEuler.y);
|
nextRotation.y = THREE.Math.radToDeg(rotationEuler.y);
|
||||||
nextRotation.z = THREE.Math.radToDeg(rotationEuler.z);
|
nextRotation.z = THREE.Math.radToDeg(rotationEuler.z);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const nextPosition = {x: x - offsetVector.x, y: y - offsetVector.y, z: z - offsetVector.z};
|
const nextPosition = {x: x - offsetVector.x, y: y - offsetVector.y, z: z - offsetVector.z};
|
||||||
|
|
||||||
|
// When the element has parents, we need to convert its new world position
|
||||||
|
// into new local position of its parent element
|
||||||
|
if (element.parentEl !== element.sceneEl) {
|
||||||
|
|
||||||
|
// The new world position
|
||||||
|
offsetVector.set(nextPosition.x, nextPosition.y, nextPosition.z);
|
||||||
|
|
||||||
|
// Converted
|
||||||
|
element.parentEl.object3D.worldToLocal(offsetVector);
|
||||||
|
|
||||||
|
nextPosition.x = offsetVector.x;
|
||||||
|
nextPosition.y = offsetVector.y;
|
||||||
|
nextPosition.z = offsetVector.z;
|
||||||
|
}
|
||||||
|
|
||||||
element.emit(DRAG_MOVE_EVENT, {nextPosition, nextRotation, clientX, clientY});
|
element.emit(DRAG_MOVE_EVENT, {nextPosition, nextRotation, clientX, clientY});
|
||||||
|
|
||||||
element.setAttribute('position', nextPosition);
|
element.setAttribute('position', nextPosition);
|
||||||
|
|
Loading…
Reference in a new issue