170 lines
4.2 KiB
JavaScript
170 lines
4.2 KiB
JavaScript
L3D.ObjectClicker = (function() {
|
|
|
|
function pointerCheck(camera) {
|
|
return (camera instanceof L3D.PointerCamera && camera.pointerLocked);
|
|
}
|
|
|
|
/**
|
|
* Class to allow easy object clicking
|
|
* @constructor
|
|
* @memberof L3D
|
|
* @param renderer {THREE.Renderer} the renderer
|
|
* @param camera {THREE.Camera} the camera to use
|
|
* @param objects {Object[]} the objects on which the collision is possible
|
|
* @param onHover {function} callback called when the mouse hovers an object
|
|
* @param onClick {function} callback called when the user clicks an object
|
|
* @param [domElement=document] {Element} element to which ObjectClicker listens to
|
|
*/
|
|
var ObjectClicker = function(renderer, camera, objects, onHover, onClick, domElement) {
|
|
|
|
/**
|
|
* Renderer used
|
|
* @type {THREE.Renderer}
|
|
*/
|
|
this.renderer = renderer;
|
|
|
|
/**
|
|
* Objects on which the collision is possible
|
|
* @type {Object[]}
|
|
*/
|
|
this.objects = objects;
|
|
|
|
/**
|
|
* Function called when the mouse hovers an object
|
|
* @type {function}
|
|
*/
|
|
this.onHover = onHover;
|
|
|
|
/**
|
|
* Function called when the user clicks on an object
|
|
* @type {function}
|
|
*/
|
|
this.onClick = onClick;
|
|
|
|
/**
|
|
* Camera used for ray casting
|
|
* @type {THREE.Camera}
|
|
*/
|
|
this.camera = camera;
|
|
|
|
/**
|
|
* Position of the mouse
|
|
* @type {Object}
|
|
*/
|
|
this.mouse = {x: null, y: null};
|
|
|
|
/**
|
|
* Element on which we will listen
|
|
* @type {Element}
|
|
*/
|
|
this.domElement = domElement || document;
|
|
|
|
/**
|
|
* Element currently hovered
|
|
* @type {Object}
|
|
*/
|
|
this.hoveredElement = null;
|
|
|
|
/**
|
|
* Raycaster used for finding the objects
|
|
* @private
|
|
* @type {THREE.Raycaster}
|
|
*/
|
|
this.raycaster = new THREE.Raycaster();
|
|
|
|
/**
|
|
* Currently pointed object
|
|
* @type {Object}
|
|
*/
|
|
this.currentPointedObject = null;
|
|
|
|
/**
|
|
* Previously pointed object
|
|
* @type {Object}
|
|
*/
|
|
this.previousPointedObject = null;
|
|
|
|
// Add event listeners
|
|
var self = this;
|
|
this.domElement.addEventListener('mousemove', function(event) { self.update(event); });
|
|
this.domElement.addEventListener('click', function(event) { self.click(event); });
|
|
|
|
};
|
|
|
|
/**
|
|
* Returns the object pointed by the mouse
|
|
*/
|
|
ObjectClicker.prototype.getPointedObject = function() {
|
|
|
|
// Compute x and y for unprojection
|
|
var x = ( this.mouse.x / this.renderer.domElement.width ) * 2 - 1;
|
|
var y = - (this.mouse.y / this.renderer.domElement.height) * 2 + 1;
|
|
|
|
if (pointerCheck(this.camera)) {
|
|
|
|
x = 0;
|
|
y = 0;
|
|
|
|
}
|
|
|
|
var vector = new THREE.Vector3(x,y,0.5);
|
|
vector.unproject(this.camera);
|
|
|
|
// Set raycaster
|
|
this.raycaster.set(this.camera.position, vector.sub(this.camera.position).normalize());
|
|
|
|
// Compute intersections
|
|
var intersects = this.raycaster.intersectObjects(this.objects, false);
|
|
|
|
// Avoid non-raycastable objects
|
|
for (var i = 0; i < intersects.length && !intersects[i].object.raycastable; i++){};
|
|
|
|
// Objects are sorted by distance in intersects, the best is the first
|
|
return intersects[i] !== undefined ? intersects[i].object : undefined;
|
|
|
|
};
|
|
|
|
/**
|
|
* Updates the position of the mouse and the hovered object and calls onHover
|
|
* @param event {Event} the event received by 'mousemove'
|
|
*/
|
|
ObjectClicker.prototype.update = function(event) {
|
|
|
|
// Set mouse position
|
|
if (event !== undefined) {
|
|
|
|
this.mouse.x = event.offsetX || event.layerX;
|
|
this.mouse.y = event.offsetY || event.layerY;
|
|
|
|
}
|
|
|
|
// Update current pointed object
|
|
this.previousPointedObject = this.currentPointedObject;
|
|
this.currentPointedObject = this.getPointedObject();
|
|
|
|
// If those two objects are different, call onHover
|
|
if (this.previousPointedObject !== this.currentPointedObject) {
|
|
var p = pointerCheck(this.camera);
|
|
this.onHover(
|
|
this.currentPointedObject,
|
|
p ? this.renderer.domElement.width / 2 : this.mouse.x,
|
|
p ? this.renderer.domElement.height / 2 : this.mouse.y
|
|
);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
/**
|
|
* Calls onClick on the current pointed element
|
|
*/
|
|
ObjectClicker.prototype.click = function() {
|
|
|
|
this.onClick(this.currentPointedObject, this.mouse.x, this.mouse.y);
|
|
|
|
}
|
|
|
|
return ObjectClicker;
|
|
|
|
})();
|