Undesired Mouseover Effects When Using an iPad or Other Mobile Device - javascript

I'm working on a responsive website. There is one type of navigation element that is an clickable image link. I've got many of these on the page. On a normal desktop computer when you mouseover this image it changes color (+ more), and changes back when you mouseout. When clicked, you are linked to a new webpage. Right now this is coded via a simple JavaScript Event handler.
<a href="http://myfakewebsite.com/next_page_1.html">
<img onmouseover="{ this.src = 'image_1_red.png'; }"
onmouseout="{ this.src='image_1_normal.png'; }"
src='image_1_normal.png'
/>
</a>
The issue is when a iPad user taps a clickable event, the following elements are sent.. mouseover, mousemove, mousedown, mouseup and click. And that mouseover event is definitely causes me troubles. There is a fraction of a second where the image_1_normal image disappears and you get a visible icon (white question mark in box with blue background and white border) for a period of time before the site snaps to the new URL. There is not enough time for the image_1_red to appear. The whole affect looks odd. Its noticeable enough that my customer isn't happy. Is there any way to mitigate this issue? Is there a way in JavaScript to say...
if this is a mobile touch device, then skip the whole mouseover thing?
Is there a way to do this inline via Event Handler, or am i going to have to create event listeners for all of the elements in script en mass?
So I did an update to code:
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", init, false);
function init() {
var image_1 = document.getElementById("image_1_nav");
var image_2 = document.getElementById("image_2_nav"); .. etc...
if (!("ontouchstart" in document.documentElement)){
image_1.addEventListener("onmouseover", function(){
this.src="image_1_red.png";}, false);
}
if ("ontouchstart" in document.documentElement){
alert( "Mobile device with Touchstart"); }
}
</script>
The alert test works fine on ipad not on desktop as expected.
Now I'm unable to get the onmouseover function to register...
First off, the system didn't like if (!"ontouchstart" in document.documentElement){ I had to change that to if(!("ontouchstart" in document.documentElement)){ before it would register correctly. I'm now stuck trying to figure out why I can't see the event listeners for onmouseover....

So from what I can see, there appears to be no way to use an 'inline' event handler to avoid OnMouseOver when a website is viewed on a mobile device. This code seems to work:
<img src='image_1_normal.png' />
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", init, false);
function init() {
var image_1 = document.getElementById("image_1_nav");
var image_2 = document.getElementById("image_2_nav"); //.. etc...
if (!("ontouchstart" in document.documentElement) &&
! (navigator.maxTouchPoints > 0) &&
! (navigator.msMaxTouchPoints > 0) ){
image_1.addEventListener("mouseover", function(){
this.src="image_1_red.png";}, false);
image_1.addEventListener("mouseout", function(){
this.src="image_1.png";}, false); // .. etc...
}
}
</script>
So on a mobile device (iPad) the original image never gets modified at all during a click, No weird momentary popup icons, no miffed customers. Oh, and many thanks to Manuel Ignacio López Quintero for this blog entry. and Patrick H. Lauke and Robert Nyman for their article on detecting touch.

Related

ontouchstart acting weird on mobile devices?

I am working on a game and i am using ontouchstart as a way to handle au ser tapping on the screen. but when i click on the screen it does not register the first time, it makes me click it twice for it to register even one click. I have no idea what to do. does anyone know a fix?
I decided to update my code with a more simplified version of it. this is not working either. on an IOS device at least, no matter what browser i use, i have to tap twice for it to register once.
<html>
<link href="https://fonts.googleapis.com/css?family=Press+Start+2P&display=swap" rel="stylesheet" />
<body>
<h1 class="center-align" id="cn">click me</h1>
<h2 id="cl">clicked:</h2>
</body>
<script>
let click = 1;
document.getElementById("cn").ontouchstart = () => {
click++;
document.getElementById("cl").innerHTML = "clicked: " + click;
};
</script>
</html>
Hey can you try removing the touch-action from the styles? Manipulating touch action ends up affecting touch event listeners
EDIT
Can you try this instead?
object.addEventListener("touchstart", myScript);

Firefox seems to ignore event.preventDefault()

I'm working on a page where I have a draggable item (a map inside a container). When you click and drag with the mouse, the map moves and everything is fine. I then wanted to add the same functionality for touch devices (such as a smartphone or a tablet). I searched the net and found a working script that "changes" touch input to mouseinput and thus making it possible to drag the map without dragging the entire page (which is standard behaviour). This is done using the line
event.preventDefault()
It is even possible to have click events as well by timing how long apart the touches are. I am no coding genius and all this programming was done by others. You can see the discussion at Javascript Drag and drop for touch devices (I have used the original code in the top answer as well as the timing code in the answer just below the top answer).
So far, so good. It is now possible to drag the map around and click any links on it or the page just as you would, if you were using a mouse. This works on all touch browsers I have tried (I haven't tried a lot, but the ones I've tried work). The only problem is, that you cannot drag the page itself around, since the default behaviour of the touch has been disabled. This is a problem when the content of the page (for instance the size of the map container) is larger than the browser window.
Luckily an answer was provided for this as well (it is the bottom-most answer on the page I linked to above): replacing
event.preventDefault()
with
if (touches.length > 1) event.preventDefault();
the default scrolling/resizing etc. of a touch works if you use one finger, but if you use more than one finger, the default behaviour is prevented. In other words: If you use two fingers, you can drag the map around without dragging the page (just as before), but if you use one finger, you can drag the page around! I really like this solution as it seems quite elegant to me.
Well, I added the line and tested on the default browser on my HTC Incredible phone (way to small screen but it is what I have). The default browser is just called "Internet". Everything works perfectly!
So, I test on Firefox and Opera, and unfortunately, they are not working perfectly. It seems that once the
event.preventDefault()
is inside the "if" statement, it is completely ignored, so when I drag the map, it IS dragged (as the touch is still converted to a drag of the mouse), but the page itself is also dragged, regardless of the number of fingers I use. In short: The page behaves as if no
event.preventDefault()
is triggered.
I have looked around for several hours and have come to suspect that the event variable needs to be initialized or imported for Firefox and Opera to be able to use it, as described here: jQuery event.preventDefault() not working in Firefox (JSFiddle included)
My question (at long last): Could this be right, and how do I go about "importing" the event into the "if" statement?
The code is here (the init() function is triggered by body onload)
<script type="text/javascript">
var clickms = 400;
var lastTouchDown = -1;
function touchHandler(event)
{
var touches = event.changedTouches,
first = touches[0],
type = "";
var d = new Date();
switch(event.type)
{
case "touchstart": type = "mousedown"; lastTouchDown = d.getTime(); break;
case "touchmove": type="mousemove"; lastTouchDown = -1; break;
case "touchend": if(lastTouchDown > -1 && (d.getTime() - lastTouchDown) < clickms){lastTouchDown = -1; type="click"; break;} type="mouseup"; break;
default: return;
}
var simulatedEvent = document.createEvent("MouseEvent");
simulatedEvent.initMouseEvent(type, true, true, window, 1,
first.screenX, first.screenY,
first.clientX, first.clientY, false,
false, false, false, 0/*left*/, null);
first.target.dispatchEvent(simulatedEvent);
if (touches.length > 1)
{
event.preventDefault();
}
}
function init()
{
document.addEventListener("touchstart", touchHandler, true);
document.addEventListener("touchmove", touchHandler, true);
document.addEventListener("touchend", touchHandler, true);
document.addEventListener("touchcancel", touchHandler, true);
}
</script>
Edit: I should add that I have tried inserting an alert statement into the if statement, just to see whether Firefox or Opera actually register that a two-finger gesture is performed. The alert is triggered without problems, so perhaps the problem is that once Firefox or Opera has started a two-finger gesture, the standard behaviour of the gesture (draggring or resizing the page) cannot be stopped, at least not in this way.
I seem to have solved the problem (at least on the browsers at my disposal for testing)
What I did was changing
if (touches.length > 1) {
event.preventDefault();
}
to
if (event.touches.length > 1) {
event.preventDefault();
}
It's now possible to drag the draggable element around using two fingers without having the rest of the page move. It's still possible to drag the map with one finger on Firefox and Opera, but this is a minor thing, as soon as you adopt a "use only two fingers when you want to drag" attitude.
The only small issue is that both Firefox and Opera seem to jump back and forth between which fingertip they choose to focus on, making the draggable element jitter somewhat, especially when the fingers are a bit apart. This behaviour is not displayed in the "Internet" browser.

Why doesn't dragging images using JavaScript work in Firefox?

I'm using the code below for dragging an image (#StndSoln1). It works perfectly in Chrome and all, but not in Firefox. Here startDrag() is the function which i attached to the mousedown event listener. Could anybody please help me.
function initialFunction(){
document.getElementById("StndSoln1").addEventListener('mousedown',startDrag,false);
document.getElementById("StndSoln1").addEventListener('mousemove',drag,false);
document.getElementById("StndSoln1").addEventListener('mouseup',stopDrag,false);
}
function startDrag()
{
if (!moveFlag){
currentTraget=document.getElementById("StndSoln1");
offsetX=currentTraget.offsetLeft;
offsetY=currentTraget.offsetTop;
ImgPlaced=false;
moveFlag=true;
x=window.event.clientX;
y=window.event.clientY;
event.preventDefault();
}
}
// Fn for drag the current target object...
function drag(){
if (moveFlag && !ImgPlaced){
currentTraget.style.left=(offsetX+window.event.clientX-x)+"px";
currentTraget.style.top=(offsetY+window.event.clientY-y)+"px";
}
}
I actually had a similar problem, so I can try to help even without the code you're using.
See, the Firefox developers had this bright idea of making it so that, when you drag an image, you can "move" it around and possibly drop it in an Explorer window to quickly and easily download it, or to the tab bar to open the image in a new tab. The obvious downside of this is that it results in a default behaviour that other browsers don't have.
The simple solution is to make sure that all your events are properly cancelling the default action (event.preventDefault, return false, that kind of thing). Should that fail too, then you should use a <div> element with a background-image instead of an <img> element.

UIWebView performance with JS onclick function

I have a rather large page showing in a UIWebView (around 150 <article>s with some text, separated in <section>s). I want to do something like this with JS (I use jQuery):
$('article').click(function() {alert('hi');});
The problem is, it takes forever to run that code (around 2 seconds from the tap, on an iPad 3).
How can I improve performance on this?
I'm using the latest version of XCode and iOS 5.1.
I used this answer's class SingleTapDetector, and the following code:
new SingleTapDetector(window, function(e) {
alert($(e.srcElement).text()); //show the text of the element that was tapped
});
Then it's easy to see if the element was an article, or even stuff like $(e.srcElement).closest('article') (because my articles have <p> paragraphs).
I suggest you to try to put a click event on the window object, and then verify if this is the <article> tag. Here's the example:
$(window).click(function(e){
var e = e || event;
if(e.srcElement.tagName==ARTICLE)
alert('hi');
});

Image map with overlay not working in IE

I am trying to create an interactive map with an overlay using html image maps.
To see it, please visit: http://www.surge.ca/testing/WFA2100/index.html
The explanation:
When you hover over an <area> of the map, it bring up an overlay with links.
To prevent the overlay from closing when you move to it, as you are no longer hovering over the area, I am using a setTimeout before it closes the overlay.
The problem:
It works like I want in every browser but IE.
In IE 7 and 8, when you hover over an overlay that is above another <area>, it immediately switches to the overlay of that <area>.
At first, I thought it was a z-index issue where the <area>'s z-index was above the overlay, but I think my z-index is set up correctly. I am also thinking that it could just be how IE handles image maps?
The code:
Here is the code that sets up the events.
jQuery(function($){
// binds mouseenter and mouseleave to <area>
$('area').bind('mouseenter',function(){
sectionNum = this.hash;
sectionNum = sectionNum.replace(/#/,'');
showOverlay(sectionNum);
clearTimeout(timer);
}).bind('mouseleave', function(){
timerClose();
});
$('.map_info').bind('mouseenter', function(){
clearTimeout(timer);
}).bind('mouseleave', function(){
timerClose();
});
});
// sets timer before closing to allow cancel
var timer;
function timerClose(){
timer = setTimeout(function(){hideOverlay();},500);
}
The problem is that IE clear the setTimeout when hover ends. I didn't ran your code but I had same problem and cpuld fix it by passing the setTimeout function as an string.
For example setTimeout(alert('hi'), 1000) wasn't working on a function that was running in a hover state but setTimeout("alert('hi')", 1000) was working.
In your code maybe replacing
timer = setTimeout(function(){hideOverlay();},500);
with
timer = setTimeout("function(){hideOverlay();}",500);
solve the problem.
It seems IE run code that passed in string in global scope.
Also I can see you have jQuery in your page. There is a jQuery plug-in called hoverIntent that do hover delay very nice. Maybe plug-in writer wrote more cross-browser code.
Let me know if it works. :)

Categories