Javascript: Child should not be inheriting mouse state from Parent - javascript

I'm trying to create a small image that follows the mouse around but only exists inside a specific area. I'm using javascript/jquery to create the image when the mouse enters the area and remove it when the mouse leaves.
The problem is, if I create the "follower" inside the area div, the image seems to be considered part of it's parent for determining mouse state, and thus it continues to exist even after the mouse is outside the area.
(If I move the mouse fast enough the cursor will escape and the follower disapears.)
Here is the code I'm using:
$("#area").mouseenter(function() {
$("#area").append("<img id='follower' src='follower.png'/>");
});
$("#area").mousemove(function(event){
$("#follower").css("top",event.pageY-35);
$("#follower").css("left",event.pageX-35);
});
$("#area").mouseleave(function() {
$("#follower").remove();
});
JSFiddle: http://jsfiddle.net/cgWdF/186/
I have also attempted creating the "follower" inside a separate div, which works but results in a weird flickering of the image, as seen here: http://jsfiddle.net/cgWdF/187/
Any help, with this, would be appreciated. It doesn't matter whether the follower is created inside the area div, or not, as long as the flickering affect isn't seen. Also, I'd like to keep the code as compact as possible, but I'll take what I can get.

This occurs because the element on which you mouseleave is not the one on which you think it happens. In fact, your sprite is triggering the event instead because your pointer is over it at that time.
To prevent that from happening, you can force the page to cancel all pointer events on your sprite. By doing that, #area will trigger your pointer events as intended. The css rule pointer-events might be helpful for this.
CSS
#follower {
position: absolute;
height: 80px;
pointer-events: none;
}
There are probably better ways to deal with that but it's the most simple I can come up with for now.
Hope this helps!
See FIDDLE.

Related

Pass event from overlayed div to Highmaps

I'm using Highmaps to show a simple map and over it I have another div with a component that draws things on top of the map (this has to be done this way, I cannot draw everything inside Highmaps, unfortunely).
Now I would like to have some interation with the map, although it is below my div. I would like to know if there is a way to trigger the click, hover, etc. events on the map when I click on the div on top of it.
I have searched Highmaps docs trying to find a method a-like trigger(ev, x, y) but there seems to be none. Then I tried a pure javascript solution using MouseEvent() and dispatchEvent() on the Map DOM, but it also didn't work.
I have set up a simple fiddle with what I want to work: http://jsfiddle.net/k11yfz58/1/
If we coment the #overlay div, we get an alert when we click in a state. I want the same behavior but clicking on the overlay div, is that possible?
Thanks!
EDIT
It was suggested to use the pointer-events CSS property for this. That does not solve my problem because I also need the events to be triggered on the #overlay div.
You can add this to your css:
#overlay {
pointer-events: none;
}
From MDN:
The pointer-events CSS property specifies under what circumstances (if any) a particular graphic element can become the target of mouse events.
and the none value:
none
The element is never the target of mouse events; however, mouse events may target its descendant elements if those descendants have pointer-events set to some other value. In these circumstances, mouse events will trigger event listeners on this parent element as appropriate on their way to/from the descendant during the event capture/bubble phases.
What this means is that your overlay element is "invisible" to mouse events, and thus mouse events occur on the div below.

Capture Scroll Event on Element with overflow: hidden Using Javascript

EDIT: Thanks for the comments so far! Here's a JS fiddle with (hopefully all of) the relevant code:
https://jsfiddle.net/3y1cw6nt/
I have an image slider set up where the images' classes are toggled between .above, .active and .below, and their top: attribute changes accordingly.
At the moment the toggle is activated by an event listener for up and down arrow key presses, and I have html, body { height: 100vh, overflow: hidden } so that the user can't scroll to the the images which are .below or .above.
Is there a way to still capture scroll up and down events and trigger the class changes using Javascript?
I've tried this solution, but it isn't working - var st is undefined no matter what I do to the page, which I guess is because no scroll event is being captured and therefore var st is never declared.
Thanks a lot!
The body doesn't scroll, so there is no scroll event.
Have a look at a different set of events: mousemove, touch. Support for touch events can be rather varied across devices, so perhaps a library like Hammer would also come in handy.

Apply gradient over page without hindering user interaction [duplicate]

I have a div that has background:transparent, along with border. Underneath this div, I have more elements.
Currently, I'm able to click the underlying elements when I click outside of the overlay div. However, I'm unable to click the underlying elements when clicking directly on the overlay div.
I want to be able to click through this div so that I can click on the underlying elements.
Yes, you CAN do this.
Using pointer-events: none along with CSS conditional statements for IE11 (does not work in IE10 or below), you can get a cross browser compatible solution for this problem.
Using AlphaImageLoader, you can even put transparent .PNG/.GIFs in the overlay div and have clicks flow through to elements underneath.
CSS:
pointer-events: none;
background: url('your_transparent.png');
IE11 conditional:
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='your_transparent.png', sizingMethod='scale');
background: none !important;
Here is a basic example page with all the code.
Yes, you CAN force overlapping layers to pass through (ignore) click events.
PLUS you CAN have specific children excluded from this behavior...
You can do this, using pointer-events
pointer-events influences the reaction to click-, tap-, scroll- und hover events.
In a layer that should ignore / pass-through mentioned events you set
pointer-events: none;
Children of that unresponsive layer that need to react mouse / tap events again need:
pointer-events: auto;
That second part is very helpful if you work with multiple overlapping div layers (probably some parents being transparent), where you need to be able to click on child elements and only that child elements.
Example usage:
.parent {
pointer-events:none;
}
.child {
pointer-events:auto;
}
<div class="parent">
I'm unresponsive
I'm clickable again, wohoo !
</div>
Allowing the user to click through a div to the underlying element depends on the browser. All modern browsers, including Firefox, Chrome, Safari, and Opera, understand pointer-events:none.
For IE, it depends on the background. If the background is transparent, clickthrough works without you needing to do anything. On the other hand, for something like background:white; opacity:0; filter:Alpha(opacity=0);, IE needs manual event forwarding.
See a JSFiddle test and CanIUse pointer events.
I'm adding this answer because I didn’t see it here in full. I was able to do this using elementFromPoint. So basically:
attach a click to the div you want to be clicked through
hide it
determine what element the pointer is on
fire the click on the element there.
var range-selector= $("")
.css("position", "absolute").addClass("range-selector")
.appendTo("")
.click(function(e) {
_range-selector.hide();
$(document.elementFromPoint(e.clientX,e.clientY)).trigger("click");
});
In my case the overlaying div is absolutely positioned—I am not sure if this makes a difference. This works on IE8/9, Safari Chrome and Firefox at least.
Hide overlaying the element
Determine cursor coordinates
Get element on those coordinates
Trigger click on element
Show overlaying element again
$('#elementontop').click(e => {
$('#elementontop').hide();
$(document.elementFromPoint(e.clientX, e.clientY)).trigger("click");
$('#elementontop').show();
});
I needed to do this and decided to take this route:
$('.overlay').click(function(e){
var left = $(window).scrollLeft();
var top = $(window).scrollTop();
//hide the overlay for now so the document can find the underlying elements
$(this).css('display','none');
//use the current scroll position to deduct from the click position
$(document.elementFromPoint(e.pageX-left, e.pageY-top)).click();
//show the overlay again
$(this).css('display','block');
});
I currently work with canvas speech balloons. But because the balloon with the pointer is wrapped in a div, some links under it aren't click able anymore. I cant use extjs in this case.
See basic example for my speech balloon tutorial requires HTML5
So I decided to collect all link coordinates from inside the balloons in an array.
var clickarray=[];
function getcoo(thatdiv){
thatdiv.find(".link").each(function(){
var offset=$(this).offset();
clickarray.unshift([(offset.left),
(offset.top),
(offset.left+$(this).width()),
(offset.top+$(this).height()),
($(this).attr('name')),
1]);
});
}
I call this function on each (new) balloon. It grabs the coordinates of the left/top and right/down corners of a link.class - additionally the name attribute for what to do if someone clicks in that coordinates and I loved to set a 1 which means that it wasn't clicked jet. And unshift this array to the clickarray. You could use push too.
To work with that array:
$("body").click(function(event){
event.preventDefault();//if it is a a-tag
var x=event.pageX;
var y=event.pageY;
var job="";
for(var i in clickarray){
if(x>=clickarray[i][0] && x<=clickarray[i][2] && y>=clickarray[i][1] && y<=clickarray[i][3] && clickarray[i][5]==1){
job=clickarray[i][4];
clickarray[i][5]=0;//set to allready clicked
break;
}
}
if(job.length>0){
// --do some thing with the job --
}
});
This function proofs the coordinates of a body click event or whether it was already clicked and returns the name attribute. I think it is not necessary to go deeper, but you see it is not that complicate.
Hope in was enlish...
Another idea to try (situationally) would be to:
Put the content you want in a div;
Put the non-clicking overlay over the entire page with a z-index higher,
make another cropped copy of the original div
overlay and abs position the copy div in the same place as the original content you want to be clickable with an even higher z-index?
Any thoughts?
I think the event.stopPropagation(); should be mentioned here as well. Add this to the Click function of your button.
Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.
Just wrap a tag around all the HTML extract, for example
<a href="/categories/1">
<img alt="test1" class="img-responsive" src="/assets/photo.jpg" />
<div class="caption bg-orange">
<h2>
test1
</h2>
</div>
</a>
in my example my caption class has hover effects, that with pointer-events:none; you just will lose
wrapping the content will keep your hover effects and you can click in all the picture, div included, regards!
An easier way would be to inline the transparent background image using Data URIs as follows:
.click-through {
pointer-events: none;
background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
}
I think that you can consider changing your markup. If I am not wrong, you'd like to put an invisible layer above the document and your invisible markup may be preceding your document image (is this correct?).
Instead, I propose that you put the invisible right after the document image but changing the position to absolute.
Notice that you need a parent element to have position: relative and then you will be able to use this idea. Otherwise your absolute layer will be placed just in the top left corner.
An absolute position element is positioned relative to the first parent
element that has a position other than static.
If no such element is found, the containing block is html
Hope this helps. See here for more information about CSS positioning.
You can place an AP overlay like...
#overlay {
position: absolute;
top: -79px;
left: -60px;
height: 80px;
width: 380px;
z-index: 2;
background: url(fake.gif);
}
<div id="overlay"></div>
just put it over where you dont want ie cliked. Works in all.
This is not a precise answer for the question but may help in finding a workaround for it.
I had an image I was hiding on page load and displaying when waiting on an AJAX call then hiding again however...
I found the only way to display my image when loading the page then make it disappear and be able to click things where the image was located before hiding it was to put the image into a DIV, make the size of the DIV 10x10 pixels or small enough to prevent it causing an issue then hiding the containing div. This allowed the image to overflow the div while visible and when the div was hidden, only the divs area was affected by inability to click objects beneath and not the whole size of the image the DIV contained and was displaying.
I tried all the methods to hide the image including CSS display=none/block, opacity=0, hiding the image with hidden=true. All of them resulted in my image being hidden but the area where it was displayed to act like there was a cover over the stuff underneath so clicks and so on wouldn't act on the underlying objects. Once the image was inside a tiny DIV and I hid the tiny DIV, the entire area occupied by the image was clear and only the tiny area under the DIV I hid was affected but as I made it small enough (10x10 pixels), the issue was fixed (sort of).
I found this to be a dirty workaround for what should be a simple issue but I was not able to find any way to hide the object in its native format without a container. My object was in the form of etc. If anyone has a better way, please let me know.
I couldn't always use pointer-events: none in my scenario, because I wanted both the overlay and the underlying element(s) to be clickable / selectable.
The DOM structure looked like this:
<div id="outerElement">
<div id="canvas-wrapper">
<canvas id="overlay"></canvas>
</div>
<!-- Omitted: element(s) behind canvas that should still be selectable -->
</div>
(The outerElement, canvas-wrapper and canvas elements have the same size.)
To make the elements behind the canvas act normally (e.g. selectable, editable), I used the following code:
canvasWrapper.style.pointerEvents = 'none';
outerElement.addEventListener('mousedown', event => {
const clickedOnElementInCanvas = yourCheck // TODO: check if the event *would* click a canvas element.
if (!clickedOnElementInCanvas) {
// if necessary, add logic to deselect your canvas elements ...
wrapper.style.pointerEvents = 'none';
return true;
}
// Check if we emitted the event ourselves (avoid endless loop)
if (event.isTrusted) {
// Manually forward element to the canvas
const mouseEvent = new MouseEvent(event.type, event);
canvas.dispatchEvent(mouseEvent);
mouseEvent.stopPropagation();
}
return true;
});
Some canvas objects also came with input fields, so I had to allow keyboard events, too.
To do this, I had to update the pointerEvents property based on whether a canvas input field was currently focused or not:
onCanvasModified(canvas, () => {
const inputFieldInCanvasActive = // TODO: Check if an input field of the canvas is active.
wrapper.style.pointerEvents = inputFieldInCanvasActive ? 'auto' : 'none';
});
it doesn't work that way. the work around is to manually check the coordinates of the mouse click against the area occupied by each element.
area occupied by an element can found found by 1. getting the location of the element with respect to the top left of the page, and 2. the width and the height. a library like jQuery makes this pretty simple, although it can be done in plain js. adding an event handler for mousemove on the document object will provide continuous updates of the mouse position from the top and left of the page. deciding if the mouse is over any given object consists of checking if the mouse position is between the left, right, top and bottom edges of an element.
Nope, you can't click ‘through’ an element. You can get the co-ordinates of the click and try to work out what element was underneath the clicked element, but this is really tedious for browsers that don't have document.elementFromPoint. Then you still have to emulate the default action of clicking, which isn't necessarily trivial depending on what elements you have under there.
Since you've got a fully-transparent window area, you'll probably be better off implementing it as separate border elements around the outside, leaving the centre area free of obstruction so you can really just click straight through.

How to ensure CSS :hover is applied to dynamically added element

I have a script that adds full images dynamically over thumbnails when you hover over them. I've also given the full images a CSS :hover style to make them expand to a larger width (where normally they are constrained to the dimensions of the thumbnail). This works fine if the image loads quickly or is cached, but if the full image takes a long time to load and you don't move the mouse while it's loading, then once it does appear it will usually stay at the thumbnail width (the non-:hover style) until you move the mouse again. I get this behavior in all browsers that I've tried it in. I'm wondering if this is a bug, and if there's a way to fix or work around it.
It may be worth noting that I've also tried to do the same thing in Javascript with .on('mouseenter'), and encountered the same problem.
Due to the nature of the issue, it can be hard to reproduce, especially if you have a fast connection. I chose a largish photo from Wikipedia to demonstrate, but to make it work you might have to change it to something especially large or from a slow domain. Also note that you may have to clear the cache for successive retries.
If you still can't reproduce, you can add an artificial delay to the fullimage.load before the call to anchor.show().
HTML:
<img id="image" src="http://upload.wikimedia.org/wikipedia/commons/thumb/3/32/Cairo_International_Stadium.jpg/220px-Cairo_International_Stadium.jpg" />
CSS:
.kiyuras-image {
position: absolute;
top: 8px;
left: 8px;
max-width: 220px;
}
.kiyuras-image:hover {
max-width: 400px;
}
JS:
$(function () {
var fullimageurl = 'http://upload.wikimedia.org/wikipedia/commons/3/32/Cairo_International_Stadium.jpg';
var fullimage = $('<img/>')
.addClass('kiyuras-image')
.load(function () {
anchor.show();
});
var anchor = $('<a/>').hide().append(fullimage);
$('body').prepend(anchor);
$("#image").on('mouseenter', function () {
fullimage.attr('src',fullimageurl);
$(this).off('mouseenter');
});
});
JS Bin
Updated JS Bin with 1.5-second delay added (Hopefully makes issue clearer)
Again: Reproducing the issue involves clearing your cache of the large image, and then hovering over the original image to initial the loading of large image, then not moving your mouse while it's loading. Intended behavior is for the large image to properly take on the :hover pseudo-class when it eventually loads. Issue I see when it takes longer than ~0.75 secs to load is that it does not take on :hover until you jiggle the mouse a little.
Edit: See my comments on #LucaFagioli's answer for further details of my use case.
Edit, the sequel: I thought I already did this, but I just tried to reproduce the issue in Firefox and I couldn't. Perhaps this is a Chrome bug?
Most browsers update their hover states only when the cursor moves over an element by at least one pixel. When the cursor enters the thumbnail's img it gets hover applied and runs your mouseenter handler. If you keep your cursor still until the full-sized image loads, your old img (the thumbnail) will keep the hover state and the new one won't get it.
To get it working in these browsers, move the hover pseudo-class to a common parent element in the CSS; for example, enclose both imgs in a span.
If the selectors are correct, CSS will be applied to all elements, dynamic or otherwise. This includes all pseudo classes, and will change as attributes in the DOM change.
[Edit: while my explanation might be of interest, pozs' solution above is nicer, so I suggest using that if you can.]
The hover pseudo-class specification is quite relaxed concerning when it should be activated:
CSS does not define which elements may be in the above states,
or how the states are entered and left. Scripting may change
whether elements react to user events or not, and different
devices and UAs may have different ways of pointing to, or
activating elements.
In particular, it is not being activated when you update the visibility of the anchor element on load.
You can get around this fairly easily: copy the hover styles to a class, intercept the cursor moving over the element that it will eventually cover, and based on that add or remove your class from the element.
Demo: JS Bin (based on your delayed example).
Javascript:
$("#image")
.on('mouseenter', function () {
fullimage.attr('src',fullimageurl).toggleClass('mouseover', true);
$(this).off('mouseenter');
})
.mouseleave(function() {
fullimage.toggleClass('mouseover', false);
});
CSS:
.kiyuras-image:hover, .kiyuras-image.mouseover {
max-width: 400px;
}
TL;DR: You cannot rely on :hover applying to dynamically added elements underneath the cursor. However, there are workarounds available in both pure CSS and Javascript.
I'm upvoting both Jordan Gray and posz' answers, and I wish I could award them both the bounty. Jordan Gray addressed the issue re: the CSS specification in a somewhat conclusive way and offered (another) working fix that still allowed for :hover and other CSS effects like transitions, except on load. posz provided a solution that works even better and avoids Javascript for any of the hover events; I provide essentially the same solution here, but with a div instead of a span. I decided to award it to him, but I think Jordan's input was essential. I'm adding and accepting my own answer because I felt the need to elaborate more on all of this myself. (Edit: Changed, I accepted posz')
Jordan referenced the CSS2 spec; I will refer instead to CSS3. As far as I can tell, they don't differ on this point.
The pseudo-class in question is :hover, which refers to elements that the user has "designated with a pointing device." The exact definition of the behavior is deliberately left vague to allow for different kinds of interaction and media, which unfortunately means that the spec does not address questions like: "Should a new element that appears under the pointing device have this pseudo-class applied?" This is a hard question to answer. Which answer will align with user intent in a majority of cases? A dynamic change to a page the user is interacting with would normally be a result of ongoing user interaction or preparation for the same. Therefore, I would say yes, and most current browsers seem to agree. Normally, when you add an element under the cursor, :hover is immediately applied. You can see this here: The jsbin I originally posted. Note that if there's a delay in loading the larger image, you may have to refresh the page to get it to work, for reasons I'll go into.
Now, there's a similar case where the user activates the browser itself with the cursor held stationary over an element with a :hover rule; should it apply in that case? The mouse "hover" in this case was not a result of direct user interaction. But the pointing device is designating it, right? Besides, any movement of the mouse will certainly result in an unambiguous interaction. This is a harder question to answer, and browsers answer it in different ways. When you're activating them, Chrome and Firefox do not change :hover state until you move the mouse (Even if you activated them with a click!). Internet Explorer, on the other hand, updates :hover state as soon as it's activated. In fact, it updates it even when it's not active, as long as it's the first visible window under the mouse. You can see this yourself using the jsbin linked above.
Let's return to the first case, though, because that's where my current issue arises. In my case, the user hasn't moved the mouse for a significant length of time (over a second), and an element is added directly underneath the cursor. This could more easily be argued to be a case where user interaction is ambiguous, and where the pseudo-class should not be toggled. Personally, I think that it should still be applied. However, most browsers do not seem to agree with me. When you hover over the image for the first time and then do not move your mouse in this jsbin (Which is the one I posted in my question to demonstrate the issue, and, like the first one, has a straightforward :hover selector), the :hover class is not applied in current Chrome, Opera, and IE. (Safari also doesn't apply it, but interestingly, it does if you go on to press a key on the keyboard.) In Firefox, however, the :hover class is applied immediately. Since Chrome and Firefox were the only two I initially tested with, I thought this was a bug in Chrome. However, the spec is more or less completely silent on this point. Most implementations say nay; Firefox and I say aye.
Here are the relevant sections of the spec:
The :hover pseudo-class applies while the user designates an element with a pointing device, but does not necessarily activate it. For example, a visual user agent could apply this pseudo-class when the cursor (mouse pointer) hovers over a box generated by the element. User agents not that do not support interactive media do not have to support this pseudo-class. Some conforming user agents that support interactive media may not be able to support this pseudo-class (e.g., a pen device that does not detect hovering).
[...]
Selectors doesn't define if the parent of an element that is ‘:active’ or ‘:hover’ is also in that state.
[...]
Note: If the ‘:hover’ state applies to an element because its child is designated by a pointing device, then it's possible for ‘:hover’ to apply to an element that is not underneath the pointing device.
So! On to the workarounds! As several have zealously pointed out in this thread, Javascript and jQuery provide solutions for this as well, relying on the 'mouseover' and 'mouseenter' DOM events. I explored quite a few of those solutions myself, both before and after asking this question. However, these have their own issues, they have slightly different behavior, and they usually involve simply toggling a CSS class anyway. Besides, why use Javascript if it's not necessary?
I was interested in finding a solution that used :hover and nothing else, and this is it (jsbin). Instead of putting the :hover on the element being added, we instead put it on an existing element that contains that new element, and that takes up the same physical space; in this case, a div containing both the thumbnail and the new larger image (which, when not hovered, will be the same size as the div and thumbnail). This would seem to be fairly specific to my use case, but it could probably be accomplished in general using a positioned div with the same size as the new element.
Adding: After I finished composing this answer, pozs provided basically the same solution as above!
A compromise between this and one of the full-Javascript solutions is to have a one-time-use class that will effectively rely on Javascript/DOM hover events while adding the new element, and then remove all that and rely on :hover going forward. This is the solution Jordan Gray offered (Jsbin)
Both of these work in all the browsers I tried: Chrome, Firefox, Opera, Safari, and Internet Explorer.
From this part of your question: "This works fine if the image loads quickly or is cached, but if the full image takes a long time to load and you don't move the mouse while it's loading,"
Could it be worth while to "preload" all of the images first with JavaScript. This may allow all of the images to load successfully first, and it may be a little more user friendly for people with slower connections.
You could do something like that : http://jsfiddle.net/jR5Ba/5/
In summary, append a loading layout in front of your image, then append a div containing your large image with a .load() callback to remove your loading layer.
The fiddle above has not been simplified and cleaned up due to lack of time, but I can continue to work on it tomorrow if needed.
$imageContainer = $("#image-container");
$image = $('#image');
$imageContainer.on({
mouseenter: function (event) {
//Add a loading class
$imageContainer.addClass('loading');
$image.css('opacity',0.5);
//Insert div (for styling) containing large image
$(this).append('<div><img class="hidden large-image-container" id="'+this.id+'-large" src="'+fullimageurl+'" /></div>');
//Append large image load callback
$('#'+this.id+'-large').load(function() {
$imageContainer.removeClass('loading');
$image.css('opacity',1);
$(this).slideDown('slow');
//alert ("The image has loaded!");
});
},
mouseleave: function (event) {
//Remove loading class
$imageContainer.removeClass('loading');
//Remove div with large image
$('#'+this.id+'-large').remove();
$image.css('opacity',1);
}
});
EDIT
Here is a new version of the fiddle including the right size loading layer with an animation when the large picture is displayed : http://jsfiddle.net/jR5Ba/6/
Hope it will help
Don't let the IMG tag get added to the DOM until it has an image to download. That way the Load event won't fire until the image has been loaded. Here is the amended JS:
$(function () {
var fullimageurl = 'http://upload.wikimedia.org/wikipedia/commons/3/32/Cairo_International_Stadium.jpg';
var fullimage = $('<img/>')
.addClass('kiyuras-image')
.load(function () {
anchor.show(); // Only happens after IMG src has loaded
});
var anchor = $('<a/>').hide();
$('body').prepend(anchor);
$("#image").on('mouseenter', function () {
fullimage.attr('src',fullimageurl); // IMG has source
$(this).off('mouseenter');
anchor.append(fullimage); // Append IMG to DOM now.
});
});
I did that and it worked on Chrome (version 22.0.1229.94 m):
I changed the css as that:
.kiyuras-image{
position: absolute;
top: 8px;
left: 8px;
max-width: 400px;
}
.not-hovered{
max-width: 220px;
}
and the script this way:
$(function(){
var fullimageurl = 'http://upload.wikimedia.org/wikipedia/commons/3/32/Cairo_International_Stadium.jpg';
var fullimage = $('<img/>')
.addClass('kiyuras-image')
.load(function () {
anchor.show();
});
var anchor = $('<a/>').hide().append(fullimage);
$('body').prepend(anchor);
$('.kiyuras-image').on('mouseout',function(){
$(this).addClass('not-hovered');
});
$('.kiyuras-image').on('mouseover',function(){
$(this).removeClass('not-hovered');
});
$("#image").one('mouseover', function(){
fullimage.attr('src',fullimageurl);
});
});
Basically I think it's a Chrome bug in detecting/rendering the 'hover' status; in fact when I tried to simply change the css as:
.kiyuras-image{
position: absolute;
top: 8px;
left: 8px;
max-width: 400px;
}
.kiyuras-image:not(:hover) {
position: absolute;
top: 8px;
left: 8px;
max-width: 220px;
}
it still didn't worked.
PS: sorry for my english.
I'm not 100% sure why the :hover declaration is only triggered on slight mouse move. A possible reason could be that technically you may not really hover the element. Basically you're shoving the element under the cursor while it is loading (until the large image is completely loaded the A element has display: none and can therefore impossible be in the :hover state). At the same time, that doesn't explain the difference with smaller images though...
So, a workaround is to just use JavaScript and leave the :hover statement out of the equation. Just show the user the two different IMG elements depending on the hover state (toggles in JavaScript). As an extra advantage, the image doesn't have to be scaled up and down dynamically by the browser (visual glitch in Chrome).
See http://jsbin.com/ifitep/34/
UPDATE: By using JavaScript to add an .active class on the large image, it's entirely possible to keep using native CSS animations. See http://jsbin.com/ifitep/48

Trigger an event on a specific part of an image

I want to trigger an event handler when the user hovers on a particular part of the image, like the center of the image or the right side of the image (area would include, say, about a 100 pixels). I am not using any framework, so this is normal javascript that I am working with.
I am not sure if using image maps would work. Can anyone help?
Quirksmode about mouse position
Given the craziness involved here I would:
Use a framework (I just did something like this with Mootools)
Put absolutely positioned divs over the image and listen to events on them, instead of the image (did this too recently, a left 50% and a right 50%, way less cumbersome than tracking the mouse position).
Or go for it, quirksmode gives a decent function to get the mouse position, then you'll need to calculate the position of the image, then do the math to get the position of the mouse on the image, do the math in a mouseover event of the image, then continually check if the position meets your criteria, then do something about it when it does :)
You can use the MouseMove event to find out the location of the cursor, and then implement your own logic to calculate this position relative to the image.
See this page on getting the mouse coordinates.
i do not know how many areas you need and if they need to be especially shaped or something like that....
a straightforward solution would be placing (CSS) empty div elements "over" the image which will trigger the events
afaik it is not possible to trigger js events with an image map
An image map coupled with jquery is a great solution I've used before. I see that you're not using a framework, but it's worth a look.
Here's a little code snippet I used with an image map and mouseenter / mouseleave events.
$(".map-areas area")
.mouseenter(function() {
idx = $(".map-areas area").index(this);
showMapArea(idx);
})
.mouseleave(function() {
$(".map-hovers img").hide();
$(".map-titles img").hide();
});
I suggest putting an invisible div in the place where you want to check for mouse_over in the image. (In the case that the area you want is rectangular of course). And then trigger on mouse_over for this div.
If you want to check for non rectangular areas (that can't be a div), I would suggest that you put a div of the same size of the image on top of it. Check mouse position on that div, and use it to compare with a mask image.
Example:
MousePosOnGhostDiv_X = 76;
MousePosOnGhostDiv_Y = 145;
if(CheckColorOfMaskImage(MousePosOnGhostDiv_X,MousePosOnGhostDiv_Y)=="orange") do something.
By knowing which color it is on the mask image you can set multiple events.

Categories

Resources