Enable screen locking for rotated camera views
This commit is contained in:
parent
a675ba84ba
commit
20f5f9b000
5 changed files with 47 additions and 33 deletions
|
@ -3,9 +3,7 @@
|
||||||
A Click & Drag component for [A-Frame](https://aframe.io).
|
A Click & Drag component for [A-Frame](https://aframe.io).
|
||||||
|
|
||||||
Entities with the `click-drag` component can be click and dragged around the 3D
|
Entities with the `click-drag` component can be click and dragged around the 3D
|
||||||
scene. Even works whle the camera is moving!
|
scene. Even works whle the camera is moving or rotating!
|
||||||
|
|
||||||
_Note: entities are not positioned correctly when the camera is rotated._
|
|
||||||
|
|
||||||
### Events
|
### Events
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
<a-sky color="#ECECEC"></a-sky>
|
<a-sky color="#ECECEC"></a-sky>
|
||||||
|
|
||||||
<a-entity position="0 0 3.8">
|
<a-entity position="0 0 3.8">
|
||||||
<a-camera look-controls-enabled="false"></a-camera>
|
<a-camera look-controls-enabled="false" keyboard-controls="fpsMode: true"></a-camera>
|
||||||
</a-entity>
|
</a-entity>
|
||||||
</a-scene>
|
</a-scene>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
<a-sky color="#ECECEC"></a-sky>
|
<a-sky color="#ECECEC"></a-sky>
|
||||||
|
|
||||||
<a-entity position="0 0 3.8">
|
<a-entity position="0 0 3.8">
|
||||||
<a-camera look-controls-enabled="false"></a-camera>
|
<a-camera look-controls-enabled="false" keyboard-controls="fpsMode: true"></a-camera>
|
||||||
</a-entity>
|
</a-entity>
|
||||||
<script>
|
<script>
|
||||||
var draggable = document.querySelector('[click-drag]');
|
var draggable = document.querySelector('[click-drag]');
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
<a-sky color="#ECECEC"></a-sky>
|
<a-sky color="#ECECEC"></a-sky>
|
||||||
|
|
||||||
<a-entity position="0 0 3.8">
|
<a-entity position="0 0 3.8">
|
||||||
<a-camera look-controls-enabled="false"></a-camera>
|
<a-camera look-controls-enabled="false" keyboard-controls="fpsMode: true"></a-camera>
|
||||||
</a-entity>
|
</a-entity>
|
||||||
<script>
|
<script>
|
||||||
var draggable = document.querySelector('[click-drag]');
|
var draggable = document.querySelector('[click-drag]');
|
||||||
|
|
60
src/index.js
60
src/index.js
|
@ -289,7 +289,7 @@ const {selectItem} = (function selectItemFunction() {
|
||||||
};
|
};
|
||||||
}());
|
}());
|
||||||
|
|
||||||
function dragItem(THREE, element, offset, camera, depth, mouseInfo) {
|
function dragItem(THREE, element, offset, camera, depth, mouseInfo, lockToLocalRotation) {
|
||||||
|
|
||||||
const {x: offsetX, y: offsetY, z: offsetZ} = offset;
|
const {x: offsetX, y: offsetY, z: offsetZ} = offset;
|
||||||
const threeCamera = camera.components.camera.camera;
|
const threeCamera = camera.components.camera.camera;
|
||||||
|
@ -300,9 +300,17 @@ function dragItem(THREE, element, offset, camera, depth, mouseInfo) {
|
||||||
const elementRotationOrder = element.object3D.rotation.order;
|
const elementRotationOrder = element.object3D.rotation.order;
|
||||||
|
|
||||||
const rotationQuaternion = new THREE.Quaternion();
|
const rotationQuaternion = new THREE.Quaternion();
|
||||||
const rotationEuler = new THREE.Euler();
|
const rotationEuler = element.object3D.rotation.clone();
|
||||||
|
|
||||||
|
const offsetVector = new THREE.Vector3(offset.x, offset.y, offset.z);
|
||||||
let lastMouseInfo = mouseInfo;
|
let lastMouseInfo = mouseInfo;
|
||||||
|
|
||||||
|
const nextRotation = {
|
||||||
|
x: THREE.Math.radToDeg(rotationEuler.x),
|
||||||
|
y: THREE.Math.radToDeg(rotationEuler.y),
|
||||||
|
z: THREE.Math.radToDeg(rotationEuler.z),
|
||||||
|
};
|
||||||
|
|
||||||
function onMouseMove({clientX, clientY}) {
|
function onMouseMove({clientX, clientY}) {
|
||||||
|
|
||||||
lastMouseInfo = {clientX, clientY};
|
lastMouseInfo = {clientX, clientY};
|
||||||
|
@ -321,34 +329,36 @@ function dragItem(THREE, element, offset, camera, depth, mouseInfo) {
|
||||||
depth
|
depth
|
||||||
);
|
);
|
||||||
|
|
||||||
// 1. Store initial element rotation
|
if (lockToLocalRotation) {
|
||||||
// 2. Store initial camera rotation
|
|
||||||
// 3. Calculate difference in camera rotation, inverted
|
|
||||||
// 4. Add #3 + #1
|
|
||||||
// 5. Set element rotation to #4
|
|
||||||
|
|
||||||
// Start by rotating backwards from the initial camera rotation
|
// Start by rotating backwards from the initial camera rotation
|
||||||
const rotationDiff = rotationQuaternion.copy(startCameraRotationInverse)
|
const rotationDiff = rotationQuaternion.copy(startCameraRotationInverse)
|
||||||
// Then add the current camera rotation
|
// Then add the current camera rotation
|
||||||
.multiply(threeCamera.getWorldQuaternion())
|
.multiply(threeCamera.getWorldQuaternion());
|
||||||
// And correctly offset rotation
|
|
||||||
.multiply(startElementRotation);
|
|
||||||
|
|
||||||
|
// rotate the offset
|
||||||
|
offsetVector.set(offset.x, offset.y, offset.z);
|
||||||
|
offsetVector.applyQuaternion(rotationDiff);
|
||||||
|
|
||||||
|
// And correctly offset rotation
|
||||||
|
rotationDiff.multiply(startElementRotation);
|
||||||
rotationEuler.setFromQuaternion(rotationDiff, elementRotationOrder);
|
rotationEuler.setFromQuaternion(rotationDiff, elementRotationOrder);
|
||||||
|
|
||||||
const nextRotation = {
|
nextRotation.x = THREE.Math.radToDeg(rotationEuler.x);
|
||||||
x: THREE.Math.radToDeg(rotationEuler.x),
|
nextRotation.y = THREE.Math.radToDeg(rotationEuler.y);
|
||||||
y: THREE.Math.radToDeg(rotationEuler.y),
|
nextRotation.z = THREE.Math.radToDeg(rotationEuler.z);
|
||||||
z: THREE.Math.radToDeg(rotationEuler.z),
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const nextPosition = {x: x - offsetX, y: y - offsetY, z: z - offsetZ};
|
const nextPosition = {x: x - offsetVector.x, y: y - offsetVector.y, z: 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);
|
||||||
|
|
||||||
|
if (lockToLocalRotation) {
|
||||||
element.setAttribute('rotation', nextRotation);
|
element.setAttribute('rotation', nextRotation);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onCameraChange({detail}) {
|
function onCameraChange({detail}) {
|
||||||
if (
|
if (
|
||||||
|
@ -375,7 +385,7 @@ const {initialize, tearDown} = (function closeOverInitAndTearDown() {
|
||||||
let removeClickListeners;
|
let removeClickListeners;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
initialize(THREE, componentName) {
|
initialize(THREE, componentName, lockToLocalRotation) {
|
||||||
|
|
||||||
// TODO: Based on a scene from the element passed in?
|
// TODO: Based on a scene from the element passed in?
|
||||||
const scene = document.querySelector('a-scene');
|
const scene = document.querySelector('a-scene');
|
||||||
|
@ -419,7 +429,8 @@ const {initialize, tearDown} = (function closeOverInitAndTearDown() {
|
||||||
{
|
{
|
||||||
clientX,
|
clientX,
|
||||||
clientY,
|
clientY,
|
||||||
}
|
},
|
||||||
|
lockToLocalRotation
|
||||||
);
|
);
|
||||||
|
|
||||||
draggedElement = element;
|
draggedElement = element;
|
||||||
|
@ -536,10 +547,10 @@ const {didMount, didUnmount} = (function getDidMountAndUnmount() {
|
||||||
const cache = [];
|
const cache = [];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
didMount(element, THREE, componentName) {
|
didMount(element, THREE, componentName, lockToLocalRotation) {
|
||||||
|
|
||||||
if (cache.length === 0) {
|
if (cache.length === 0) {
|
||||||
initialize(THREE, componentName);
|
initialize(THREE, componentName, lockToLocalRotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cache.indexOf(element) === -1) {
|
if (cache.indexOf(element) === -1) {
|
||||||
|
@ -579,6 +590,11 @@ export default function aframeDraggableComponent(aframe, componentName = COMPONE
|
||||||
*/
|
*/
|
||||||
aframe.registerComponent(componentName, {
|
aframe.registerComponent(componentName, {
|
||||||
schema: {
|
schema: {
|
||||||
|
/*
|
||||||
|
* @param {bool} [lockToLocalRotation=true] - When dragging the component,
|
||||||
|
* should it be screen locked (true), or should its rotation be left alone
|
||||||
|
* (false).
|
||||||
|
*/
|
||||||
lockToLocalRotation: {default: true},
|
lockToLocalRotation: {default: true},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -586,7 +602,7 @@ export default function aframeDraggableComponent(aframe, componentName = COMPONE
|
||||||
* Called once when component is attached. Generally for initial setup.
|
* Called once when component is attached. Generally for initial setup.
|
||||||
*/
|
*/
|
||||||
init() {
|
init() {
|
||||||
didMount(this, THREE, componentName);
|
didMount(this, THREE, componentName, this.data.lockToLocalRotation);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -618,7 +634,7 @@ export default function aframeDraggableComponent(aframe, componentName = COMPONE
|
||||||
* Use to continue or add any dynamic or background behavior such as events.
|
* Use to continue or add any dynamic or background behavior such as events.
|
||||||
*/
|
*/
|
||||||
play() {
|
play() {
|
||||||
didMount(this, THREE, componentName);
|
didMount(this, THREE, componentName, this.data.lockToLocalRotation);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue