Events in three.js and CSS do not work in some languages

Asked

Viewed 60 times

0

The idea is to make a 3d prediction and when you click on an apartment to open on the side (each occupying half the screen) a card with some information, in Vices with width of up to 650px, the card should open superimposing the mock-up (both take up the entire screen instead of half)

On the desktop works as expected, but when switching to the Desktop (touch) type in the developer tools, the click event is not called (I put a console.log('teste') and shows nothing)

When lowering the screen to 650px (value of the media query in css), both the desktop touch and the no touch, the event does not work (shows nothing in the console)

When using the mobile type on touch the events of three work normally in any size but the css does not work (even on screens smaller than 650px the screen remains divided in two)

With mobile touch, neither the events of three (shows nothing in the console) nor the css works the screen is still divided into two)

I’m using the library Threex to be able to use events on objects

// - - - - - Biblioteca THREEx - - - - - 

var THREEx		= THREEx 		|| {};

// # Constructor
THREEx.DomEvents	= function(camera, domElement)
{
	this._camera	= camera || null;
	this._domElement= domElement || document;
	this._raycaster = new THREE.Raycaster();
	this._selected	= null;
	this._boundObjs	= {};
	// Bind dom event for mouse and touch
	var _this	= this;

	this._$onClick		= function(){ _this._onClick.apply(_this, arguments);		};
	this._$onDblClick	= function(){ _this._onDblClick.apply(_this, arguments);	};
	this._$onMouseMove	= function(){ _this._onMouseMove.apply(_this, arguments);	};
	this._$onMouseDown	= function(){ _this._onMouseDown.apply(_this, arguments);	};
	this._$onMouseUp	= function(){ _this._onMouseUp.apply(_this, arguments);		};
	this._$onTouchMove	= function(){ _this._onTouchMove.apply(_this, arguments);	};
	this._$onTouchStart	= function(){ _this._onTouchStart.apply(_this, arguments);	};
	this._$onTouchEnd	= function(){ _this._onTouchEnd.apply(_this, arguments);	};
	this._$onContextmenu	= function(){ _this._onContextmenu.apply(_this, arguments);	};
	this._domElement.addEventListener( 'click'	, this._$onClick	, false );
	this._domElement.addEventListener( 'dblclick'	, this._$onDblClick	, false );
	this._domElement.addEventListener( 'mousemove'	, this._$onMouseMove	, false );
	this._domElement.addEventListener( 'mousedown'	, this._$onMouseDown	, false );
	this._domElement.addEventListener( 'mouseup'	, this._$onMouseUp	, false );
	this._domElement.addEventListener( 'touchmove'	, this._$onTouchMove	, false );
	this._domElement.addEventListener( 'touchstart'	, this._$onTouchStart	, false );
	this._domElement.addEventListener( 'touchend'	, this._$onTouchEnd	, false );
	this._domElement.addEventListener( 'contextmenu', this._$onContextmenu	, false );
	
}

// # Destructor
THREEx.DomEvents.prototype.destroy	= function()
{
	// unBind dom event for mouse and touch
	this._domElement.removeEventListener( 'click'		, this._$onClick	, false );
	this._domElement.removeEventListener( 'dblclick'	, this._$onDblClick	, false );
	this._domElement.removeEventListener( 'mousemove'	, this._$onMouseMove	, false );
	this._domElement.removeEventListener( 'mousedown'	, this._$onMouseDown	, false );
	this._domElement.removeEventListener( 'mouseup'		, this._$onMouseUp	, false );
	this._domElement.removeEventListener( 'touchmove'	, this._$onTouchMove	, false );
	this._domElement.removeEventListener( 'touchstart'	, this._$onTouchStart	, false );
	this._domElement.removeEventListener( 'touchend'	, this._$onTouchEnd	, false );
	this._domElement.removeEventListener( 'contextmenu'	, this._$onContextmenu	, false );
}

THREEx.DomEvents.eventNames	= [
	"click",
	"dblclick",
	"mouseover",
	"mouseout",
	"mousemove",
	"mousedown",
	"mouseup",
	"contextmenu",
	"touchstart",
	"touchend"
];

THREEx.DomEvents.prototype._getRelativeMouseXY	= function(domEvent){
	var element = domEvent.target || domEvent.srcElement;
	if (element.nodeType === 3) {
		element = element.parentNode; // Safari fix -- see http://www.quirksmode.org/js/events_properties.html
	}
	
	//get the real position of an element relative to the page starting point (0, 0)
	//credits go to brainjam on answering http://stackoverflow.com/questions/5755312/getting-mouse-position-relative-to-content-area-of-an-element
	var elPosition	= { x : 0 , y : 0};
	var tmpElement	= element;
	//store padding
	var style	= getComputedStyle(tmpElement, null);
	elPosition.y += parseInt(style.getPropertyValue("padding-top"), 10);
	elPosition.x += parseInt(style.getPropertyValue("padding-left"), 10);
	//add positions
	do {
		elPosition.x	+= tmpElement.offsetLeft;
		elPosition.y	+= tmpElement.offsetTop;
		style		= getComputedStyle(tmpElement, null);

		elPosition.x	+= parseInt(style.getPropertyValue("border-left-width"), 10);
		elPosition.y	+= parseInt(style.getPropertyValue("border-top-width"), 10);
	} while(tmpElement = tmpElement.offsetParent);
	
	var elDimension	= {
		width	: (element === window) ? window.innerWidth	: element.offsetWidth,
		height	: (element === window) ? window.innerHeight	: element.offsetHeight
	};
	
	return {
		x : +((domEvent.pageX - elPosition.x) / elDimension.width ) * 2 - 1,
		y : -((domEvent.pageY - elPosition.y) / elDimension.height) * 2 + 1
	};
};


/********************************************************************************/
/*		domevent context						*/
/********************************************************************************/

// handle domevent context in object3d instance

THREEx.DomEvents.prototype._objectCtxInit	= function(object3d){
	object3d._3xDomEvent = {};
}
THREEx.DomEvents.prototype._objectCtxDeinit	= function(object3d){
	delete object3d._3xDomEvent;
}
THREEx.DomEvents.prototype._objectCtxIsInit	= function(object3d){
	return object3d._3xDomEvent ? true : false;
}
THREEx.DomEvents.prototype._objectCtxGet		= function(object3d){
	return object3d._3xDomEvent;
}

/********************************************************************************/
/*										*/
/********************************************************************************/

/**
 * Getter/Setter for camera
*/
THREEx.DomEvents.prototype.camera	= function(value)
{
	if( value )	this._camera	= value;
	return this._camera;
}

THREEx.DomEvents.prototype.bind	= function(object3d, eventName, callback, useCapture)
{
	console.assert( THREEx.DomEvents.eventNames.indexOf(eventName) !== -1, "not available events:"+eventName );

	if( !this._objectCtxIsInit(object3d) )	this._objectCtxInit(object3d);
	var objectCtx	= this._objectCtxGet(object3d);	
	if( !objectCtx[eventName+'Handlers'] )	objectCtx[eventName+'Handlers']	= [];

	objectCtx[eventName+'Handlers'].push({
		callback	: callback,
		useCapture	: useCapture
	});
	
	// add this object in this._boundObjs
	if( this._boundObjs[eventName] === undefined ){
		this._boundObjs[eventName]	= [];	
	}
	this._boundObjs[eventName].push(object3d);
}
THREEx.DomEvents.prototype.addEventListener	= THREEx.DomEvents.prototype.bind

THREEx.DomEvents.prototype.unbind	= function(object3d, eventName, callback, useCapture)
{
	console.assert( THREEx.DomEvents.eventNames.indexOf(eventName) !== -1, "not available events:"+eventName );

	if( !this._objectCtxIsInit(object3d) )	this._objectCtxInit(object3d);

	var objectCtx	= this._objectCtxGet(object3d);
	if( !objectCtx[eventName+'Handlers'] )	objectCtx[eventName+'Handlers']	= [];

	var handlers	= objectCtx[eventName+'Handlers'];
	for(var i = 0; i < handlers.length; i++){
		var handler	= handlers[i];
		if( callback != handler.callback )	continue;
		if( useCapture != handler.useCapture )	continue;
		handlers.splice(i, 1)
		break;
	}
	// from this object from this._boundObjs
	var index	= this._boundObjs[eventName].indexOf(object3d);
	console.assert( index !== -1 );
	this._boundObjs[eventName].splice(index, 1);
}
THREEx.DomEvents.prototype.removeEventListener	= THREEx.DomEvents.prototype.unbind

THREEx.DomEvents.prototype._bound	= function(eventName, object3d)
{
	var objectCtx	= this._objectCtxGet(object3d);
	if( !objectCtx )	return false;
	return objectCtx[eventName+'Handlers'] ? true : false;
}

/********************************************************************************/
/*		onMove								*/
/********************************************************************************/

// # handle mousemove kind of events

THREEx.DomEvents.prototype._onMove	= function(eventName, mouseX, mouseY, origDomEvent)
{
//console.log('eventName', eventName, 'boundObjs', this._boundObjs[eventName])
	// get objects bound to this event
	var boundObjs	= this._boundObjs[eventName];
	if( boundObjs === undefined || boundObjs.length === 0 )	return;
	// compute the intersection
	var vector = new THREE.Vector2();

	// update the picking ray with the camera and mouse position
	vector.set( mouseX, mouseY );
	this._raycaster.setFromCamera( vector, this._camera );	

	var intersects = this._raycaster.intersectObjects( boundObjs );

	var oldSelected	= this._selected;
	
	if( intersects.length > 0 ){
		var notifyOver, notifyOut, notifyMove;
		var intersect	= intersects[ 0 ];
		var newSelected	= intersect.object;
		this._selected	= newSelected;
		// if newSelected bound mousemove, notify it
		notifyMove	= this._bound('mousemove', newSelected);

		if( oldSelected != newSelected ){
			// if newSelected bound mouseenter, notify it
			notifyOver	= this._bound('mouseover', newSelected);
			// if there is a oldSelect and oldSelected bound mouseleave, notify it
			notifyOut	= oldSelected && this._bound('mouseout', oldSelected);
		}
	}else{
		// if there is a oldSelect and oldSelected bound mouseleave, notify it
		notifyOut	= oldSelected && this._bound('mouseout', oldSelected);
		this._selected	= null;
	}


	// notify mouseMove - done at the end with a copy of the list to allow callback to remove handlers
	notifyMove && this._notify('mousemove', newSelected, origDomEvent, intersect);
	// notify mouseEnter - done at the end with a copy of the list to allow callback to remove handlers
	notifyOver && this._notify('mouseover', newSelected, origDomEvent, intersect);
	// notify mouseLeave - done at the end with a copy of the list to allow callback to remove handlers
	notifyOut  && this._notify('mouseout' , oldSelected, origDomEvent, intersect);
}


/********************************************************************************/
/*		onEvent								*/
/********************************************************************************/

// # handle click kind of events

THREEx.DomEvents.prototype._onEvent	= function(eventName, mouseX, mouseY, origDomEvent)
{
	//console.log('eventName', eventName, 'boundObjs', this._boundObjs[eventName])
	// get objects bound to this event
	var boundObjs	= this._boundObjs[eventName];
	if( boundObjs === undefined || boundObjs.length === 0 )	return;
	// compute the intersection
	var vector = new THREE.Vector2();

	// update the picking ray with the camera and mouse position
	vector.set( mouseX, mouseY );
	this._raycaster.setFromCamera( vector, this._camera );	

	var intersects = this._raycaster.intersectObjects( boundObjs, true);
	// if there are no intersections, return now
	if( intersects.length === 0 )	return;

	// init some variables
	var intersect	= intersects[0];
	var object3d	= intersect.object;
	var objectCtx	= this._objectCtxGet(object3d);
	var objectParent = object3d.parent;

	while ( typeof(objectCtx) == 'undefined' && objectParent )
	{
	    objectCtx = this._objectCtxGet(objectParent);
	    objectParent = objectParent.parent;
	}
	if( !objectCtx )	return;

	// notify handlers
	this._notify(eventName, object3d, origDomEvent, intersect);
}

THREEx.DomEvents.prototype._notify	= function(eventName, object3d, origDomEvent, intersect)
{
	var objectCtx	= this._objectCtxGet(object3d);
	var handlers	= objectCtx ? objectCtx[eventName+'Handlers'] : null;
	
	// parameter check
	console.assert(arguments.length === 4)

	// do bubbling
	if( !objectCtx || !handlers || handlers.length === 0 ){
		object3d.parent && this._notify(eventName, object3d.parent, origDomEvent, intersect);
		return;
	}
	
	// notify all handlers
	var handlers	= objectCtx[eventName+'Handlers'];
	for(var i = 0; i < handlers.length; i++){
		var handler	= handlers[i];
		var toPropagate	= true;
		handler.callback({
			type		: eventName,
			target		: object3d,
			origDomEvent	: origDomEvent,
			intersect	: intersect,
			stopPropagation	: function(){
				toPropagate	= false;
			}
		});
		if( !toPropagate )	continue;
		// do bubbling
		if( handler.useCapture === false ){
			object3d.parent && this._notify(eventName, object3d.parent, origDomEvent, intersect);
		}
	}
}

/********************************************************************************/
/*		handle mouse events						*/
/********************************************************************************/
// # handle mouse events

THREEx.DomEvents.prototype._onMouseDown	= function(event){ return this._onMouseEvent('mousedown', event);	}
THREEx.DomEvents.prototype._onMouseUp	= function(event){ return this._onMouseEvent('mouseup'	, event);	}


THREEx.DomEvents.prototype._onMouseEvent	= function(eventName, domEvent)
{
	var mouseCoords = this._getRelativeMouseXY(domEvent);
	this._onEvent(eventName, mouseCoords.x, mouseCoords.y, domEvent);
}

THREEx.DomEvents.prototype._onMouseMove	= function(domEvent)
{
	var mouseCoords = this._getRelativeMouseXY(domEvent);
	this._onMove('mousemove', mouseCoords.x, mouseCoords.y, domEvent);
	this._onMove('mouseover', mouseCoords.x, mouseCoords.y, domEvent);
	this._onMove('mouseout' , mouseCoords.x, mouseCoords.y, domEvent);
}

THREEx.DomEvents.prototype._onClick		= function(event)
{
	// TODO handle touch ?
	this._onMouseEvent('click'	, event);
}
THREEx.DomEvents.prototype._onDblClick		= function(event)
{
	// TODO handle touch ?
	this._onMouseEvent('dblclick'	, event);
}

THREEx.DomEvents.prototype._onContextmenu	= function(event)
{
	//TODO don't have a clue about how this should work with touch..
	this._onMouseEvent('contextmenu'	, event);
}

/********************************************************************************/
/*		handle touch events						*/
/********************************************************************************/
// # handle touch events


THREEx.DomEvents.prototype._onTouchStart	= function(event){ return this._onTouchEvent('touchstart', event);	}
THREEx.DomEvents.prototype._onTouchEnd	= function(event){ return this._onTouchEvent('touchend'	, event);	}

THREEx.DomEvents.prototype._onTouchMove	= function(domEvent)
{
	if( domEvent.touches.length != 1 )	return undefined;

	domEvent.preventDefault();

	var mouseX	= +(domEvent.touches[ 0 ].pageX / window.innerWidth ) * 2 - 1;
	var mouseY	= -(domEvent.touches[ 0 ].pageY / window.innerHeight) * 2 + 1;
	this._onMove('mousemove', mouseX, mouseY, domEvent);
	this._onMove('mouseover', mouseX, mouseY, domEvent);
	this._onMove('mouseout' , mouseX, mouseY, domEvent);
}

THREEx.DomEvents.prototype._onTouchEvent	= function(eventName, domEvent)
{
	if( domEvent.touches.length != 1 )	return undefined;

	domEvent.preventDefault();

	var mouseX	= +(domEvent.touches[ 0 ].pageX / window.innerWidth ) * 2 - 1;
	var mouseY	= -(domEvent.touches[ 0 ].pageY / window.innerHeight) * 2 + 1;
	this._onEvent(eventName, mouseX, mouseY, domEvent);	
}




// - - - - - Meu Código (parte dele) - - - - - 




// Elemento em que o Three irá renderizar
const container = document.querySelector('.webgl');

// Cena
const scene	= new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
scene.rotation.y = -0.25;

// Camera
const camera = new THREE.PerspectiveCamera(45, container.clientWidth / container.clientWidth, 0.01, 1000);
camera.position.z = 30;
camera.position.y = 10;

// Renderizador
const renderer = new THREE.WebGLRenderer();
renderer.setSize(container.clientWidth, container.clientWidth);
container.appendChild(renderer.domElement);

// Eventos
const domEvents	= new THREEx.DomEvents(camera, renderer.domElement)

// Prédio
const boxGeometry = new THREE.BoxGeometry(7, 13, 7);
const material = new THREE.MeshBasicMaterial({ color: 0x85b9dd});
let edifice = new THREE.Mesh(boxGeometry, material);
edifice.position.x = 0;
edifice.position.y = 10;
edifice.position.z = 0;
scene.add(edifice);

domEvents.addEventListener(edifice, 'click', function() {
    console.log('test'); //Não mostra nada quando clica no bloco
}, false);

// Movimentação: No foco ou click das setas
const leftArrow = document.querySelector('i.left');
const rightArrow = document.querySelector('i.right');
let move = false;

leftArrow.addEventListener('click', () => {
    move = -0.03;
    setTimeout(() => move = -0.05, 100);
    setTimeout(() => move = -0.07, 200);
    setTimeout(() => move = -0.1, 300);
    setTimeout(() => move = -0.005, 400);
});
leftArrow.addEventListener('mouseover', () => move = -0.005);
leftArrow.addEventListener('mouseleave', () => move = false);

rightArrow.addEventListener('click', () => {
    move = 0.03;
    setTimeout(() => move = 0.05, 100);
    setTimeout(() => move = 0.07, 200);
    setTimeout(() => move = 0.1, 300);
    setTimeout(() => move = 0.005, 400);
});
rightArrow.addEventListener('mouseover', () => move = 0.005);
rightArrow.addEventListener('mouseleave', () => move = false);

// Inicialização da animação
(function animate() {
    requestAnimationFrame(animate);

    if(move) {
        scene.rotation.y += move;
    }

    renderer.render(scene, camera);
})();

document.querySelector('canvas').setAttribute('title', 'Clique em um apartamento para ver mais informações')

document.querySelector('.info-content button').addEventListener('click', function(event) {
    document.querySelector('.info-content').style.display = 'none';
    document.querySelector('.info-title').style.marginTop = '45vh';
});
body {
	font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
	margin: 0;
}

.model {
	display: flex;
	justify-content: space-between;
}

.webgl, .info {
	display: flex;
	flex: 1;
	flex-direction: column;
}

.info-title {
	width: 100%;
	text-align: center;
	font-size: 3rem;
	margin-top: 30vh;
   	transition: margin-top 1s ease-in-out;
}
.info-content {
	transition: display 1s ease-in-out;
	display: none;
	width: 70%;
	height: 50%;
	margin: 10% 10% 10% 10%;
	padding: 5%;
	flex-direction: column;
	background-color: #FFFFFF;
	-webkit-box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 3px 1px -2px rgba(0,0,0,0.12), 0 1px 5px 0 rgba(0,0,0,0.2);
    box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 3px 1px -2px rgba(0,0,0,0.12), 0 1px 5px 0 rgba(0,0,0,0.2);
}
.info-content h2 {
	text-align: center;
	margin-bottom: 10%;
}
.info-content p {
	margin: 5% 0;
}
.info-content button {
	background-color: transparent;
	opacity: 0.5;
	font-weight: bolder;
	border: none;
	outline: none;
	align-self: flex-end;
	position: absolute;
	font-size: 1.5rem;
}

canvas {
	height: 80vh !important;
}
.rotation {
	height: 10vh;
	width: 80%;
	margin: 5vh 10%;
	display: flex;
	order: 2;
}
.rotation span {
	flex: 1 1 0;
}
.rotation i {
    border: solid black;
    border-width: 0 15px 15px 0;
    display: inline-block;
	width: 5vh;
   	height: 5vh;
}
.rotation .right {
    transform: rotate(-45deg);
    -webkit-transform: rotate(-45deg);
}
.rotation .left {
    transform: rotate(135deg);
    -webkit-transform: rotate(135deg);
}

@media all and (max-width: 650px) {
	.info {
		position: absolute;
		top: 0;
		width: 100%;
		height: 80vh;
	}
	.info-title {
		display: none;
	}
	.info-content {
		height: 80%;
	}
}
<body>
    <div class="model">
        <div class="webgl">
            <div class="rotation">
                <i class="arrow left"></i>
                <span></span>
                <i class="arrow right"></i>
            </div>
        </div>

        <div class="info">
            <h1 class="info-title">AION</h1>
            <div class="info-content">
                <h2>Apartamento N</h2>
                <p>
                    <strong>Status:</strong> Vendido | A venda | Reservado
                </p>
                <p>
                    <strong>Tamanho:</strong> 00.0 x 00.0 x 00.0
                </p>
                <button>X</button>
            </div>
        </div>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/94/three.min.js"></script>
</body>

Rotation events work as expected on any device type and any screen size

I removed the creation part of the apartments and added the event just click on the building to not make the script too large

Edit: inserir a descrição da imagem aqui

  • Cara to thinking that his problem is with CSS. Make a test there, you can even take the model and JS, just test the layout. Put a background color on each div that will receive the content and test their responsiveness. See if these display:flex that you used and the positions are working the right way first

  • @hugocsl tested how you spoke, and, looking at Chromium’s developer tools, the css that should be applied to the elements when the screen is less than 650px do not appear, but the code was loaded and appears inside the css file in sources, some idea of what might be?

  • You put the @media rule right, There has to be the last thing in your CSS, after you write everything down at the end of everything in CSS. Forehead taking this all, try it like this @media screen and (max-width: 650x)

  • Yes it’s at the end of the file, I tried it with screen, all and without any, the three didn’t work, the strange thing is that the css doesn’t even appear in the developer tools, even if it were crossed out, at least I would know that there is something about writing

  • I think I’ve figured out your problem! It’s the div class . info that’s above the clickable element, so your click doesn’t hit the element it should. Do a simple test and put the @media (max-width: 650px) { .info {display:none } } and tries to click to see if it works

  • Yes that’s it, the problem now is to understand why css is not working, I did some more tests, and the css of media query is not only appearing on mobile device (touch and touch), the desktop works as expected

  • Dude if @media wasn’t working it wouldn’t even be displaying:None on .info. Which CSS is more precisely not working, and which element is not getting that style?

  • No style of @media ... is working, I changed the display: none; direct in developer tools

  • Here I have no way to test on mobile devices, but in my Chrome Desktop and Devtools everything is right, takes the classes and is responsive... You can try to put ! Mportant in the styles, if it doesn’t work it is because some JS is overwriting the classes by the script

  • @hugocsl unfortunately that’s not it, tested and continued in it, added a screen print for you to see what I’m seeing, both the mobile touch and the no touch happens the same if I change the device type to work (even recharging the page), testing on cell phone is equal to the second image

  • Mobile (no touch) is mobile device without Touche screen, this is exactly what you need? Your page will run on mobile NO touch screen??

  • I believe not but with touch the same error happens, not understanding what is happening, have any idea?

  • I tested it here and even No Touch it is applying the CSS, I am not using your JS on page pq tested only the layout. If even in the common mobile der problem is pq your JS is putting styles in the element

  • Strange, is it the library of the three? The only js I have to change the style of the elements change only the display of the card and the margin-top of the title (AION)

Show 9 more comments
No answers

Browser other questions tagged

You are not signed in. Login or sign up in order to post.