The idea is to make a 3d building and when you click on an apartment open on the side (each occupying half the screen) a card with some information, on devices with a width of up to 650px, the card should open overlapping the model will occupy the whole screen instead of half)
On the desktop it works as expected, but when switching to the Desktop (touch) type in the developer tools, the click event is not called
(I put console.log('teste')
and it shows nothing)
When using the mobile type in touch the three events work normally in any size but the css does not work (even on screens smaller than 650px the screen continues to split in two)
With mobile touch, neither the events of three (does not show anything in the console) nor the css works the screen continues divided in two)
I'm using the THREEx library 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>
Rotationeventsworkasexpectedonanytypeofdeviceandanyscreensize
Iremovedthecreationpartoftheapartmentsandaddedtheclickeventonlyinthebuildingsoasnottoleavethescripttoobig
Edit: