making canvas register mouse move with div over it - javascript

I have a <canvas> element that spans the width and height of my webpage, like a background. It has interactive elements that rely on mouse coordinates. When the canvas was in it's own block (i.e. nothing over it) the interactive elements worked fine. But now that it's got divs over it it's not picking up any of the mouse interactions.
Below is my javascript code for the mousemove stuff. Why would items on top affect it picking up mouse xy coordinates, and how do I fix it?
var mouse = {x:-100,y:-100};
var mouseOnScreen = false;
canvas.addEventListener('mousemove', MouseMove, false);
canvas.addEventListener('mouseout', MouseOut, false);
var MouseMove = function(e) {
if (e.layerX || e.layerX == 0) {
//Reset particle positions
mouseOnScreen = true;
mouse.x = e.layerX - canvas.offsetLeft;
mouse.y = e.layerY - canvas.offsetTop;
}
}
var MouseOut = function(e) {
mouseOnScreen = false;
mouse.x = -100;
mouse.y = -100;
}
var update = function(){
var i, dx, dy, sqrDist, scale;
//...... this chunk is the only part of the function that references the mouse
dx = parts[i].x - mouse.x;
dy = parts[i].y - mouse.y;
sqrDist = Math.sqrt(dx*dx + dy*dy);
if (sqrDist < 20){
parts[i].r = true;
}
.....
}

If you don't need the top divs to be mouse-aware then set their CSS pointer-events:none; and the mouse events will filter down to your canvas underneath. Questioner needs responsive buttons placed over the canvas.
If the top divs do need to respond to mouse events, you might have to listen for mouse events on the window and convert those to canvas coordinates that your app can respond to.
You can listen for mousemove events on the window and get all moves -- even when over button elements. Also listen for mouseout events on the window. Since the canvas spans the window, you know mouseout happens when mouseevent.clientX & mouseevent.clientY report the coordinates are outside the window

Solved the issue with this code I found from another SO answer that I modified a bit.
function simulate(e) {
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent("mousemove", true, true, window,
0, e.screenX, e.screenY, e.clientX, e.clientY, false, false, false, false, 0, null);
canvas.dispatchEvent(evt);
console.log("Emulated.");
}
$("body > section, body > header").each(function(){
this.addEventListener("mousemove", simulate);
});
Also, as a side note. Changed original layerX and layerY in mouse code to offsetX and offsetY to work in firefox (in addition to all other browsers)

Related

Clipping on SVG with 'mousemove' and mouse position alternative for mobile

The idea is there is a black and white picture, and on 'mousemove' using SVG clipping the image "gain colour" (following my mouse movement). I do this by getting the mouse coordinates and clipping the black and white picture with the coloured version of it. It works perfectly on desktop with every browser.
var clientX = 0;
var clientY = 0;
getCoordinates = function(event) {
clientX = event.clientX;
clientY = event.clientY;
};
updateRect = function() {
creative.dom.rect.setAttribute('x', clientX);
creative.dom.rect.setAttribute('y', clientY);
};
clipThroughImage = function() {
updateRect();
};
creative.dom.imageBw.addEventListener('mousemove', getCoordinates);
creative.dom.imageBw.addEventListener('mousemove', clipThroughImage);
On mobile, however, the clipping only "works" (when I keep 'mousemove') by tapping. Instead of the colour following my finger movement (like it does with the mouse), it just instantly goes there when I tap.
I tried using 'touchmove' but then it doesn't work at all, it just clips the entire coloured image and that's it.
What do I need to change to get the same results on mobile?
Made it work with the following:
var allowSwipe = true;
getCoordinates = function(event) {
if (!allowSwipe) return;
allowSwipe = false;
setTimeout(function() {
allowSwipe = true;
}, 10);
clientX = (event.clientX || event.touches[0].clientX);
clientY = (event.clientY || event.touches[0].clientY);
clipThroughImage();
};
creative.dom.imageBw.addEventListener('touchmove', getCoordinates);
creative.dom.imageBw.addEventListener('mousemove', getCoordinates);
And the rest of the code was still the same.

How to move the canvas like drag and drop?

I need to move the whole canvas by touch like the movement of drag and drop
the position of the canvas is supposed to be from
flattenCanvas.height = canvas.height = SCREEN_HEIGHT - menu.container.offsetHeight;
canvas.style.position = 'absolute';
canvas.style.top = menu.container.offsetHeight+'px';
canvas.style.left = -(menu.container.offsetHeight)/2+'px';
context = canvas.getContext("2d");
and the touches for drawing or scrolling is from this
else if(event.touches.length == 1) ////one finger scrolling
{
canvas.style.top = (((event.touches[0].pageY)))+'px';
canvas.style.left = (((event.touches[0].pageX)))+'px';
}
from the last code i can move the canvas by one touch but it is not really dragging.
how to fix the canvas screen movement?
this is a demo of the webapp demo
Based on these docs, the event you want to handle is touchmove.
The code in your question appears to live inside a touchstart handler; just execute the same code in a touchmove handler to continuously update during the 'drag'.
Update
What you are trying to do is offset a target element (in this case, a canvas element) by the difference between a touch event's "current" (touchmove) and "start" (touchstart) positions. To do so, you should capture the positions of both target and touch in a touchstart handler. Then, in your touchmove handler, take the difference in touch positions, and add them to the target's start position. This might look like:
// Get your draggable element from the DOM
var draggable = document.getElementById('draggable');
// Set initial position.
draggable.style.position = 'relative'; // 'absolute' also works.
draggable.style.top = '0';
draggable.style.left = '0';
var targetStartX, targetStartY, touchStartX, touchStartY;
// Capture original coordinates of target and touch
function dragStart(e) {
targetStartX = parseInt(e.target.style.left);
targetStartY = parseInt(e.target.style.top);
touchStartX = e.touches[0].pageX;
touchStartY = e.touches[0].pageY;
}
function dragMove(e) {
// Calculate touch offsets
var touchOffsetX = e.touches[0].pageX - touchStartX,
touchOffsetY = e.touches[0].pageY - touchStartY;
// Add touch offsets to original target coordinates,
// then assign them to target element's styles.
e.target.style.left = targetStartX + touchOffsetX + 'px';
e.target.style.top = targetStartY + touchOffsetY + 'px';
}
draggable.addEventListener('touchstart', dragStart);
draggable.addEventListener('touchmove', dragMove);
Here's a live demo.

How can I bind a Raphael element to the mouse cursor?

I want to create an element and then have that element be immediately bound to the cursor. I have tools to move the element, but I don't know how to bind them to the cursor without having to click the element. I thought about simulating the mousedown() event, but I don't know how to do it.
For context, my ultimate goal is to create a line with user defined endpoint. The user clicks a point and 2 small black circles are created. One as a reference point the the first click and the other to be attached to the cursor with a path connect the 2 points. Once the user clicks another point, both small black circles with disappear and only the line will remain.
Any ideas?
Thanks to #Joan Charmant for pointing me in the right direction. Here's my solution thus far. $('#paper') is my canvas and tempPoint is the circle I created to bind to cursor movement.
$("#paper").mousemove(function (event)
{
if(firstLinePointSelected && tempPoint!=null)
{
if (!event) var event = window.event;
var x=0, y=0;
if (event.pageX || event.pageY)
{
x = event.pageX;
y = event.pageY;
}
else if (event.clientX || event.clientY)
{
x = event.clientX + document.body.scrollLeft
+ document.documentElement.scrollLeft;
y = event.clientY + document.body.scrollTop
+ document.documentElement.scrollTop;
}
// subtract paper coords on page
tempPoint.attr("cx", x - $('#paper').offset().left);
tempPoint.attr("cy", y - $('#paper').offset().top);
}
});

What is technique behind draggable objects?

I am trying to learn how to make a div in an HTML page draggable by pure JavaScript not by using external library so I tried some of mine techniques but I failed to make it a proper draggable object. I am sure I'm missing something important in my code so I want to know what is the basic idea behind draggable object. I was trying to achieve it by setting some startX and startY position and making the Div position absolute and setting the left and top of div by css as
p.style.left = (e.clientX-startX) + 'px';
p.style.top = (e.clientY-startY) + 'px';
// where p is the element i am trying to make draggable
You should not forget to save p's initial position and add it each time to make sure you're doing relative calculations. Currently, you assume p is always at position (0, 0) when starting dragging.
Secondly, cancelling the selectstart event makes for no ugly selection being created when dragging.
I updated your code a bit to this effect: http://jsfiddle.net/rLegF/1/.
var p = document.getElementById("p"),
startX, startY,
origX, origY,
down = false;
document.documentElement.onselectstart = function() {
return false; // prevent selections
};
p.onmousedown = function(e) {
startX = e.clientX;
startY = e.clientY;
origX = p.offsetLeft;
origY = p.offsetTop;
down = true;
};
document.documentElement.onmouseup = function() {
// releasing the mouse anywhere to stop dragging
down = false;
};
document.documentElement.onmousemove = function(e) {
// don't do anything if not dragging
if(!down) return;
p.style.left = (e.clientX - startX) + origX + 'px';
p.style.top = (e.clientY - startY) + origY + 'px';
};
Edit: You could also combine startX and origX since you're basically always doing - startX + origX: http://jsfiddle.net/rLegF/2/.
What you're then doing is calculating the mouse position with respect to the top left-hand corner of the element, and then set the position to the new mouse position minus that old mouse position. Perhaps it's a little more intuitive that way.
I cleaned up some more as well.

Getting mouse location in canvas [duplicate]

This question already has answers here:
How do I get the coordinates of a mouse click on a canvas element? [duplicate]
(22 answers)
Closed 3 years ago.
Is there a way to get the location mouse inside a <canvas> tag? I want the location relative to to the upper right corner of the <canvas>, not the entire page.
The accepted answer will not work every time. If you don't use relative position the attributes offsetX and offsetY can be misleading.
You should use the function: canvas.getBoundingClientRect() from the canvas API.
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
canvas.addEventListener('mousemove', function(evt) {
var mousePos = getMousePos(canvas, evt);
console.log('Mouse position: ' + mousePos.x + ',' + mousePos.y);
}, false);
Easiest way is probably to add a onmousemove event listener to the canvas element, and then you can get the coordinates relative to the canvas from the event itself.
This is trivial to accomplish if you only need to support specific browsers, but there are differences between f.ex. Opera and Firefox.
Something like this should work for those two:
function mouseMove(e)
{
var mouseX, mouseY;
if(e.offsetX) {
mouseX = e.offsetX;
mouseY = e.offsetY;
}
else if(e.layerX) {
mouseX = e.layerX;
mouseY = e.layerY;
}
/* do something with mouseX/mouseY */
}
Also note that you'll need CSS:
position: relative;
set to your canvas tag, in order to get the relative mouse position inside the canvas.
And the offset changes if there's a border
I'll share the most bulletproof mouse code that I have created thus far. It works on all browsers will all manner of padding, margin, border, and add-ons (like the stumbleupon top bar)
// Creates an object with x and y defined,
// set to the mouse position relative to the state's canvas
// If you wanna be super-correct this can be tricky,
// we have to worry about padding and borders
// takes an event and a reference to the canvas
function getMouse = function(e, canvas) {
var element = canvas, offsetX = 0, offsetY = 0, mx, my;
// Compute the total offset. It's possible to cache this if you want
if (element.offsetParent !== undefined) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
// Add padding and border style widths to offset
// Also add the <html> offsets in case there's a position:fixed bar (like the stumbleupon bar)
// This part is not strictly necessary, it depends on your styling
offsetX += stylePaddingLeft + styleBorderLeft + htmlLeft;
offsetY += stylePaddingTop + styleBorderTop + htmlTop;
mx = e.pageX - offsetX;
my = e.pageY - offsetY;
// We return a simple javascript object with x and y defined
return {x: mx, y: my};
}
You'll notice that I use some (optional) variables that are undefined in the function. They are:
stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(canvas, null)['paddingLeft'], 10) || 0;
stylePaddingTop = parseInt(document.defaultView.getComputedStyle(canvas, null)['paddingTop'], 10) || 0;
styleBorderLeft = parseInt(document.defaultView.getComputedStyle(canvas, null)['borderLeftWidth'], 10) || 0;
styleBorderTop = parseInt(document.defaultView.getComputedStyle(canvas, null)['borderTopWidth'], 10) || 0;
// Some pages have fixed-position bars (like the stumbleupon bar) at the top or left of the page
// They will mess up mouse coordinates and this fixes that
var html = document.body.parentNode;
htmlTop = html.offsetTop;
htmlLeft = html.offsetLeft;
I'd recommend only computing those once, which is why they are not in the getMouse function.
For mouse position, I usually use jQuery since it normalizes some of the event attributes.
function getPosition(e) {
//this section is from http://www.quirksmode.org/js/events_properties.html
var targ;
if (!e)
e = window.event;
if (e.target)
targ = e.target;
else if (e.srcElement)
targ = e.srcElement;
if (targ.nodeType == 3) // defeat Safari bug
targ = targ.parentNode;
// jQuery normalizes the pageX and pageY
// pageX,Y are the mouse positions relative to the document
// offset() returns the position of the element relative to the document
var x = e.pageX - $(targ).offset().left;
var y = e.pageY - $(targ).offset().top;
return {"x": x, "y": y};
};
// now just make sure you use this with jQuery
// obviously you can use other events other than click
$(elm).click(function(event) {
// jQuery would normalize the event
position = getPosition(event);
//now you can use the x and y positions
alert("X: " + position.x + " Y: " + position.y);
});
This works for me in all the browsers.
EDIT:
I copied the code from one of my classes I was using, so the jQuery call to this.canvas was wrong. The updated function figures out which DOM element (targ) caused the event and then uses that element's offset to figure out the correct position.
GEE is an endlessly helpful library for smoothing out troubles with canvas, including mouse location.
Simple approach using mouse event and canvas properties:
JSFiddle demo of functionality http://jsfiddle.net/Dwqy7/5/
(Note: borders are not accounted for, resulting in off-by-one):
Add a mouse event to your canvas
canvas.addEventListener("mousemove", mouseMoved);
Adjust event.clientX and event.clientY based on:
canvas.offsetLeft
window.pageXOffset
window.pageYOffset
canvas.offsetTop
Thus:
canvasMouseX = event.clientX - (canvas.offsetLeft - window.pageXOffset);
canvasMouseY = event.clientY - (canvas.offsetTop - window.pageYOffset);
The original question asked for coordinates from the upper right (second function).
These functions will need to be within a scope where they can access the canvas element.
0,0 at upper left:
function mouseMoved(event){
var canvasMouseX = event.clientX - (canvas.offsetLeft - window.pageXOffset);
var canvasMouseY = event.clientY - (canvas.offsetTop - window.pageYOffset);
}
0,0 at upper right:
function mouseMoved(event){
var canvasMouseX = canvas.width - (event.clientX - canvas.offsetLeft)- window.pageXOffset;
var canvasMouseY = event.clientY - (canvas.offsetTop - window.pageYOffset);
}
I'd use jQuery.
$(document).ready(function() {
$("#canvas_id").bind( "mousedown", function(e){ canvasClick(e); } );
}
function canvasClick( e ){
var x = e.offsetX;
var y = e.offsetY;
}
This way your canvas can be anywhere on your page, relative or absolute.
Subtract the X and Y offsets of the canvas DOM element from the mouse position to get the local position inside the canvas.

Categories