Responding to the onmousemove event outside of the browser window in IE - javascript

In Internet Explorer 7 body onmousemove or document.onmousemove events only seem to fire while the mouse is inside the browser window, not when it's outside. Yet in Firefox the onmousemove event is called correctly when I move outside of the browser window.
How can I setup an event to be called outside of the browser window in IE?
Google Maps does this in IE. If you hold the mouse button down and move the mouse outside of the browser window you can see that the map still moves.

(Note: this answer refers exclusively to the "standard" drag implementation of mousedown -> mousemove -> mouseup. It is not applicable to the HTML5 drag specification).
Allowing dragging outside the browser window is an old problem that different browsers have solved in two ways.
With the exception of IE, when a user initiates a drag operation via mousedown browsers have done something neat (and this is all just from observation): a kind of statemachine kicks in to handle the special case of mouse movements outside the window:
User triggers mousedown event inside the document
User triggers mousemove event. Event fires even when triggered from outside the document (i.e. the window)
User triggers mouseup event (inside or outside the document). mousemove events triggered from outside the document no longer fire
IE and older versions of Firefox [as late as 2.0.20] don't exhibit this behavior. Dragging outside the window just doesn't work1.
The problem for IE and FF2 actually lies in whether an element is "selectable" or not (See here and here). If a dragging implementation does nothing (thereby allowing selection by the mouse), then said implementation does not have to account for movements outside the window; the browser will go ahead and fire mousemove properly and the user is allowed to drag freely outside the window. Nice.
However by letting the browser decide what to do on mousemove you get this effect where the browser thinks the user is trying to "select" something (eg the element), as opposed to moving it, and proceeds to frantically try to highlight the element or text therein as the mouse crosses in or out of the element during the drag.
Most drag implementations I've seen do a little trick to make the element being dragged "unselectable", thereby taking full control of mousemove to simulate dragging:
elementToDrag.unselectable = "on";
elementToDrag.onselectstart = function(){return false};
elementToDrag.style.userSelect = "none"; // w3c standard
elementToDrag.style.MozUserSelect = "none"; // Firefox
This works nicely, but breaks dragging outside the window. 2
Anyway, to answer your question, to get IE (all versions) to allow dragging outside the window, use setCapture (and inversely releaseCapture when the mouse is released).
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Simple drag demo</title>
<style>
#dragme {
position:absolute;
cursor:move;
background:#eee;
border:1px solid #333;
padding:10px;
}
</style>
<script>
function makeDraggable(element) {
/* Simple drag implementation */
element.onmousedown = function(event) {
document.onmousemove = function(event) {
event = event || window.event;
element.style.left = event.clientX + 'px';
element.style.top = event.clientY + 'px';
};
document.onmouseup = function() {
document.onmousemove = null;
if(element.releaseCapture) { element.releaseCapture(); }
};
if(element.setCapture) { element.setCapture(); }
};
/* These 3 lines are helpful for the browser to not accidentally
* think the user is trying to "text select" the draggable object
* when drag initiation happens on text nodes.
* Unfortunately they also break draggability outside the window.
*/
element.unselectable = "on";
element.onselectstart = function(){return false};
element.style.userSelect = element.style.MozUserSelect = "none";
}
</script>
</head>
<body onload="makeDraggable(document.getElementById('dragme'))">
<div id="dragme">Drag me (outside window)</div>
</body>
</html>
Demo can be seen here.
This is exactly what Google maps does (as I discovered since reverse engineering google maps back in 2004 when it was first released).
1I believe it actually only breaks when initiating a drag operation (i.e. mousedown) on a textnode. Element/container nodes do not exhibit the same behavior and can be dragged around inside or outside the document, provided the user moused down on an "empty " portion of the element
2Again, for drag initiations on textnodes.

You can look at the code here, as it seems to work in IE8 and FF3.5. If you can understand his code great.
http://www.walterzorn.de/en/dragdrop/dragdrop_e.htm

Related

X and y coordinates while mousedown

I am currently making a game that requires the player to drag around an object on a touch screen device.
I've used the event listener mousemove, and it has worked on my Intel XDK emulator, but now that I move it to a touch screen device, I need an touch event that is mousemove and mousedown, and I am not sure how to do that.
Example of ideal code:
canvas.addEventListener("mousemove" && "mousedown", function(e){
pointerX = e.pageX;
pointerY = e.pageY;
}
So this ideal code spits out x and y when the mouse is down, and it has moved.
If anyone knows the legit syntax or a different method of doing this, it would be a great help.
I don't want to incorporate JQuery into this, just pure JS.
Thanks! :)
Edit: Let me rephrase this so it is all straight forward. While the user is dragging an object I need a function that spits out x and y of the pointer the entire drag.
Per MDN:
The EventTarget.addEventListener() method registers the specified listener on the EventTarget it's called on. The event target may be an Element in a document, the Document itself, a Window, or any other object that supports events (such as XMLHttpRequest).
Note the "eventTarget" above. The AddEventListener method takes only one string which represents EventType. You'll need to write a custom function in order to iterate multiple events:
const target = document.getElementById("myDiv");
['mousedown', 'mousemove'].forEach(eventType => {
target.addEventListener(eventType, (event) => {
target.innerText = `x: ${event.pageX} y: ${event.pageY}`;
});
});
#myDiv {
width: 100px;
height: 100px;
background-color: orange;
color: white;
}
<div id="myDiv"></div>
For touch devices, you should be looking into touchstart, touchend, touchcancel and touchmove.
Touch events are similar to mouse events except they support simultaneous touches and at different locations on the touch surface.
https://developer.mozilla.org/en-US/docs/Web/API/Touch_events`
MDN has a great post on touch events. The posts are not just full of quality information but also there are lots of javascript code shown which will provide you with a good resource for touch events.
Interfaces
TouchEvent
Represents an event that occurs when the state of touches on the surface changes.
Touch
Represents a single point of contact between the user and the touch surface.
TouchList
Represents a group of touches; this is used when the user has, for example, multiple fingers on the surface at the same time.
How does this solve my current problem?
The information above provides greater detail for all the types of events you may want to look into. However, for your specific problem, you should look into touchmove & touchend events.
Side note - check touchmove & touchend links for compatibility concerns.

Video on mousemove

I'm having problems while trying to play a video as long as mouse moves. I want it's time to follow mouse, as if the mouse was the time handler.
I have this code. It works fine on Internet Explorer but on Chrome or Mozi time is not fluid, as it has something to do with refreshing times. Video plays with difficult.
<script type="text/javascript">
var mouseX;
$(document).mousemove( function moveFunc(e) {
mouseX = e.clientX;
var timV = $(".video").get(0).duration;
var valV = (timV*mouseX/$(window).width());
$(".video").get(0).currentTime = valV;
});
</script>
Could you help me?
Firefox and Chrome stopped firing mousemove events for every mouse position update on the window and document in an attempt to make pages more responsive.
You can fix it by binding your event to something more specific like the video element itself or any wrapper element.

How to identify REAL mouse movement when entering fullscreen mode

I have the problem, that I need to know if the user actually moved his mouse for real when entering fullscreen, or if it just is a programatically side effect of entering the fullscreen.
Because, when entering fullscreen, the mouse Y coordinates change automatically because the mouse moves upwards on the absolute screen position (since the top navigation of the browser disappears). And since every browser brings a notification in fullscreen mode, this very notification triggers a mousemove event.
So, this makes it very painful to find out, whether the user acually move the mouse, or not.
Is there a solution to identify REAL mouse movement?
$(document).on('mousemove', function(event){
/* gets also triggered when just entering fullscreen,
but without actual movement of the physical mouse..
how can this be identified/ignored?
*/
});
JS Fiddle
What I've tried so far
I tried already relativating the mouse position by using something like window.screen.top - but this seems not to be implemented yet by any browser so far.
I don't think there's anything formally implemented as yet to detect full screen. There's a fullscreenchange as part of the Fullscreen API but it's still experimental and requires vendor-specific prefixes.
So, basically you'll have to get around that limitation with some tricks, like intersecting the resize event and skipping whatever logic you are running on mousemove. Here's an example...
var resizing = false;
$(document).on('mousemove', function(event){
if(resizing == false){
$('p').text(event.pageX + ':' + event.pageY);
console.log("moving");
}
});
$(window).resize(function(){
resizing = true;
setTimeout(function(){
resizing = false;
}, 4000);
});
This example simply defines a flag that determines whether the window is resizing or not, if resizing the onmousemove logic is skipped. Particularly I hate to use setTimeout with an arbitrary time to switch off the resizing flag, but if your requirements are not so strict it can get the job done beautifully
Why don't you incorporate a delay (for example 0.5 seconds) where you ignore all mouse inputs. After the delay, any mouse movements are likely to be from the user...
I solved it now by saving the mouse coordinates, and check if they change - while I force one mousemove event after fullscreen in order to update the coordinates once.
$(document).on('mousemove', function(event){
if(event.pageX == $(this).data('mouseX') && event.pageY == $(this).data('mouseY'))
return;
$(this)
.data('mouseX', event.pageX)
.data('mouseY', event.pageY)
;
});
$(document).mousemove();

Disable scrolling when touch moving certain element

I have a page with a section to sketch a drawing in. But the touchmove events, at least the vertical ones, are also scrolling the page (which degrades the sketching experience) when using it on a mobile browser. Is there a way to either a) disable & re-enable the scrolling of the page (so I can turn it off when each line is started, but turn it back on after each is done), or b) disable the default handling of touchmove events (and presumably the scrolling) that go to the canvas the sketch is drawn in (I can't just disable them completely, as the sketching uses them)?
I've used jquery-mobile vmouse handlers for the sketch, if that makes a difference.
Update: On an iPhone, if I select the canvas to be sketched in, or just hold my finger for a bit before drawing, the page doesn't scroll, and not because of anything I coded in the page.
Set the touch-action CSS property to none, which works even with passive event listeners:
touch-action: none;
Applying this property to an element will not trigger the default (scroll) behavior when the event is originating from that element.
Note: As pointed out in the comments by #nevf, this solution may no longer work (at least in Chrome) due to performance changes. The recommendation is to use touch-action which is also suggested by #JohnWeisz's answer.
Similar to the answer given by #Llepwryd, I used a combination of ontouchstart and ontouchmove to prevent scrolling when it is on a certain element.
Taken as-is from a project of mine:
window.blockMenuHeaderScroll = false;
$(window).on('touchstart', function(e)
{
if ($(e.target).closest('#mobileMenuHeader').length == 1)
{
blockMenuHeaderScroll = true;
}
});
$(window).on('touchend', function()
{
blockMenuHeaderScroll = false;
});
$(window).on('touchmove', function(e)
{
if (blockMenuHeaderScroll)
{
e.preventDefault();
}
});
Essentially, what I am doing is listening on the touch start to see whether it begins on an element that is a child of another using jQuery .closest and allowing that to turn on/off the touch movement doing scrolling. The e.target refers to the element that the touch start begins with.
You want to prevent the default on the touch move event however you also need to clear your flag for this at the end of the touch event otherwise no touch scroll events will work.
This can be accomplished without jQuery however for my usage, I already had jQuery and didn't need to code something up to find whether the element has a particular parent.
Tested in Chrome on Android and an iPod Touch as of 2013-06-18
There is a little "hack" on CSS that also allows you to disable scrolling:
.lock-screen {
height: 100%;
overflow: hidden;
width: 100%;
position: fixed;
}
Adding that class to the body will prevent scrolling.
document.addEventListener('touchstart', function(e) {e.preventDefault()}, false);
document.addEventListener('touchmove', function(e) {e.preventDefault()}, false);
This should prevent scrolling, but it will also break other touch events unless you define a custom way to handle them.
The ultimate solution would be setting overflow: hidden; on document.documentElement like so:
/* element is an HTML element You want catch the touch */
element.addEventListener('touchstart', function(e) {
document.documentElement.style.overflow = 'hidden';
});
document.addEventListener('touchend', function(e) {
document.documentElement.style.overflow = 'auto';
});
By setting overflow: hidden on start of touch it makes everything exceeding window hidden thus removing availability to scroll anything (no content to scroll).
After touchend the lock can be freed by setting overflow to auto (the default value).
It is better to append this to <html> because <body> may be used to do some styling, plus it can make children behave unexpectedly.
EDIT:
About touch-action: none; - Safari doesn't support it according to MDN.
try overflow hidden on the thing you don't want to scroll while touch event is happening. e.g set overflow hidden on Start and set it back to auto on end.
Did you try it ? I'd be interested to know if this would work.
document.addEventListener('ontouchstart', function(e) {
document.body.style.overflow = "hidden";
}, false);
document.addEventListener('ontouchmove', function(e) {
document.body.style.overflow = "auto";
}, false);
I found that ev.stopPropagation(); worked for me.
To my surprise, the "preventDefault()" method is working for me on latest Google Chrome (version 85) on iOS 13.7. It also works on Safari on the same device and also working on my Android 8.0 tablet.
I am currently implemented it for 2D view on my site here:
https://papercraft-maker.com
this worked for me on iphone
$(".owl-carousel").on('touchstart', function (e) {
e.preventDefault();
});
the modern way (2022) of doing this is using pointer events as outlined here in the mozilla docs: https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events
Pointer events build on touchstart and other touch events and actually stop scroll events by default along with other improvements.

How can I react when a user touches an HTML element on an iPhone?

I'm displaying some HTML content in my iPhone app using a UIWebView. I have an image link, and I want it to change when the user touches it - at the moment the user puts a finger on the screen, rather than waiting until they lift their finger back off.
What CSS or JavaScript concept could accomplish this? I've looked at the hover and active states in CSS, but they don't seem to be what I'm after: hover relates to touch-up rather than touch-down, while active seems to have no effect at all.
You could try this.
I think it should be what you are looking for!
http://articles.sitepoint.com/article/iphone-development-12-tips/2
8: Touch Events
Of course, you use your iPhone with a
finger instead of a mouse; rather than
clicking, you tap. What’s more, you
can use several fingers to touch and
tap. On the iPhone, mouse events are
replaced by touch events. They are:
touchstart
touchend
touchmove
touchcancel (when the system cancels the touch)
When you subscribe to any of those
events, your event listener will
receive an event object. The event
object has some important properties,
such as:
touches — a collection of touch objects, one for each finger that
touches the screen. The touch objects
have, for example, pageX and pageY
properties containing the coordinates
of the touch within the page.
targetTouches — works like touches, but only registers touches on
a target element as opposed to the
whole page.
The next example is a simple
implementation of drag and drop. Let’s
put a box on a blank page and drag it
around. All you need to do is
subscribe to the touchmove event and
update the position of the box as the
finger moves around, like so:
window.addEventListener('load', function() {
var b = document.getElementById('box'),
xbox = b.offsetWidth / 2, // half the box width
ybox = b.offsetHeight / 2, // half the box height
bstyle = b.style; // cached access to the style object
b.addEventListener('touchmove', function(event) {
event.preventDefault(); // the default behaviour is scrolling
bstyle.left = event.targetTouches[0].pageX - xbox + 'px';
bstyle.top = event.targetTouches[0].pageY - ybox + 'px';
}, false);
}, false);
The touchmove event listener first cancels the default behavior of the finger move—otherwise Safari will scroll the page. The collection event.targetTouches contains a list of data for each finger currently on the target div element.
We only care about one finger, so we use event.targetTouches[0]. Then pageX gives us the X coordinate of the finger. From this value we subtract half the width of the div so that the finger stays in the center of the box.
Hope it helps!
Try the Javascript "onMouseDown", hopefully the mobile Safari will fire the event.
Link

Categories

Resources