So I have the raycaster set up with mousemove to change the cursor It works great!
However it only works as intended when the mouse is either over the model or over the box themselves if you hover into blank space where there is nothing it kind of breaks and an undefined error occurs… So if I am hovering over the box which changes the cursor to a pointer and then move off it but the mouse then hovers over the model behind the box it works and the cursor changes to auto but if I hover into blank space after hovering on the box where there is nothing the cursor still remains a pointer instead of changing to auto
function onDocumentMouseMove(event) {
event.preventDefault();
var mouse = new THREE.Vector2();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(scene.children, true);
if (intersects[0].object.name == 'MaBox') {
container.style.cursor = 'pointer';
console.log('Mouse is over')
} else {
container.style.cursor = 'auto';
console.log('Mouse is off')
}
}
Error:
Uncaught TypeError: Cannot read property ‘object’ of undefined at
HTMLDocument.onDocumentMouseMove
Any suggestions?
You need to check that the array of intersects is not empty. Otherwise, there is no element of index 0.
Something like this:
var intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) { // check the array
if (intersects[0].object.name == 'MaBox') {
container.style.cursor = 'pointer';
console.log('Mouse is over')
} else {
container.style.cursor = 'auto';
console.log('Mouse is off')
}
}
Related
in my three.js scene I have 4 floors made using THREE.BoxGeometry. The floor's textures can be changed easily by right clicking on the individual floors and selecting an option from the div menu that appears.
My menu is on the html as:
<div id="menu" style="position:absolute;display:none;background-color:red">
<span id="menuTitle" color="blue">menu</span>
<br>
<button id="35">Black Floor</button><br>
<button id="36">Wood Floor</button><br>
<button id="37">Blue Floor</button><br>
<button id="38">Grey Floor</button>
</div>
my mouseDown function is as follows:
function onMouseDown(event) {
event.preventDefault();
var rightclick;
if (!event) var event = window.event;
if (event.which) rightclick = (event.which == 3);
else if (event.button) rightclick = (event.button == 2);
if (!rightclick) return;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects([floor1, floor2, floor3, floor4]);
if (intersects.length) {
intersect = intersects[0].object;
menu.style.left = (event.clientX - rect.left) + "px";
menu.style.top = (event.clientY - rect.top) + "px";
document.getElementById("menuTitle").innerHTML = intersects[0].name;
menu.style.display = "";
}
else{
intersect = undefined;
}
}
What I'm trying to do is change the inner HTML of "menuTitle" to floor1 when floor1 is right clicked (currently I'm getting "undefined") or better still a particular string (e.g. "Floor 1" when floor 1 is right clicked).
Thank You! :)
There is a small error in your code, instead of
document.getElementById("menuTitle").innerHTML = intersects[0].name;
it should be
document.getElementById("menuTitle").innerHTML = intersect.name;
The intersect objects in the returned array are not the same as the Object3D
So I am currently trying to create a notebook styled module for a web application. Currently it is working perfectly fine with its mouse event but not when using touch events.
//TOUCH LISTENER
theCanvas.addEventListener("touchstart", startT, false);
theCanvas.addEventListener("touchend", endT, false);
theCanvas.addEventListener("touchmove", moveT, false);
//MOUSE LISTENER
theCanvas.addEventListener("mousedown", start);
theCanvas.addEventListener("mouseup", end);
theCanvas.addEventListener("mousemove", move, false);
//MOUSE EVENTS
function start(event) {
if (event.button === MAIN_MOUSE_BUTTON) {
shouldDraw = true;
setLineProperties(theContext);
theContext.beginPath();
let elementRect = event.target.getBoundingClientRect();
theContext.moveTo(event.clientX - elementRect.left, event.clientY - elementRect.top);
console.log(PenType(mode));
}
}
function end(event) {
if (event.button === MAIN_MOUSE_BUTTON) {
shouldDraw = false;
}
}
function move(event) {
if (shouldDraw) {
let elementRect = event.target.getBoundingClientRect();
theContext.lineTo(event.clientX - elementRect.left, event.clientY - elementRect.top);
theContext.stroke()
}
}
//TOUCH EVENTS
function startT(event) {
event.preventDefault();
shouldDraw = true;
setLineProperties(theContext);
theContext.beginPath();
let elementRect = event.target.getBoundingClientRect();
theContext.moveTo(event.clientX - elementRect.left, event.clientY - elementRect.top);
console.log(PenType(mode));
}
function endT(event) {
if (event.touches.length == 1) {
event.preventDefault();
shouldDraw = false;
}
}
function moveT(event) {
if (shouldDraw) {
event.preventDefault();
let elementRect = event.target.getBoundingClientRect();
theContext.lineTo(event.clientX - elementRect.left, event.clientY - elementRect.top);
theContext.stroke()
}
}
While the mouse event is fully functional and allow drawing on the canvas. The touch events has only the a small space near the left and top border of the canvas that can be drawn on, and it is only when u tap on the border, just a dot. It should have worked like the mouse event
Since touch event can handle multiple touch points, the x and y of the fingers are not described by event.clientX and event.clientY like for mouse. Instead you got event.touches which is an array of coordinates. So in your code, everytime you want to handle touch event, just replace event.clientX by event.touches[0].clientX and event.clientY by event.touches[0].clientY (considering you only want to handle one finger of course)
I have made a fiddle here and I am using Chrome.
I want to drag the red dashed/dotted line on the left to the right. A new flex column is added on mouseup OR when you exceed a part of the container, depending on the number of columns already added. For now I just try to add max 5 columns.
The first "drag" works as expected
mouse down
while holding mousedown drag to right
column is added on mouseup or when exceeding some width
Now I want to repeat these steps and add another one. But now the behaviour is different:
mouse down
drag it to the right but it gets stuck
I have to release the mouse button and move to the right and get out of the function
Here is some code, I've tried some stuff with bubble true or false on the eventlisteners but no luck. Should I use other events?
var container = document.querySelector('.js-flex-container'),
containerRow = container.querySelector('.js-flex-row'),
oldX = 0,
oldY = 0,
rect = container.getBoundingClientRect(),
mouseupEvent = new MouseEvent('mouseup'),
newDiv,
colCount,
captureMouseMove = function captureMouseMove(event){
var directionX = 0,
directionY = 0;
if ((event.clientX - rect.left) > oldX) {
// "right"
newDiv.style.width = oldX + 'px';
if (oldX >= Math.round(rect.right / colCount)) {
container.dispatchEvent(mouseupEvent);
}
}
oldX = (event.clientX - rect.left);
};
container.querySelector('.js-flex-column').addEventListener('mousedown', function(event){
var colWidth = event.clientX - rect.left,
columns = container.querySelectorAll('.col');
colCount = columns.length + 1;
newDiv = document.createElement('div');
newDiv.className = 'col-x';
columns[0].parentNode.insertBefore(newDiv, columns[0]);
container.addEventListener('mousemove', captureMouseMove);
});
container.addEventListener('mouseup', function(){
console.log('mouseup');
if (typeof newDiv !== 'undefined') {
newDiv.style.width = '';
newDiv.className = 'col col-' + colCount;
container.removeEventListener('mousemove', captureMouseMove);
}
});
Chrome is doing something (funky) with the event after move.
Adding event.preventDefault() should do the trick
captureMouseMove = function captureMouseMove(event){
var directionX = 0,
directionY = 0;
if ((event.clientX - rect.left) > oldX) {
// "right"
newDiv.style.width = oldX + 'px';
if (oldX >= Math.round(rect.right / colCount)) {
container.dispatchEvent(mouseupEvent);
}
}
oldX = (event.clientX - rect.left);
event.preventDefault(); // <---
};
I would also recommend that you don't use container for mouseup events. Instead use window so releasing outside of the container doesn't cause issues. You could do the same for mousemove.
How I put in my funtion moveBloco() to control the white bars through the touch.
I want to make the white bars touchable for a smarthphone user. To move the bars up and down through the touch.
function moveBloco(){
if(87 in keyBoard && left.y > 0)
left.y -= left.speed;
if(83 in keyBoard && left.y + left.altura < canvas.height)
left.y += left.speed;
if(38 in keyBoard && right.y >0)
right.y -= right.speed;
if(40 in keyBoard && right.y + right.altura < canvas.height)
right.y += right.speed;
};
https://jsfiddle.net/bd7v016e/1/
You need to handle touch using TouchEvents. You'll have to add 3 more event listeners corresponding to touchstart, touchmove, and touchend. For a touch you can get the pageX and pageY. You'll have to convert these to position relative to the canvas and apply your logic for moving the bars up or down.
document.addEventListener("touchstart", handleTouchStart, false);
document.addEventListener("touchend", handleTouchMove, false);
document.addEventListener("touchend", handleTouchEnd, false);
var touchPosition = {
x: 0,
y: 0
};
function handleTouchStart(e) {
e.preventDefault();
touchPosition.x = e.changedTouches[0].pageX;
touchPosition.y = e.changedTouches[0].pageY;
var canvasPosition = canvas.getBoundingClientRect();
if (touchPosition.x - canvasPosition.left > canvas.width/2) {
// Trigger Right Bar
if (touchPosition.y - canvasPosition.top > right.y) {
// Move Down the Right Bar
}
else {
// Move Up the Right Bar
}
}
else {
// Trigger Left Bar and apply same logic as above
if (touchPosition.y - canvasPosition.top > right.y) {
// Move Down the left bar
}
else {
// Move Up the left bar
}
}
}
function handleTouchMove(e) {
// Handle When User drags along the touch point
}
function handleTouchEnd(e) {
// Handle Touch End
}
I'm attempting to make it, so that when the mouse is within the boundaries set by var play, it changes image. I used the same method I've used for changing images on click, but mouseover and mouseout don't want to work here.
var play = {
x: 650,
y: 360,
width: 200,
height: 100
}
var playUpButton = new Image();
playUpButton.src = "images/PlayUp.png";
var playDownButton = new Image();
playDownButton.src = "images/PlayDown.png";
var playHovering = false;
thisCanvas.addEventListener('click', checkPlay);
thisCanvas.addEventListener('mouseover', hoverPlay, false);
thisCanvas.addEventListener('mouseout', hoverPlay, false);
function seen_move(e)
{
var bounding_box = thisCanvas.getBoundingClientRect();
mouseX = ((e.clientX-bounding_box.left) *(thisCanvas.width/bounding_box.width));
mouseY = ((e.clientY-bounding_box.top) * (thisCanvas.height/bounding_box.height));
}
function draw_start()
{
context.drawImage(menubg, menubg.x, menubg.y, menubg.width, menubg.height);
if(playHovering)
{
context.drawImage(playDownButton, play.x, play.y, play.width, play.height);
}
}
function mouseInArea(top, right, bottom, left)
{
if(mouseX >= left && mouseX < right && mouseY >= top && mouseY < bottom)
{
return true;
}
else
{
return false;
}
}
function hoverPlay()
{
if(mouseInArea(play.y, play.x + play.width, play.y + play.height, play.x))
{
console.log("Hovering");
if(playHovering)
{
playHovering = false;
}
else
{
playHovering = true;
}
}
}
It looks like the following is missing from your code.
var thisCanvas = document.getElementById("thisCanvas");
The function checkPlay also seems to be missing.
Take a look at these articles:
http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
http://www.informit.com/articles/article.aspx?p=1903884&seqNum=6
You must call function seen_move(e) to get the mouse position.
BTW, I'm confused about what the extra code in seen_move is. I'm guessing you're making the mouse position relative to the bounding box. I just mention it in case that's also a problem:
// this usually get the mouse position
var bounding_box = thisCanvas.getBoundingClientRect();
mouseX = e.clientX-bounding_box.left;
mouseY = e.clientY-bounding_box.top;
// and you have this extra bit:
// *(thisCanvas.width/bounding_box.width)); and
// * (thisCanvas.height/bounding_box.height));
mouseX = ((e.clientX-bounding_box.left) *(thisCanvas.width/bounding_box.width));
mouseY = ((e.clientY-bounding_box.top) * (thisCanvas.height/bounding_box.height));