Mousemove offset messes up hover effect - javascript

I'm working on a website, and I wanted to do a little extra in the context of the subject (a shooting range) in the menubar. When a user hovers onto the element, a little crosshair would appear next to the cursor and the image would follow the cursor while in the li element.
However it seems a little off sometimes, as in if you keep moving a mouse on the list elements, sometimes the shadow-y hover effect (which is a css :hover thing) gets stuck on the last element. You can see it here. (Just move the mouse on the menu elements.)
At first I thought it's a css problem, but after fiddling with both css and js, it seems to be a javascript problem. If I comment out the "offset" lines, it's working fine. Later I have tried switching out the jquery function to native javascript, but the bug(?) still happens when the offset lines are commented out.
I've found that setting the offset can be slow. Would that cause my problem?
How could I solve this?
Thank you for your help/advice!
This is my jQuery code:
$("nav li").mousemove(function(e) {
var $img = $(this).find("img.crosshair");
$img.css("display", "inline-block");
$img.offset({left:e.pageX-10,top:e.pageY-10});
});
And this is the native javascript:
var menu = document.querySelectorAll("nav li");
for (var i = 0; i < menu.length; i++) {
var elem = menu[i];
elem.addEventListener("mousemove", function(e) {
var img = this.querySelector("img.crosshair");
img.style.display = "inline-block";
img.style.left = (parseInt(e.pageX, 10) - 10) + "px";
img.style.top = (parseInt(e.pageY, 10) - 10) + "px";
});
}

I'd suggest to use only one img.crosshair in your code.. first try to reconstuct your html something like this: (remove redundant img's from each li)
<section class="header">
<img class="crosshair" src="images/xhair.png">
<nav>
<ul>
<li><img class="bullet_hole" src="images/bullet_hole.png">A lőtér</li>
<li><img class="bullet_hole" src="images/bullet_hole.png">Fegyverek</li>
<li><img class="bullet_hole" src="images/bullet_hole.png">Szolgáltatásaink</li>
</ul>
</nav>
<div class="logo">
<img src="images/logo.png"></div>
<nav>
<ul>
<li><img class="bullet_hole" src="images/bullet_hole.png">Egyesület</li>
<li><img class="bullet_hole" src="images/bullet_hole.png">Galéria</li>
<li><img class="bullet_hole" src="images/bullet_hole.png">Információk</li>
</ul>
</nav>
</section>
then try to use jquery like this one below ,, fix the position of image on hover to your needs and that should cover it..
$(document).ready(function() {
$("nav li").click(function(e) {
var $img = $(this).find("img.bullet_hole");
$img.css("display", "inline-block");
$img.offset({left:e.pageX-20,top:e.pageY-10});
setTimeout( function(){
$img.css("display", "none");
},4000);
});
$("nav li").mousemove(function(e) {
var $img = $(this).closest('.header').find("img.crosshair");
$img.css("display", "inline-block");
$img.offset({left:e.pageX-10,top:e.pageY-10});
});
$("nav li").mouseout(function(e) {
var $img = $(this).closest('.header').find("img.crosshair");
$img.css("display", "none");
});
});
the thing that was happening is that hover over each li moved sometimes TWO images when you hovered over one li and one before when mouseover event propagated in browser,, that's where glitch happend
hth, cheers and good luck

Related

Use Javascript to make image go back to original - OpenCart 2.3

I wrote some JS that lets me replace the main image on a product page with that a different image. This part is working great. However, I need the original image to return once the mouse leaves. I cannot get this to work.
Also, I would like to add a delay to this so that when I remove the mouse there is like a 1/4 second delay before changing back to the original image. This is all being done on the product page of OC 2.3.
this.imagePreview = function(){
$("a.preview").mouseleave(function(e){
$("#image").attr("src",default_image);
});
$("a.preview").hover(function(e){
$("#image").attr("src",this.rel);
});
$(document).ready(function(){
default_image = $("#image").attr("src");
imagePreview();
});
Can someone help me write this little bit of extra code? Everything else I've tried doesnt work.
You can get the desired result using JavaScript.
(function() {
var img, defaultImage, preview, i, hnd;
img = document.getElementById("image"); // Gets the image element.
defaultImage = img.src; // Sets the image src attribute to the defaultImage variable.
preview = document.querySelectorAll(".preview"); // Gets the elements with css selector is «.preview».
for (i = 0; i < preview.length; i++) {
/* Adds the mouseover event to the preview element. */
preview[i].addEventListener("mouseover", function() {
img.src = this.rel;
clearTimeout(hnd); // Reset the timeout handler.
});
/* Adds the mouseleave event to the preview element. */
preview[i].addEventListener("mouseleave", function() {
hnd = setTimeout(function() {
img.src = defaultImage;
}, 250); // 1/4 second delay.
});
}
})();
#list li {
margin: 10px;
}
<img id="image" src="https://cdn1.iconfinder.com/data/icons/technology-and-hardware-2/200/vector_66_08-32.png" />
<ul id="list">
<li>
<a class="preview" href="#" rel="https://cdn3.iconfinder.com/data/icons/device-icons-2/512/BT_computer-32.png">Computer</a>
</li>
<li>
<a class="preview" href="#" rel="https://cdn4.iconfinder.com/data/icons/48-bubbles/48/29.Mac-32.png">Mac</a>
</li>
<li>
<a class="preview" href="#" rel="https://cdn2.iconfinder.com/data/icons/crystalproject/32x32/devices/laptop.png">Laptop</a>
</li>
</ul>
Try this code:
$("a.preview").mouseleave(function(){
setTimeout(function () {
var default_image = $("#defaultImage").attr("src");
$("#image").attr("src",default_image);
}, 3000);
});

circular linked list not working as expected (jquery)

I created a circular linked list to transverse through an ul of images (i made an image gallery and am using the linked list to go through the images with the left and right arrow keys). Everything works fine until I get to the end of the list and try to go back to the first picture (or pressing left, when i get to the beginning and try to get to the last). This is my first time using jQuery and I'm not very good with circular linked lists (i only had to use one once--for school) and it seems like the problem is the if/else statement in my getNextPic function.
BTW I know this is really sloppy. Like I said, first time, so I'm sorry if it's a little difficult to follow. I'm posting a lot of my code because I always see people on here not posting enough to find the problem. Most of this i know works fine. The problem lies in getNextPic function as I said, 3rd snippet down. Thank you to anyone who attempts to help :)
here is a fiddle
html
<div id="gallery">
<div id="main">
<img id="main_img" src="d:/allyphotos/amanda_1.jpg" alt=""/></div>
<div id="thumbnail">
<ul>
<li><img class="thumb" id="long" src="d:/allyphotos/thumb/olivia_2.jpg"/></li>
<li><img class="thumb" id="long" src="d:/allyphotos/thumb/autumn_1.jpg"/></li>
<li><img class="thumb" id="long" src="d:/allyphotos/thumb/olivia_2.jpg"/></li>
<li><img class="thumb" id="long" src="d:/allyphotos/thumb/autumn_1.jpg"/></li>
<li><img class="thumb" id="long" src="d:/allyphotos/thumb/olivia_2.jpg"/></li>
<li><img class="thumb" id="long" src="d:/allyphotos/thumb/autumn_1.jpg"/></li>
<li><img class="thumb" id="long" src="d:/allyphotos/thumb/olivia_2.jpg"/></li>
<li><img class="thumb" id="long" src="d:/allyphotos/thumb/autumn_1.jpg"/></li>
</ul>
</div>
</div>
jQuery
document ready function
$(document).ready(function(){
//these ($first and $last) dont change
var $first = $('li:first img', '#gallery ul');
var $last = $('li:last img', '#gallery ul');
//set to current selected image to be displayed
var current = $first;
var previousImage = current;
runGallery(current, $first, $last, previousImage);
});
my runGallery function
function runGallery($current, $first, $last, previousImage){
//first and last thumbnails, selected and current
$("body").keydown(function(e){
// left arrow pressed
if ((e.keyCode || e.which) == 37)
{ $current = getNextPic($current, $first, $last, false);//false gets previous img, true gets following img
fade($current, previousImage);//fade selected, unfade previously selected
previousImage=$current;
var newlink = $($current).attr('src').replace('thumb/', '');
$('#main_img').attr('src', newlink);//set $current to main_img
}
// right arrow pressed
if ((e.keyCode || e.which) == 39)
{
$current = getNextPic($current, $first, $last, true);
fade($current, previousImage);
previousImage=$current;
var newlink = $($current).attr('src').replace('thumb/', '');
$('#main_img').attr('src', newlink);
}
});
$("#gallery li img").click(function()
{
//fade selected and unfade previous selected
fade(this, previousImage);
$current = this;
previousImage = this;
//get src for clicked thumb and change to full version
var newlink = $(this).attr('src').replace('thumb/', '');
$('#main_img').attr('src', newlink);
});
var imgSwap =[];
$("gallery li img").each(function()
{
imgUrl = this.src.replace('thumb/','');
imgSwap.push(imgUrl);
});
$(imgSwap).preload();
}
my getNextPic function -- this is where I believe the problem lies. I have commented the lines that aren't working properly
function getNextPic(current, first, last, boolval)
{
var next = $(current).closest('li');
if(boolval===true)
{
if(current === last)
{
next = first;//this seems to never happen???
}
else
{
next = $(next).next('li');
next = $(next).find('img');
}
}
else
{
if(current === first)
{
next = last;//this also never happens
}
else
{
next = $(next).prev();
next = $(next).find('img');
}
}
return next;
}
my fade function, 99.999% sure this has absolutely nothing to do with the problem but posting it anyway
function fade(current, previous)
{
$(previous).fadeTo('fast',1);
$(current).fadeTo('fast', 0.5);
}
The preload function, which i did not write (i got it from a tutorial) but i know isnt contributing to the problem. Posting so anyone who looks can rule it out too.
$.fn.preload = function(){
this.each(function(){
$('<img/>')[0].src=this;
});
}
Comparison of jquery objects cannot be done directly.
Your code contains, for example
current === last
Instead, as suggested in this answer, use the inner object:
You need to compare the raw DOM elements, e.g.:
if ($(this).parent().get(0) === $('body').get(0))
or
if ($(this).parent()[0] === $('body')[0])
Check out this fixed fiddle for your expected results.

Use $(window).scroll function to jump to divs on a page

Im trying to mimic the functionality of this site https://moto360.motorola.com/
When you scroll down on that page it just jumps to the next "screen" and if you scroll up it jumps back up.
My JS is here :
var currentDiv = "Home";
var latestScroll = 0;
var scrollable = true;
$(document).ready(function(){
$("#HomeLink").addClass("activeNav");
$(".navLink").click(function(){
$(".navLink").removeClass("activeNav");
$(this).addClass("activeNav");
var divID = $(this).attr("data-linkID");
scrollTo(divID);
});
$(window).scroll(function(){
console.log(scrollable);
if (scrollable==true){
var currentScroll = $(window).scrollTop();
if (currentScroll > latestScroll){
scrollable = false;
//downscroll
if(currentDiv!="About"){
var nextDiv = $("#"+currentDiv).next()[0];
var nextDivID = $(nextDiv).attr("id");
scrollTo(nextDivID);
}
}else{
scrollable = false;
//upscroll
if(currentDiv!="Home"){
var prevDiv = $("#"+currentDiv).prev()[0];
var prevDivID = $(prevDiv).attr("id");
scrollTo(prevDivID);
}
}
}
});
});
function scrollTo(divID){
currentDiv = divID;
var target = $("#"+divID);
$('html,body').animate({
scrollTop: target.offset().top
}, 500);
setTimeout(function() {
// Do something after 2 seconds
latestScroll = target.offset().top;
scrollable = true;
}, 2000);
}
My problem is that once it starts scrolling it jumps to the next screen but then when the jQuery animate is running it registers more scrolls and then just keeps jumping. I've tried adding the boolean scrollable and even a timeout when setting that back to true but it still will jump at least twice.
HTML :
<div id="screens">
<div class="screen" id="Home">
<div id="logo">ZEPPA</div>
</div>
<div class="screen" id="Video">
<iframe width="100%" height="100%" src="http://www.youtube.com/embed/XGSy3_Czz8k"></iframe>
</div>
<div class="screen" id="Info">INFO</div>
<div class="screen" id="About">ABOUT US</div>
</div>
Anyone have any ideas on how to fix this? I cannot seem to find a way to get it to only register the scrolling once and then reset itself nicely.
I have a fiddle here: http://jsfiddle.net/a1cpx2cf/
I would recommend you to make use of a tested plugin like fullPage.js rather than trying to reinvent the wheel.
Things will become more complicated when you start worrying about touch screen computers, mobile phones, kinetic scrolling (used in Apple laptops), transitions performance, fallback compatibility with old browsers, keyboard accessibility, changes in the URL for each section, useful URLs for returning users or specific linking etc.
Using a tested script will always make things easier and will save you many headaches.

Image highlight (hover state) on active section while scrolling?

I have these icons above each section on my page (the largish circular icons, please see example: http://pftest.fhero.net) with colored hover states... what I would really love to do is have them change to the active hover states as the user scrolls to each section (preferably with a simple fade transition) - much like the effect of highlighting the active links/section in the navigation.
There are many tutorials, plugins and questions on this site and so forth for highlighting active sections in a navigation however, but doesn't seem to be much that I can find relating to applying the effect to another div or image on the page...
I'm definitely not any kind of jQuery expert but I'm wondering if one of the myriad of scripts/plugins available which are typically used for highlighting active states in navigation could simply be adapted to this scenario somehow to achieve the same effect? Perhaps even the one I am currently using on my page?
Here is the script I'm using for highlighting the active section in the navigation on my page:
/* Scroll Navigation highlight */
$("#work-section1").parent().addClass('active');
var main = main = $('#mainmenu ul');
$('.scroll').click(function(event) {
event.preventDefault();
var full_url = this.href,
parts = full_url.split('#'),
trgt = parts[1],
target_offset = $('#'+trgt).offset(),
target_top = target_offset.top;
$('html, body').animate({scrollTop:target_top}, 500);
/* Remove active class on any li when an anchor is clicked */
main.children().removeClass();
/* Add active class to clicked anchor's parent li */
$(this).parent().addClass('active');
});
$(window).scroll(function(event) {
if($("#work-section").offset().top < $(window).scrollTop() + $(window).outerHeight()){
$("#work-section1").parent().addClass('active');
$("#about-section1").parent().removeClass('active');
$("#footer-section").parent().removeClass('active');
$("#services-section1").parent().removeClass('active');
$("#process-section1").parent().removeClass('active');
}
if($("#about-section").offset().top < $(window).scrollTop() + $(window).outerHeight()) {
$("#about-section1").parent().addClass('active');
$("#work-section1").parent().removeClass('active');
$("#footer-section1").parent().removeClass('active');
$("#services-section1").parent().removeClass('active');
$("#process-section1").parent().removeClass('active');
}
if($("#services-section").offset().top < $(window).scrollTop() + $(window).outerHeight()){
$("#services-section1").parent().addClass('active');
$("#about-section1").parent().removeClass('active');
$("#work-section1").parent().removeClass('active');
$("#footer-section1").parent().removeClass('active');
$("#process-section1").parent().removeClass('active');
}
if($("#process-section").offset().top < $(window).scrollTop() + $(window).outerHeight()){
$("#process-section1").parent().addClass('active');
$("#about-section1").parent().removeClass('active');
$("#work-section1").parent().removeClass('active');
$("#footer-section1").parent().removeClass('active');
$("#services-section1").parent().removeClass('active');
}
if($("#footer-section").offset().top < $(window).scrollTop() + $(window).outerHeight()){
$("#footer-section1").parent().addClass('active');
$("#about-section1").parent().removeClass('active');
$("#work-section1").parent().removeClass('active');
$("#services-section1").parent().removeClass('active');
$("#process-section1").parent().removeClass('active');
}
});
and the HTML:
<nav id="mainmenu" name="mainmenu">
<ul>
<li><a class="scroll" id="work-section1" href="#work-section">Works</a></li>
<li><a class="scroll" id="about-section1" href="#about-section">About</a></li>
<li><a class="scroll" id="services-section1" href="#services-section">Services</a></li>
<li><a class="scroll" id="process-section1" href="#process-section">Process</a></li>
<li><a class="scroll" id="footer-section1" href="#footer-section">Contact</a></li>
</ul>
</nav>
<section id="about-section" data-anchor-offset="90">
<section id="work-section" data-anchor-offset="90">
...ect...
Could this somehow be adapted to accomplish the effect I am looking for? Or any other/better methods, or plugins I should be looking at?
I should add that the icons use the sprites method which could make the CSS side of things a little trickier, although I would be willing to change them to non-sprite images if necessary...
You could use a small little function for this, that checks if a element is on screen. I set up a little JSFiddle for you: http://jsfiddle.net/LHrkB/1/
Code:
function isElementVisible(elementToBeChecked)
{
var TopView = $(window).scrollTop();
var BotView = TopView + $(window).height();
var TopElement = $(elementToBeChecked).offset().top;
var BotElement = TopElement + $(elementToBeChecked).height();
return ((BotElement <= BotView) && (TopElement >= TopView));
}
$(window).scroll(function () {
isOnView = isElementVisible(".inview");
if(isOnView){
//What to do when element is visible
$(".inview").css({"background":"#ccc"});
}else{ // If not visible
}
});
Ok, so i have changed the JSFiddle a bit, now it uses a fadeIn on a invisible element when it comes into view: http://jsfiddle.net/LHrkB/2/
Ok, i changed the JSFiddle once again. When you scroll in the results pane, and you play around with it a bit you can see the element change class as it comes on screen and also when it goes away again. I commented the JS so you can see what it does and where it does it. http://jsfiddle.net/LHrkB/4/
Thanks to the help of Veritas87 (who is super awesome), managed to get it all working with the following code:
function isElementVisible(elementToBeChecked)
{
var TopView = $(window).scrollTop();
var BotView = TopView + $(window).height();
var TopElement = $(elementToBeChecked).offset().top;
var BotElement = TopElement + $(elementToBeChecked).height();
return ((BotElement <= BotView) && (TopElement >= TopView));
}
$(window).scroll(function () {
isOnView = isElementVisible(".about-icon");
if(isOnView){
//What to do when element is visible
$('.about-icon').addClass('about-icon-active');
}else{ // If not visible
$('.about-icon').removeClass('about-icon-active');
}
isOnView = isElementVisible(".works-icon");
if(isOnView){
//What to do when element is visible
$('.works-icon').addClass('works-icon-active');
}else{ // If not visible
$('.works-icon').removeClass('works-icon-active');
}
isOnView = isElementVisible(".services-icon");
if(isOnView){
//What to do when element is visible
$('.services-icon').addClass('services-icon-active');
}else{ // If not visible
$('.services-icon').removeClass('services-icon-active');
}
isOnView = isElementVisible(".process-icon");
if(isOnView){
//What to do when element is visible
$('.process-icon').addClass('process-icon-active');
}else{ // If not visible
$('.process-icon').removeClass('process-icon-active');
}
});
with the "...icon-active" classes of course containing the style for the icon hover states.

is(:hover) alternative for ie & firefox

I a have a menu, which on rollover shows a div which is not a child of the menu and when you roll off it hides that div again. The div is placed directly below the menu item, mimicking a submenu.
the html looks something like this -
Here is my menu -
<div id="nav">
<ul>
<li class='with_panel'>
<span id='panel1' class='current'><img src='theImage' /></span>
</li>
<!-- more list items -->
</ul>
</div>
In an unrelated div, I have this -
<div id="panels">
<div style="" id="panel1_panel" class="panel">
<img src="myImage.png">
</div>
<div>
I have some jquery that shows and hides the related panel when you rollover the li -
$("#nav .with_panel").mouseenter(function(){
var id = $(this).find("span").attr("id");
$(".panel").removeClass("open");
$panel = $("#" + id + "_panel");
$panel.addClass("open");
$img = $(this).find("span img");
$img.addClass("on");
var hide = function(){
if(!$panel.is(":hover")){
$img.removeClass("on");
$panel.removeClass("open");
}
}
$panel.mouseleave(hide);
$(this).mouseleave(hide);
})
This only seems to work in Chrome, and I'm fairly certain it's due to ie & Firefox not recognising .is(":hover").
I can't change the html structure, only the javascript. So I'm struggling on getting it to work cross browser. Any ideas?
The following code gives you 200 ms timeout (hide_to) to leave the menu and enter your panel before hiding it. Works the other way too. If you mouseenter the menuitem or the panel the timeout for the hiding is cancelled, and restarted when the mouse leaves any of them.
$("#nav .with_panel").each(function() {
var id = $(this).find("span").attr("id"),
$panel = $("#" + id + "_panel"),
$img = $(this).find("span img"),
hide_to = null;
var hide = function() {
// start hide timeout
hide_to = window.setTimeout(function () {
$img.removeClass("on");
$panel.removeClass("open");
},200);
};
var show = function() {
// clear hide timeout
window.clearTimeout(hide_to);
if (!$panel.is(".open"))
{
// open panel, only if it is not open already
$(".panel").removeClass("open");
$panel.addClass("open");
$img.addClass("on");
}
};
$(this).mouseenter(function() {
show();
}).mouseleave(function() {
hide();
});
$panel.mouseenter(function() {
show();
}).mouseleave(function() {
hide();
});
});
Try mouseover instead of mouseenter and mouseout instead of mouseleave.
For example:
$("#nav .with_panel").mouseover(function(){
var id = $(this).find("span").attr("id");
$(".panel").removeClass("open");
$panel = $("#" + id + "_panel");
$panel.addClass("open");
$img = $(this).find("span img");
$img.addClass("on");
var hide = function(){
if(!$panel.is(":hover")){
$img.removeClass("on");
$panel.removeClass("open");
}
}
$panel.mouseout(hide);
$(this).mouseout(hide);
})
It appears that .is(":hover") is actually broken for all browsers, as of jQuery 1.9.1. Bummer. The following is tested with FF, IE10, and Chrome (sorry don't have Opera) with jQuery 1.9.1. Opera users, please comment on whether this works on Opera.
function isHovered(elt){
var temp = $(elt).parent().find(":hover");
return temp.length == 1 && temp[0] == elt;
}
Then replace
$panel.is(":hover")
by
isHovered($panel[0])
otherwise, leave all your code as is.
fiddle: http://jsfiddle.net/mathheadinclouds/BxL4w/

Categories