@learn-hunger/visual-gestures
Version:
VisualGestures.js is a package that empowers users to effortlessly control the cursor, including actions such as hover, click, drag, and drop, through precise finger movements in the air.
158 lines • 6.49 kB
JavaScript
import { DefaultConfig } from "./app/config/defalut-config";
import { AVgCommon } from "./app/shared/vg-cursor-pointer-abstract";
import { VgPointer } from "./app/pointer/custom-events";
import { VgHandLandmarksDTO } from "./app/pointer/DTO/vg-handlandmark";
/**
* Central Class to Hold all kinds of gestures such as hand for now and
* may be audio gestures for future
*/
export class VisualGestures extends AVgCommon {
constructor(container = DefaultConfig.instance.cursorContainer, pointer = DefaultConfig.instance.pointer) {
super(container);
//initialise the central hand gesture class
this.mouseEvents = new VgPointer();
//initialise the constant properties of the cursor etc
this.props = {
pointer: {
keypoint: pointer,
currentLandmark: DefaultConfig.instance.cursorPosition,
},
cursorElement: this.cursor,
cursorSpeed: 1,
};
this.props.element = {};
}
/**
* here common properties gets updated whenever landmarks gets detected
* on each frame
* @private
* @type {{}}
*/
set setLandmarks(landmarks) {
if (landmarks.length > 0) {
this.props.previousLandmarks = this.props.currentLandmarks;
this.props.currentLandmarks = landmarks;
this.props.previousStructuredLandmarks = this.props.structuredLandmarks;
this.props.structuredLandmarks = new VgHandLandmarksDTO(landmarks);
this.props.pointer.previousLandmark = this.props.pointer.currentLandmark;
this.props.pointer.currentLandmark =
landmarks[this.props.pointer.keypoint];
//update delta landmarks of pointer
this.props.pointer.deltaLandmark = (() => {
const prev = this.props.pointer.previousLandmark
? this.props.pointer.previousLandmark
: { x: 0, y: 0, z: 0 };
const { x, y, z } = this.props.pointer.currentLandmark;
const deltaLandmarks = {
x: x - prev.x,
y: y - prev.y,
z: z - prev.z,
};
return deltaLandmarks;
})();
//update delta landmarks of all landmarks
this.props.deltaLandmarks = this.props.currentLandmarks.map((i, index) => {
const prev = this.props.previousLandmarks
? this.props.previousLandmarks[index]
: { x: 0, y: 0, z: 0 };
const { x, y, z } = i;
const deltaLandmarks = {
x: x - prev.x,
y: y - prev.y,
z: z - prev.z,
};
return deltaLandmarks;
});
}
}
/**
* Calculates and normalizes the position of the cursor position
* to fit within the viewport of the container element
* called only when landmarks got detected
* @private
* @readonly
* @type {MouseEventInit}
*/
get mouseInit() {
let { x: pointerX, y: pointerY } = this.props.pointer.currentLandmark;
const { clientWidth: cursorX, clientHeight: cursorY } = this.sizes.cursor;
const { clientWidth: containerX, clientHeight: containerY } = this.sizes.container;
//normalise x ,y to 0-1
//here x is 1 to 0 from left to right wrt screen
const speed = this.props.cursorSpeed;
// const temp=pointerX
pointerX = pointerX * speed > 1 ? 1 : pointerX * speed;
pointerX = pointerX * speed < 0 ? 0 : pointerX * speed;
pointerY = pointerY * speed < 0 ? 0 : pointerY * speed;
pointerY = pointerY * speed > 1 ? 1 : pointerY * speed;
//TODO Z axis
//screen wise normalisation to fit into view port lower boundaries
//right operator here is to make the cursor inside the viewport of upper boundaries
const clientX = Math.min(Math.max((1 - pointerX) * containerX, 0), containerX - cursorX);
const clientY = Math.min(Math.max(pointerY * containerY, 0), containerY - cursorY);
const m = {
clientX: clientX,
clientY: clientY,
};
return m;
}
/**
* It assigns the timestamp of the current frame and previous frame
* which will be used in core logic of the gestures in vgPointer class
* @private
* @type {number}
*/
set setTimer(timeStamp) {
if (!this.props.time) {
//setting the initial timestamps ie timer at first frame
this.props.time = {
deltaTime: timeStamp,
timeStamp: timeStamp,
};
return;
}
//timestamps after first frame
this.props.time.deltaTime = timeStamp - this.props.time.timeStamp;
this.props.time.timeStamp = timeStamp;
}
/**
* This is the handler which gets called by the end developer
* based on the handlandmarks detected setLandmarks and mouseInit gets called
* Timer gets called every time to update the timestamp irrespective of handlandmarks detected or not
* @param landmark
* @param timeStamp
* @param cursorSpeed
*/
detect(landmark, timeStamp, cursorSpeed = 1) {
this.setTimer = timeStamp;
if (landmark) {
//update landmarks and cursor position and delta landmarks as per detected landmarks
this.setLandmarks = landmark;
/**
* callibrate with cursor sizes in the first frame
* call actual detection only after the first frame
* in first frame no events get fired
*/
const isCallibrated = this.props.sizes;
if (isCallibrated) {
try {
this.props.cursorSpeed = cursorSpeed;
this.mouseEvents.updateProps(this.mouseInit, this.props);
}
catch (err) {
console.log(err);
}
}
else {
//first frame callibration
this.initialiseSizes();
this.props.sizes = this.sizes;
}
}
else {
//whenever landmarks are not detected , reset the states in vgPointer class
this.mouseEvents.resetStatesOnNoLandmarks();
}
}
}
//# sourceMappingURL=index.js.map