我正在尝试让用户使用标准的CTRL-click选择多个three.js对象。单选是完美的。在进行CTRL点击时,我得到了我无法理解的行为。我在SELECTED数组中得到重复的条目,当我单击第二个对象时,有时会将其添加到数组中,有时则不会。并非SELECTED数组中的每个项都应用了转换...我甚至无法理解我得到的结果。我认为这个问题在某种程度上与if ( event.type === 'click' && event.ctrlKey )
函数中mouseEventHandler()
语句中的语句逻辑有关,但我无法弄清楚我做错了什么。
这是我的相关代码:
var ray = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var INTERSECTED; // Object closest to the camera
var SELECTED = []; // Object selected via dblclick
function onMouse( event ) {
event.preventDefault();
// calculate mouse position in normalized device coordinates
// (-1 to +1) for both components
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
mouseEventHandler( event );
}
function mouseEventHandler( event /* , fn, revFn */ ){
// update the picking ray with the camera and mouse position
ray.setFromCamera( mouse, entities.cameras.perspCamera );
// calculate objects intersecting the picking ray
var intersects = ray.intersectObjects( scene.children );
// if there's at least one intersected object...
if ( intersects && intersects[0] && intersects[0].object ){
// Check if the event is a mouse move, INTERSECTED exists and we're sitting on the same INTERSECTED object as the last time this function ran...
if ( event.type === 'mousemove' ){
// Check if the current top-level intersected object is the previous INTERSECTED
if ( intersects[ 0 ].object != INTERSECTED ){
// ... if there is a previous INTERSECTED
if ( INTERSECTED ) {
// restore the previous INTERSECTED to it's previous state.
unTransformGraphElementOnMouseOut( INTERSECTED );
}
// set the currently intersected object to INTERSECTED
INTERSECTED = intersects[ 0 ].object;
// and transform it accordingly.
transformGraphElementOnMouseOver( INTERSECTED );
}
}
if ( event.type === 'click' && event.ctrlKey ){
// If there's an INTERSECTED object that's a GraphElement
var intersectedIsGraphElement = INTERSECTED && INTERSECTED.isGraphElement;
var selectedIncludesIntersected = SELECTED && SELECTED.includes( INTERSECTED );
var selectedDoesntIncludeIntersected = SELECTED && !SELECTED.includes( INTERSECTED );
if ( !INTERSECTED || !INTERSECTED.isGraphElement ){
return;
}
if ( intersectedIsGraphElement ) {
// If SELECTED includes INTERSECTED, leave it alone.
if ( selectedIncludesIntersected ) {
return;
}
// If SELECTED doesn't include INTERSECTED, transform it and add it.
else if ( selectedDoesntIncludeIntersected ) {
SELECTED.push( INTERSECTED );
transformGraphElementOnSelect( INTERSECTED );
console.log( SELECTED );
}
}
}
if ( event.type === 'click' ){ // If CTRL isn't clicked
// If there's no INTERSECTED or the INTERSECTED isn't a GraphElement
if ( !INTERSECTED || !INTERSECTED.isGraphElement ){
// If there's a SELECTED Array
if ( SELECTED ){
// for all elements in the SELECTED array
for ( var s = 0; s < SELECTED.length; s++ ){
// restore them to their unselected state.
unTransformGraphElementOnUnselect( SELECTED[ s ] );
}
// and purge the SELECTED array.
SELECTED = [];
}
}
// IF there's an INTERSECTED and it's a GraphElement
if ( INTERSECTED && INTERSECTED.isGraphElement ){
// If there's a SELECTED array
if ( SELECTED ){
// If that SELECTED array includes the currently INTERSECTED object
if ( SELECTED.includes ( INTERSECTED ) ) {
// Negative for loop -- untransform and remove from SELECTED everything but the INTERSECTED object
for ( var s = 0; s < SELECTED.length; s++ ){
if ( SELECTED[ s ] !== INTERSECTED ){
unTransformGraphElementOnUnselect( SELECTED[ s ] );
SELECTED.splice( s, 1 );
}
}
}
else {
for ( var s = 0; s < SELECTED.length; s++ ){
unTransformGraphElementOnUnselect( SELECTED[ s ] );
}
SELECTED = [];
}
}
transformGraphElementOnSelect( INTERSECTED );
SELECTED.push( INTERSECTED );
}
}
// Check if the mouse event is a wheel event (This is temporary, just to see if we can save a file with the change. We're also going to make it so that the change happens at the level of the graphElement itself, and not just the displayObject )
if ( event.type === 'wheel' ){
if ( intersects[ 0 ].object.isGraphElement && intersects[ 0 ].object === INTERSECTED ){
// transform on wheel.
transformGraphElementOnWheel( INTERSECTED );
}
}
INTERSECTED && console.log( 'INTERSECTED.isGraphElement: ', INTERSECTED.isGraphElement, 'MouseEvent: ', event.type );
}
}
function transformGraphElementOnMouseOver( obj ){
if ( obj.isGraphElement ) { obj.referent.transformOnMouseOver(); }
}
function unTransformGraphElementOnMouseOut( obj ){
if ( obj.isGraphElement ) { obj.referent.transformOnMouseOut(); }
}
function transformGraphElementOnSelect( obj ){
if ( obj.isGraphElement ) { obj.referent.transformOnDblClick(); }
}
function unTransformGraphElementOnUnselect( obj ){
if ( obj.isGraphElement ) { obj.referent.unTransformOnDblClickOutside(); }
}
function transformGraphElementOnWheel( obj ){
if ( obj.isGraphElement ) { obj.referent.transformOnWheel(); }
}
function listenFor(){
document.getElementById('visualizationContainer').addEventListener( 'click', onMouse, false );
document.getElementById('visualizationContainer').addEventListener( 'mousemove', onMouse, false );
document.getElementById('visualizationContainer').addEventListener( 'mousedown', onMouse, false );
document.getElementById('visualizationContainer').addEventListener( 'dblclick', onMouse, false )
document.getElementById('visualizationContainer').addEventListener( 'wheel', onMouse, false );
document.getElementById('visualizationContainer').addEventListener( 'contextmenu', onMouse, false );
}
listenFor();
答案 0 :(得分:0)
@marekful谢谢你。你的提示是解决方案的一部分,并帮助我揭开其余部分。我的问题的第二部分是我在for循环中运行的splice动作在我循环遍历它们时改变了数组索引,从而使for循环短路。最后,重复发生是因为我在完成处理后将INTERSECTED推回到SELECTED数组中,无论SELECTED是否包括INTERSECTED。
我的代码还有另一个问题 - 当我点击天空时,没有找到任何对象,没有注册点击。但我不认为这与我的问题的范围有关,这似乎已得到解决。这是我mouseEventHandler():
function mouseEventHandler( event /* , fn, revFn */ ){
// update the picking ray with the camera and mouse position
ray.setFromCamera( mouse, entities.cameras.perspCamera );
// calculate objects intersecting the picking ray
var intersects = ray.intersectObjects( scene.children );
// if there's at least one intersected object...
if ( intersects && intersects[0] && intersects[0].object ){
// Check if the event is a mouse move, INTERSECTED exists and we're sitting on the same INTERSECTED object as the last time this function ran...
if ( event.type === 'mousemove' ){
// Check if the current top-level intersected object is the previous INTERSECTED
if ( intersects[ 0 ].object != INTERSECTED ){
// ... if there is a previous INTERSECTED
if ( INTERSECTED ) {
// restore the previous INTERSECTED to it's previous state.
unTransformGraphElementOnMouseOut( INTERSECTED );
}
// set the currently intersected object to INTERSECTED
INTERSECTED = intersects[ 0 ].object;
// and transform it accordingly.
transformGraphElementOnMouseOver( INTERSECTED );
}
}
if ( event.type === 'click' ){
if ( event.ctrlKey ){
// If there's an INTERSECTED object that's a GraphElement
var intersectedIsGraphElement = INTERSECTED && INTERSECTED.isGraphElement;
var selectedIncludesIntersected = SELECTED && SELECTED.includes( INTERSECTED );
var selectedDoesntIncludeIntersected = SELECTED && !SELECTED.includes( INTERSECTED );
if ( !INTERSECTED || !INTERSECTED.isGraphElement ){
return;
}
if ( intersectedIsGraphElement ) {
// If SELECTED includes INTERSECTED, leave it alone.
if ( selectedIncludesIntersected ) {
return;
}
// If SELECTED doesn't include INTERSECTED, transform it and add it.
else if ( selectedDoesntIncludeIntersected ) {
SELECTED.push( INTERSECTED );
transformGraphElementOnSelect( INTERSECTED );
console.log( SELECTED );
}
}
}
else if ( !event.ctrlKey ){ // If CTRL isn't clicked
// If there's no INTERSECTED or the INTERSECTED isn't a GraphElement
if ( !INTERSECTED || !INTERSECTED.isGraphElement ){
// If there's a SELECTED Array
if ( SELECTED ){
// for all elements in the SELECTED array
for ( var s = 0; s < SELECTED.length; s++ ){
// restore them to their unselected state.
unTransformGraphElementOnUnselect( SELECTED[ s ] );
}
// and purge the SELECTED array.
SELECTED = [];
}
}
// IF there's an INTERSECTED and it's a GraphElement
if ( INTERSECTED && INTERSECTED.isGraphElement ){
// If there's a SELECTED array
if ( SELECTED ){
// If that SELECTED array includes the currently INTERSECTED object
if ( SELECTED.includes ( INTERSECTED ) ) {
// Negative for loop -- untransform and remove from SELECTED everything but the INTERSECTED object
for ( var s = 0; s < SELECTED.length; s++ ){
if ( SELECTED[ s ] !== INTERSECTED ){
unTransformGraphElementOnUnselect( SELECTED[ s ] );
}
}
SELECTED = [ INTERSECTED ];
console.log( SELECTED );
}
else {
for ( var s = 0; s < SELECTED.length; s++ ){
unTransformGraphElementOnUnselect( SELECTED[ s ] );
}
SELECTED = [];
transformGraphElementOnSelect( INTERSECTED );
SELECTED.push( INTERSECTED );
}
}
}
}
}
// Check if the mouse event is a wheel event (This is temporary, just to see if we can save a file with the change. We're also going to make it so that the change happens at the level of the graphElement itself, and not just the displayObject )
if ( event.type === 'wheel' ){
if ( intersects[ 0 ].object.isGraphElement && intersects[ 0 ].object === INTERSECTED ){
// transform on wheel.
transformGraphElementOnWheel( INTERSECTED );
}
}
INTERSECTED && console.log( 'INTERSECTED.isGraphElement: ', INTERSECTED.isGraphElement, 'MouseEvent: ', event.type );
}
}