three-onevent
Version:
three.js Event Listener for click,gaze and so on
211 lines (200 loc) • 5.9 kB
JavaScript
(function (definition) {
"use strict";
if (!THREE) {
throw new Error("This module is dependent from 'three.js,add this file first.");
}
// CommonJS
if (typeof exports === "object" && typeof module === "object") {
module.exports = definition(THREE);
// RequireJS
} else if (typeof define === "function" && define.amd) {
define(definition);
// <script>
} else if (typeof window !== "undefined" || typeof self !== "undefined") {
// Prefer window over self for add-on scripts. Use self for
// non-windowed contexts.
var global = typeof window !== "undefined" ? window : self;
definition(THREE);
} else {
throw new Error("This environment was not anticipated by three-onEvent. Please file a bug.");
}
})(function (THREE) {
var TargetList = {
'gaze': {},
'click': {},
'hover': {}
};
var updateCallbackList = [];
var EventListeners = {},listenerList = {};
Object.keys(TargetList).forEach(function(v,i) {
EventListeners[v] = {
flag: false,
listener: function(targetList) {
listenerList[v](targetList,option.camera);
}
};
});
var option = {};
THREE.onEvent = function(scene,camera) {
option.scene = scene || {};
option.camera = camera || {};
}
THREE.onEvent.prototype.removeAll = function() {
for(var key in TargetList) {
for(var id in TargetList[key]) {
delete TargetList[key][id];
}
}
}
THREE.onEvent.prototype.update = function() {
for(var key in updateCallbackList) {
updateCallbackList[key]();
}
}
Object.assign(THREE.Object3D.prototype,{
on: function(method,callback1,callback2) {
if (EventListeners.hasOwnProperty(method)) {
TargetList[method][this.id] = {
object3d : this,
callback: Array.from(arguments).slice(1)
};
var eventlistener = EventListeners[method];
if(!eventlistener.flag){
eventlistener.flag = true;
eventlistener.listener(TargetList[method]);
}
} else {
console.warn("There is no method called '" + method + "';");
}
},
off: function(method) {
if (!!method) {
if (EventListeners.hasOwnProperty(method)) {
delete TargetList[method][this.id];
} else {
console.warn("There is no method called '" + method + "';");
}
} else {
for(var key in TargetList) {
delete TargetList[key][this.id];
}
}
}
});
function getObjList(targetList) {
var list = [];
for(var key in targetList) {
var target = targetList[key].object3d;
list.push(target);
}
return group2meshlist(list);
}
function group2meshlist(list) {
var l = [];
for (var i in list) {
if (list[i].type === 'Group') {
l = l.concat(group2meshlist(list[i].children));
} else {
l.push(list[i])
}
}
return l;
}
function getEventObj(targetList,object3d) {
return object2group(targetList,object3d);
}
function object2group(targetList,object3d) {
if(targetList[object3d.id]) {
return targetList[object3d.id];
} else {
return object2group(targetList,object3d.parent)
}
}
// WebVR object3d on gazer
listenerList.gaze = function (targetList,camera) {
var Gazing = false,targetObject,obj;
var Eye = new THREE.Raycaster();
var gazeListener = function() {
// create a gazeListener loop
if (!!targetList ) {
var list = [];
Eye.setFromCamera(new THREE.Vector2(),camera);
list = getObjList(targetList);
var intersects = Eye.intersectObjects(list);
if (intersects.length > 0) {
if(!Gazing) { //trigger once when gaze in
Gazing = true;
targetObject = intersects[0].object;
obj = getEventObj(targetList,targetObject);
if(!!obj.callback[0]) obj.callback[0](targetObject);
}
} else{
if(Gazing && !!obj.callback[1]) {
obj.callback[1](targetObject);
}
Gazing = false;
}
}
}
updateCallbackList.push(gazeListener);
}
// object3d on mouse click
listenerList.click = function (targetList,camera) {
var targetObject,obj,Click = false,Down = false;
var Mouse = new THREE.Raycaster();
function down(event) {
event.preventDefault();
if (!targetList) return;
var list = [];
Mouse.setFromCamera(new THREE.Vector2(( event.clientX / window.innerWidth ) * 2 - 1,- ( event.clientY / window.innerHeight ) * 2 + 1), camera);
list = getObjList(targetList);
var intersects = Mouse.intersectObjects(list);
if (intersects.length > 0) { // mouse down trigger
if (Click) return;
Click = true;
targetObject = intersects[0].object;
obj = getEventObj(targetList,targetObject);
} else {
Click = false;
}
}
function move(event) {
event.preventDefault();
// disable click trigger when mouse moving
if (Click) Click = false;
}
function up(event) {
event.preventDefault();
if (Click && !!obj.callback[0]) obj.callback[0](targetObject);
Click = false;
}
window.addEventListener('mousedown',down,false);
window.addEventListener('mousemove',move,false);
window.addEventListener('mouseup',up,false);
}
// object3d on mouse hover
listenerList.hover = function (targetList,camera) {
var targetObject,obj,Hover = false;
var Mouse = new THREE.Raycaster();
window.addEventListener('mousemove',function(event) {
event.preventDefault();
if (!targetList) return;
var list = [];
Mouse.setFromCamera(new THREE.Vector2(( event.clientX / window.innerWidth ) * 2 - 1,- ( event.clientY / window.innerHeight ) * 2 + 1), camera);
list = getObjList(targetList);
var intersects = Mouse.intersectObjects(list);
if (intersects.length > 0) {
if (Hover) return;
Hover = true;
targetObject = intersects[0].object;
obj = getEventObj(targetList,targetObject);
if(!!obj.callback[0]) obj.callback[0](targetObject);
} else {
if(Hover && !!obj.callback[1]) {
obj.callback[1](targetObject);
}
Hover = false;
}
}, false)
}
});