refactor(index.js): improve syntax consistency and cleanup

Standardized single quotes to double quotes and removed unnecessary
commas for a more consistent code style across the file. Removed unused
imports and whitespace, contributing to a cleaner and more readable
codebase. Additionally, optimized the way Quaternion and Vector3 objects
are reused, reducing the need for creating new instances, thus
potentially improving memory usage and performance slightly.

No API changes or behavior modifications were introduced, ensuring
backward compatibility.
This commit is contained in:
Kumi 2024-03-27 18:30:26 +01:00
parent 887a55f37c
commit e9eeef512a
Signed by: kumi
GPG key ID: ECBCC9082395383F

View file

@ -1,15 +1,13 @@
import deepEqual from 'deep-equal'; import deepEqual from "deep-equal";
import { Linter } from 'eslint';
const COMPONENT_NAME = 'click-drag'; const COMPONENT_NAME = "click-drag";
const DRAG_START_EVENT = 'dragstart'; const DRAG_START_EVENT = "dragstart";
const DRAG_MOVE_EVENT = 'dragmove'; const DRAG_MOVE_EVENT = "dragmove";
const DRAG_END_EVENT = 'dragend'; const DRAG_END_EVENT = "dragend";
const TIME_TO_KEEP_LOG = 100; const TIME_TO_KEEP_LOG = 100;
function forceWorldUpdate(threeElement) { function forceWorldUpdate(threeElement) {
let element = threeElement; let element = threeElement;
while (element.parent) { while (element.parent) {
element = element.parent; element = element.parent;
@ -36,25 +34,21 @@ function someParent(element, lambda) {
} }
function cameraPositionToVec3(camera, vec3) { function cameraPositionToVec3(camera, vec3) {
vec3.set( vec3.set(
camera.components.position.data.x, camera.components.position.data.x,
camera.components.position.data.y, camera.components.position.data.y,
camera.components.position.data.z, camera.components.position.data.z
); );
forEachParent(camera, (element) => { forEachParent(camera, (element) => {
if (element.components && element.components.position) { if (element.components && element.components.position) {
vec3.set( vec3.set(
vec3.x + element.components.position.data.x, vec3.x + element.components.position.data.x,
vec3.y + element.components.position.data.y, vec3.y + element.components.position.data.y,
vec3.z + element.components.position.data.z, vec3.z + element.components.position.data.z
); );
} }
}); });
} }
function localToWorld(THREE, threeCamera, vector) { function localToWorld(THREE, threeCamera, vector) {
@ -62,8 +56,7 @@ function localToWorld(THREE, threeCamera, vector) {
return threeCamera.localToWorld(vector); return threeCamera.localToWorld(vector);
} }
const {unproject} = (function unprojectFunction() { const { unproject } = (function unprojectFunction() {
let initialized = false; let initialized = false;
let matrix; let matrix;
@ -75,9 +68,7 @@ const {unproject} = (function unprojectFunction() {
} }
return { return {
unproject(THREE, vector, camera) { unproject(THREE, vector, camera) {
const threeCamera = camera.components.camera.camera; const threeCamera = camera.components.camera.camera;
initialized = initialized || initialize(THREE); initialized = initialized || initialize(THREE);
@ -86,52 +77,46 @@ const {unproject} = (function unprojectFunction() {
vector.applyMatrix4(matrixInv); vector.applyMatrix4(matrixInv);
return localToWorld(THREE, threeCamera, vector); return localToWorld(THREE, threeCamera, vector);
}, },
}; };
}()); })();
const {screenCoordsToDirection} = (function screenCoordsToDirectionFunction() { const { screenCoordsToDirection } =
(function screenCoordsToDirectionFunction() {
let initialized = false;
let initialized = false; let mousePosAsVec3;
let cameraPosAsVec3;
let mousePosAsVec3; function initialize(THREE) {
let cameraPosAsVec3; mousePosAsVec3 = new THREE.Vector3();
cameraPosAsVec3 = new THREE.Vector3();
function initialize(THREE) { return true;
mousePosAsVec3 = new THREE.Vector3(); }
cameraPosAsVec3 = new THREE.Vector3();
return true; return {
} screenCoordsToDirection(THREE, aframeCamera, { x: clientX, y: clientY }) {
initialized = initialized || initialize(THREE);
return { // scale mouse coordinates down to -1 <-> +1
screenCoordsToDirection( const scene = document.querySelector("a-scene");
THREE, const bounds = scene.canvas.getBoundingClientRect();
aframeCamera, const left = clientX - bounds.left;
{x: clientX, y: clientY}, const top = clientY - bounds.top;
) { const mouseX = (left / bounds.width) * 2 - 1;
const mouseY = -((top / bounds.height) * 2) + 1;
initialized = initialized || initialize(THREE); mousePosAsVec3.set(mouseX, mouseY, -1);
const projectedVector = unproject(THREE, mousePosAsVec3, aframeCamera);
cameraPositionToVec3(aframeCamera, cameraPosAsVec3);
// scale mouse coordinates down to -1 <-> +1 // Get the unit length direction vector from the camera's position
const scene = document.querySelector('a-scene'); const { x, y, z } = projectedVector.sub(cameraPosAsVec3).normalize();
const bounds = scene.canvas.getBoundingClientRect(); return { x, y, z };
const left = clientX - bounds.left; },
const top = clientY - bounds.top; };
const mouseX = ((left / bounds.width) * 2) - 1; })();
const mouseY = -((top / bounds.height) * 2) + 1;
mousePosAsVec3.set(mouseX, mouseY, -1);
const projectedVector = unproject(THREE, mousePosAsVec3, aframeCamera);
cameraPositionToVec3(aframeCamera, cameraPosAsVec3);
// Get the unit length direction vector from the camera's position
const {x, y, z} = projectedVector.sub(cameraPosAsVec3).normalize();
return {x, y, z};
},
};
}());
/** /**
* @param planeNormal {THREE.Vector3} * @param planeNormal {THREE.Vector3}
@ -146,8 +131,7 @@ function rayPlaneIntersection(planeNormal, planeConstant, rayDirection) {
return rayDirection.multiplyScalar(distanceToPlane); return rayDirection.multiplyScalar(distanceToPlane);
} }
const {directionToWorldCoords} = (function directionToWorldCoordsFunction() { const { directionToWorldCoords } = (function directionToWorldCoordsFunction() {
let initialized = false; let initialized = false;
let direction; let direction;
@ -171,33 +155,33 @@ const {directionToWorldCoords} = (function directionToWorldCoordsFunction() {
THREE, THREE,
aframeCamera, aframeCamera,
camera, camera,
{x: directionX, y: directionY, z: directionZ}, { x: directionX, y: directionY, z: directionZ },
depth, depth
) { ) {
initialized = initialized || initialize(THREE); initialized = initialized || initialize(THREE);
cameraPositionToVec3(aframeCamera, cameraPosAsVec3); cameraPositionToVec3(aframeCamera, cameraPosAsVec3);
direction.set(directionX, directionY, directionZ); direction.set(directionX, directionY, directionZ);
let camerasWorldDirection = new THREE.Vector3();
camera.getWorldDirection(camerasWorldDirection);
// A line from the camera position toward (and through) the plane // A line from the camera position toward (and through) the plane
const newPosition = rayPlaneIntersection( const newPosition = rayPlaneIntersection(
camera.getWorldDirection(), camerasWorldDirection,
depth, depth,
direction, direction
); );
// Reposition back to the camera position // Reposition back to the camera position
const {x, y, z} = newPosition.add(cameraPosAsVec3); const { x, y, z } = newPosition.add(cameraPosAsVec3);
return {x, y, z};
return { x, y, z };
}, },
}; };
}()); })();
const {selectItem} = (function selectItemFunction() {
const { selectItem } = (function selectItemFunction() {
let initialized = false; let initialized = false;
let cameraPosAsVec3; let cameraPosAsVec3;
@ -220,14 +204,13 @@ const {selectItem} = (function selectItemFunction() {
return { return {
selectItem(THREE, selector, camera, clientX, clientY) { selectItem(THREE, selector, camera, clientX, clientY) {
initialized = initialized || initialize(THREE); initialized = initialized || initialize(THREE);
const {x: directionX, y: directionY, z: directionZ} = screenCoordsToDirection( const {
THREE, x: directionX,
camera, y: directionY,
{x: clientX, y: clientY}, z: directionZ,
); } = screenCoordsToDirection(THREE, camera, { x: clientX, y: clientY });
cameraPositionToVec3(camera, cameraPosAsVec3); cameraPositionToVec3(camera, cameraPosAsVec3);
directionAsVec3.set(directionX, directionY, directionZ); directionAsVec3.set(directionX, directionY, directionZ);
@ -238,54 +221,60 @@ const {selectItem} = (function selectItemFunction() {
// TODO: Can we do this at some other point instead of every time a ray is // TODO: Can we do this at some other point instead of every time a ray is
// cast? Is that a micro optimization? // cast? Is that a micro optimization?
let objects = Array.from( let objects = Array.from(
camera.sceneEl.querySelectorAll(`[${selector}]`), camera.sceneEl.querySelectorAll(`[${selector}]`)
).map((object) => object.object3D); ).map((object) => object.object3D);
const recursive = true; const recursive = true;
objects = objects.filter((object) => object !== undefined); objects = objects.filter((object) => object !== undefined);
console.log('objects', objects);
const intersected = raycaster const intersected = raycaster
.intersectObjects(objects, recursive) .intersectObjects(objects, recursive)
// Only keep intersections against objects that have a reference to an entity. // Only keep intersections against objects that have a reference to an entity.
.filter((intersection) => !!intersection.object.el) .filter((intersection) => !!intersection.object.el)
// Only keep ones that are visible // Only keep ones that are visible
.filter((intersection) => intersection.object.parent.visible) .filter((intersection) => intersection.object.parent.visible)[0]; // The first element is the closest // eslint-disable-line no-unexpected-multiline
// The first element is the closest
[0]; // eslint-disable-line no-unexpected-multiline
if (!intersected) { if (!intersected) {
return {}; return {};
} }
const {point, object} = intersected; const { point, object } = intersected;
// Aligned to the world direction of the camera // Aligned to the world direction of the camera
// At the specified intersection point // At the specified intersection point
var camerasWorldDirection = new THREE.Vector3();
camera.components.camera.camera.getWorldDirection(camerasWorldDirection);
plane.setFromNormalAndCoplanarPoint( plane.setFromNormalAndCoplanarPoint(
camera.components.camera.camera.getWorldDirection().clone().negate(), camerasWorldDirection.clone().negate(),
point.clone().sub(cameraPosAsVec3), point.clone().sub(cameraPosAsVec3)
); );
const depth = plane.constant; const depth = plane.constant;
const offset = point.sub(object.getWorldPosition()); var objectsWorldPosition = new THREE.Vector3();
object.getWorldPosition(objectsWorldPosition);
return {depth, offset, element: object.el}; const offset = point.sub(objectsWorldPosition);
return { depth, offset, element: object.el };
}, },
}; };
}()); })();
function dragItem(THREE, element, offset, camera, depth, mouseInfo) { function dragItem(THREE, element, offset, camera, depth, mouseInfo) {
const threeCamera = camera.components.camera.camera; const threeCamera = camera.components.camera.camera;
// Setting up for rotation calculations // Setting up for rotation calculations
const startCameraRotationInverse = threeCamera.getWorldQuaternion().inverse(); var camerasQuaternion = new THREE.Quaternion();
const startElementRotation = element.object3D.getWorldQuaternion(); threeCamera.getWorldQuaternion(camerasQuaternion);
var objectsQuaternion = new THREE.Quaternion();
element.object3D.getWorldQuaternion(objectsQuaternion);
const startCameraRotationInverse = camerasQuaternion.invert();
const startElementRotation = objectsQuaternion;
const elementRotationOrder = element.object3D.rotation.order; const elementRotationOrder = element.object3D.rotation.order;
const rotationQuaternion = new THREE.Quaternion(); const rotationQuaternion = new THREE.Quaternion();
@ -295,31 +284,32 @@ function dragItem(THREE, element, offset, camera, depth, mouseInfo) {
let lastMouseInfo = mouseInfo; let lastMouseInfo = mouseInfo;
const nextRotation = { const nextRotation = {
x: THREE.Math.radToDeg(rotationEuler.x), x: THREE.MathUtils.radToDeg(rotationEuler.x),
y: THREE.Math.radToDeg(rotationEuler.y), y: THREE.MathUtils.radToDeg(rotationEuler.y),
z: THREE.Math.radToDeg(rotationEuler.z), z: THREE.MathUtils.radToDeg(rotationEuler.z),
}; };
const activeCamera = element.sceneEl.systems.camera.activeCameraEl; const activeCamera = element.sceneEl.systems.camera.activeCameraEl;
const isChildOfActiveCamera = someParent(element, (parent) => parent === activeCamera); const isChildOfActiveCamera = someParent(
element,
(parent) => parent === activeCamera
);
function onMouseMove({clientX, clientY}) { function onMouseMove({ clientX, clientY }) {
lastMouseInfo = { clientX, clientY };
lastMouseInfo = {clientX, clientY}; const direction = screenCoordsToDirection(THREE, camera, {
x: clientX,
y: clientY,
});
const direction = screenCoordsToDirection( const { x, y, z } = directionToWorldCoords(
THREE,
camera,
{x: clientX, y: clientY},
);
const {x, y, z} = directionToWorldCoords(
THREE, THREE,
camera, camera,
camera.components.camera.camera, camera.components.camera.camera,
direction, direction,
depth, depth
); );
let rotationDiff; let rotationDiff;
@ -330,8 +320,11 @@ function dragItem(THREE, element, offset, camera, depth, mouseInfo) {
// rotate the offset // rotate the offset
offsetVector.set(offset.x, offset.y, offset.z); offsetVector.set(offset.x, offset.y, offset.z);
var camerasQuaternion = new THREE.Quaternion();
threeCamera.getWorldQuaternion(camerasQuaternion);
// Then add the current camera rotation // Then add the current camera rotation
rotationDiff = rotationQuaternion.multiply(threeCamera.getWorldQuaternion()); rotationDiff = rotationQuaternion.multiply(camerasQuaternion);
offsetVector.applyQuaternion(rotationDiff); offsetVector.applyQuaternion(rotationDiff);
@ -342,16 +335,19 @@ function dragItem(THREE, element, offset, camera, depth, mouseInfo) {
rotationEuler.setFromQuaternion(rotationDiff, elementRotationOrder); rotationEuler.setFromQuaternion(rotationDiff, elementRotationOrder);
} }
nextRotation.x = THREE.Math.radToDeg(rotationEuler.x); nextRotation.x = THREE.MathUtils.radToDeg(rotationEuler.x);
nextRotation.y = THREE.Math.radToDeg(rotationEuler.y); nextRotation.y = THREE.MathUtils.radToDeg(rotationEuler.y);
nextRotation.z = THREE.Math.radToDeg(rotationEuler.z); nextRotation.z = THREE.MathUtils.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 // When the element has parents, we need to convert its new world position
// into new local position of its parent element // into new local position of its parent element
if (element.parentEl !== element.sceneEl) { if (element.parentEl !== element.sceneEl) {
// The new world position // The new world position
offsetVector.set(nextPosition.x, nextPosition.y, nextPosition.z); offsetVector.set(nextPosition.x, nextPosition.y, nextPosition.z);
@ -364,50 +360,51 @@ function dragItem(THREE, element, offset, camera, depth, mouseInfo) {
} }
element.emit(DRAG_MOVE_EVENT, { element.emit(DRAG_MOVE_EVENT, {
nextPosition, nextRotation, clientX, clientY, nextPosition,
nextRotation,
clientX,
clientY,
}); });
element.setAttribute('position', nextPosition); element.setAttribute("position", nextPosition);
element.setAttribute('rotation', nextRotation); element.setAttribute("rotation", nextRotation);
} }
function onTouchMove({changedTouches: [touchInfo]}) { function onTouchMove({ changedTouches: [touchInfo] }) {
onMouseMove(touchInfo); onMouseMove(touchInfo);
} }
function onCameraChange({detail}) { function onCameraChange({ detail }) {
if ( if (
(detail.name === 'position' || detail.name === 'rotation') (detail.name === "position" || detail.name === "rotation") &&
&& !deepEqual(detail.oldData, detail.newData) !deepEqual(detail.oldData, detail.newData)
) { ) {
onMouseMove(lastMouseInfo); onMouseMove(lastMouseInfo);
} }
} }
document.addEventListener('mousemove', onMouseMove); document.addEventListener("mousemove", onMouseMove);
document.addEventListener('touchmove', onTouchMove); document.addEventListener("touchmove", onTouchMove);
camera.addEventListener('componentchanged', onCameraChange); camera.addEventListener("componentchanged", onCameraChange);
// The "unlisten" function // The "unlisten" function
return (_) => { return (_) => {
document.removeEventListener('mousemove', onMouseMove); document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener('touchmove', onTouchMove); document.removeEventListener("touchmove", onTouchMove);
camera.removeEventListener('componentchanged', onCameraChange); camera.removeEventListener("componentchanged", onCameraChange);
}; };
} }
// Closure to close over the removal of the event listeners // Closure to close over the removal of the event listeners
const {didMount, didUnmount} = (function getDidMountAndUnmount() { const { didMount, didUnmount } = (function getDidMountAndUnmount() {
let removeClickListeners; let removeClickListeners;
let removeDragListeners; let removeDragListeners;
const cache = []; const cache = [];
function initialize(THREE, componentName) { function initialize(THREE, componentName) {
// 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");
// delay loading of this as we're not 100% if the scene has loaded yet or not // delay loading of this as we're not 100% if the scene has loaded yet or not
let camera; let camera;
let draggedElement; let draggedElement;
@ -416,28 +413,36 @@ const {didMount, didUnmount} = (function getDidMountAndUnmount() {
function cleanUpPositionLog() { function cleanUpPositionLog() {
const now = performance.now(); const now = performance.now();
while (positionLog.length && now - positionLog[0].time > TIME_TO_KEEP_LOG) { while (
positionLog.length &&
now - positionLog[0].time > TIME_TO_KEEP_LOG
) {
// remove the first element; // remove the first element;
positionLog.shift(); positionLog.shift();
} }
} }
function onDragged({detail: {nextPosition}}) { function onDragged({ detail: { nextPosition } }) {
// Continuously clean up so we don't get huge logs built up // Continuously clean up so we don't get huge logs built up
cleanUpPositionLog(); cleanUpPositionLog();
positionLog.push({ positionLog.push({
position: {...nextPosition}, position: { ...nextPosition },
time: performance.now(), time: performance.now(),
}); });
} }
function onMouseDown({clientX, clientY}) { function onMouseDown({ clientX, clientY }) {
const { depth, offset, element } = selectItem(
const {depth, offset, element} = selectItem(THREE, componentName, camera, clientX, clientY); THREE,
componentName,
camera,
clientX,
clientY
);
if (element) { if (element) {
// If click-drag is not enabled, return. // If click-drag is not enabled, return.
if (element.getAttribute('click-drag').enabled === 'false') { if (element.getAttribute("click-drag").enabled === "false") {
return; return;
} }
@ -452,13 +457,13 @@ const {didMount, didUnmount} = (function getDidMountAndUnmount() {
{ {
clientX, clientX,
clientY, clientY,
}, }
); );
draggedElement = element; draggedElement = element;
dragInfo = { dragInfo = {
offset: {x: offset.x, y: offset.y, z: offset.z}, offset: { x: offset.x, y: offset.y, z: offset.z },
depth, depth,
clientX, clientX,
clientY, clientY,
@ -479,7 +484,6 @@ const {didMount, didUnmount} = (function getDidMountAndUnmount() {
} }
function calculateVelocity() { function calculateVelocity() {
if (positionLog.length < 2) { if (positionLog.length < 2) {
return 0; return 0;
} }
@ -495,8 +499,7 @@ const {didMount, didUnmount} = (function getDidMountAndUnmount() {
}; };
} }
function onMouseUp({clientX, clientY}) { function onMouseUp({ clientX, clientY }) {
if (!draggedElement) { if (!draggedElement) {
return; return;
} }
@ -505,52 +508,49 @@ const {didMount, didUnmount} = (function getDidMountAndUnmount() {
const velocity = calculateVelocity(); const velocity = calculateVelocity();
draggedElement.emit( draggedElement.emit(DRAG_END_EVENT, {
DRAG_END_EVENT, ...dragInfo,
{ clientX,
...dragInfo, clientX, clientY, velocity, clientY,
}, velocity,
); });
removeDragListeners && removeDragListeners(); // eslint-disable-line no-unused-expressions removeDragListeners && removeDragListeners(); // eslint-disable-line no-unused-expressions
removeDragListeners = undefined; removeDragListeners = undefined;
} }
function onTouchStart({changedTouches: [touchInfo]}) { function onTouchStart({ changedTouches: [touchInfo] }) {
onMouseDown(touchInfo); onMouseDown(touchInfo);
} }
function onTouchEnd({changedTouches: [touchInfo]}) { function onTouchEnd({ changedTouches: [touchInfo] }) {
onMouseUp(touchInfo); onMouseUp(touchInfo);
} }
function run() { function run() {
camera = scene.camera.el; camera = scene.camera.el;
// TODO: Attach to canvas? // TODO: Attach to canvas?
document.addEventListener('mousedown', onMouseDown); document.addEventListener("mousedown", onMouseDown);
document.addEventListener('mouseup', onMouseUp); document.addEventListener("mouseup", onMouseUp);
document.addEventListener('touchstart', onTouchStart); document.addEventListener("touchstart", onTouchStart);
document.addEventListener('touchend', onTouchEnd); document.addEventListener("touchend", onTouchEnd);
removeClickListeners = (_) => { removeClickListeners = (_) => {
document.removeEventListener('mousedown', onMouseDown); document.removeEventListener("mousedown", onMouseDown);
document.removeEventListener('mouseup', onMouseUp); document.removeEventListener("mouseup", onMouseUp);
document.removeEventListener('touchstart', onTouchStart); document.removeEventListener("touchstart", onTouchStart);
document.removeEventListener('touchend', onTouchEnd); document.removeEventListener("touchend", onTouchEnd);
}; };
} }
if (scene.hasLoaded) { if (scene.hasLoaded) {
run(); run();
} else { } else {
scene.addEventListener('loaded', run); scene.addEventListener("loaded", run);
} }
} }
function tearDown() { function tearDown() {
@ -560,7 +560,6 @@ const {didMount, didUnmount} = (function getDidMountAndUnmount() {
return { return {
didMount(element, THREE, componentName) { didMount(element, THREE, componentName) {
if (cache.length === 0) { if (cache.length === 0) {
initialize(THREE, componentName); initialize(THREE, componentName);
} }
@ -571,7 +570,6 @@ const {didMount, didUnmount} = (function getDidMountAndUnmount() {
}, },
didUnmount(element) { didUnmount(element) {
const cacheIndex = cache.indexOf(element); const cacheIndex = cache.indexOf(element);
removeDragListeners && removeDragListeners(); // eslint-disable-line no-unused-expressions removeDragListeners && removeDragListeners(); // eslint-disable-line no-unused-expressions
@ -587,18 +585,19 @@ const {didMount, didUnmount} = (function getDidMountAndUnmount() {
if (cache.length === 0) { if (cache.length === 0) {
tearDown(); tearDown();
} }
}, },
}; };
}()); })();
/** /**
* @param aframe {Object} The Aframe instance to register with * @param aframe {Object} The Aframe instance to register with
* @param componentName {String} The component name to use. Default: 'click-drag' * @param componentName {String} The component name to use. Default: 'click-drag'
*/ */
export default function aframeDraggableComponent(aframe, componentName = COMPONENT_NAME) { export default function aframeDraggableComponent(
aframe,
const {THREE} = aframe; componentName = COMPONENT_NAME
) {
const { THREE } = aframe;
/** /**
* Draggable component for A-Frame. * Draggable component for A-Frame.
@ -619,7 +618,7 @@ export default function aframeDraggableComponent(aframe, componentName = COMPONE
* *
* @param oldData * @param oldData
*/ */
update() { }, update() {},
/** /**
* Called when a component is removed (e.g., via removeAttribute). * Called when a component is removed (e.g., via removeAttribute).