Why my div shake after Javascript events are executed? - javascript

This is supposed to happen:
I mouseover my box, the box moves 50px to the right, and when I mouseleave the box, the box returns to its original position.
This happens:
The box moves to the right when mouseover, and moves to its original position when I mouseleave. But if I do this a few times, the box starts shaking. The more times I do it, the more it shakes.
How do I keep it from shaking after I mouseover/mouseleave several times?
I assume I need some sort of removeEventListener inside the functions, and addEventListeners, but I am farely new to this stuff.
const box1 = document.getElementById("divContainer");
let box1Left = parseInt(box1.style.marginLeft = 0 + "px");
function moveBox1Right() {
let id = null;
clearInterval(id);
id = setInterval(x, 5);
function x() {
if (box1Left == 50) {
clearInterval(id);
} else {
box1Left++;
box1.style.marginLeft = box1Left + "px";
}
}
}
box1.addEventListener("mouseover", moveBox1Right)
function moveBox1Left() {
let id = null;
clearInterval(id);
id = setInterval(y, 5);
function y() {
if (box1Left >= 1) {
box1Left--;
box1.style.marginLeft = box1Left + "px";
} else {
clearInterval(id);
}
}
}
box1.addEventListener("mouseleave", moveBox1Left);
#divContainer {
height: 100px;
width: 100px;
background-color: #c5c5c5;
}
<div id="divContainer">
</div>

If you mouse in/out during the "animation" both intervals can theoretically be active at the same time, causing the shake. The intervals are only cancelled when it reaches it's end condition, not when another interval is started, the mouse enters/leaves, or the direction is presumably intended to change.
You may want to share id between the two functions as your clearInterval(id) at the start of each function does nothing (id = null in the line before always means you're clearing null).
Better, you may want to consider using CSS animate which can solve this issue fairly elegantly.

Move the timeout reference (let id) outside the functions.
It is pointless to clear the id if you set it to null and you need to share it and use the reference when you clear it
let id;
function moveBox1Right() {
clearInterval(id);
...
function moveBox1Left() {
clearInterval(id);

Related

Pure js add and remove (toggle) class after scrolling x amount?

I don't want to use jQuery for this.
It's really simple, I just want to add a class after scrolling past a certain amount of pixels (lets say 10px) and remove it if we ever go back to the top 10 pixels.
My best attempt was:
var scrollpos = window.pageYOffset;
var header = document.getElementById("header");
function add_class_on_scroll() {
header.classList.add("fade-in");
}
function remove_class_on_scroll() {
header.classList.remove("fade-in");
}
window.addEventListener('scroll', function(){
if(scrollpos > 10){
add_class_on_scroll();
}
else {
remove_class_on_scroll();
}
console.log(scrollpos);
});
But console shows a number that continues to grow regardless of scrolling up or down. And the class fade-in never gets added, though console shows we past 10.
You forgot to change the offset value in the scroll handler.
//use window.scrollY
var scrollpos = window.scrollY;
var header = document.getElementById("header");
function add_class_on_scroll() {
header.classList.add("fade-in");
}
function remove_class_on_scroll() {
header.classList.remove("fade-in");
}
window.addEventListener('scroll', function(){
//Here you forgot to update the value
scrollpos = window.scrollY;
if(scrollpos > 10){
add_class_on_scroll();
}
else {
remove_class_on_scroll();
}
console.log(scrollpos);
});
Now you code works properly
Explanation
There is no documentation for that, like you asked for. This is just an issue in the logic workflow.
When you say that scrollpos = window.scrollY your page is at an top-offset of 0, so your variable stores that value.
When the page scrolls, your scroll listener will fires. When yout listener checks for the scrollpos value, the value is still 0, of course.
But if, at every scroll handler, you update the scrollpos value, now you can have a dynamic value.
Another option is you to create a getter, like
var scrollpos = function(){return window.scrollY};
This way you can dynamically check what that method will return for you at every offset.
if(scrollpos() > 10)
See? Hope that helped. (:
One simple way to achieve what you want (one line of code inside the scroll event):
window.addEventListener('scroll', function(e) {
document.getElementById('header').classList[e.pageY > 10 ? 'add' : 'remove']('fade-in');
});
#header {
height: 600px;
}
.fade-in {
background-color: orange;
}
<div id='header'></div>
just use the method toggle in classList
header.classList.toggle('fade-in')

onmouseover-triggered function keeps triggering on mouse over

I have a function, which is triggered when the mouse goes over a div.
The div contains a link, which is 100% height and width of the containing div. The link contains an image, which the function moves when onmouseover the grandparent (the div).
The function moves the image to the right and then back to the middle.
When I move the mouse over the div the function is triggered but moves the image by only 5px (one loop of the function) and keeps moving it 5px when I move the mouse around - the function is not looping and just loops once on every onmouseover.
<div onmouseover="jotArrow(this);" class="latest-entry latest-entry-third" id="news-link-home">
<a class="home-square-link" href="hello.php">Reviews<br/><img src="<?php echo $config['file_path']; ?>/images/squares-arrow.png" width="60px"/></a>
</div>
JS:
var arrowPos = 0;
var Arrow;
function jotArrow(arrow)
{
Arrow = arrow.getElementsByTagName('img')[0];
if (arrowPos < 50) {
arrowPos = arrowPos + 5;
Arrow.style.left = arrowPos + 'px';
setTimeout(jotArrow, 10);
} else {
jotArrowBack(arrow)
}
}
function jotArrowBack(arrow)
{
if (arrowPos > 0) {
arrowPos = arrowPos - 5;
Arrow.style.left = arrowPos + 'px';
setTimeout(jotArrowBack, 10);
}
}
To make sure the code is correct, I modified it a little (from that above) so that it makes an image in a different div move (onmouseover of div1 causes div2 image to move). And it worked fine.
So I am guessing it has something to do with the image being inside the div and the mouse goes over more than one element. But really I don't see why this would be an issue as the function does not care about onmouseout it should just perform it's whole task on the first onmouseover.
I have tried putting the onmouseover attribute on all three elements (the div, the a and the img) separately and all at the same time - same problem.
Your code appears to have two problems. As you mentioned, you get multiple mouseover events which confuse the code, but the other problem is that jotArrow fetches the Arrow element every time, and the second time it can't find it because your setTimeout call doesn't pass the parameter. When you switch the code to move another element I assume you just write something like document.getElementById('blah') which picks up the same element each time.
One approach would be to use a helper function initArrow, something like this:
function initArrow(arrow)
{
if (arrowPos == 0) {
Arrow = arrow.getElementsByTagName('img')[0];
jotArrow();
}
}

Variables won't increment in a jQuery function?

I was just doing some last minute touches when I came across a problem with my code:
$(document).ready(function()
{
/* Declaring some variables to help with scrolling through my Portfolio */
var workArray = [];
var scrollPos = 1;
/* This makes the left scroll arrow disappear if it's
at the start (scrollPos is less then or equal to 1) */
if (scrollPos <= 1) {
$('#left_scroll').hide();
} else {
$('#left_scroll').show();
}
/*This SHOULD decrement and increment values to the scrollPos variable
when the corresponding arrows are clicked*/
$('#left_scroll').click(function(){
scrollPos--;
});
$('#right_scroll').click(function(){
scrollPos++;
});
(left_scroll) is assigned to an arrow key on my page that is suppose to subtract from the value (scrollPos) that tells when the left or right arrow image should be visible.
Currently I have the value scrollPos set to 1, so the left arrow key is invisible and the right one is visible, but for some reason, when either one is clicked it doesn't appear as though any values are changed as the left arrow key remains invisible.
Can anyone see any problems with my code, hope you can help. :D
Martin
The click handlers are just doing what you told them to do, and that is increment and decrement. You didn't tell the handlers to do anything else, like some hide and show.
Place the logic inside for hide and show inside the handler functions in order to hide and show on clicking your buttons.
Working jsFiddle Demo
You must call your if statement after your increment/decrement.
Make a function for this:
function checkScrollPos() {
/* This makes the left scroll arrow disappear if it's
at the start (scrollPos is less then or equal to 1) */
if (scrollPos <= 1) {
$('#left_scroll').hide();
} else {
$('#left_scroll').show();
}
}
And after your click, call it:
$('#left_scroll').click(function(){
scrollPos--;
checkScrollPos();
});
$('#right_scroll').click(function(){
scrollPos++;
checkScrollPos();
});
Your code:
if (scrollPos <= 1) {
$('#left_scroll').hide();
} else {
$('#left_scroll').show();
}
Only executes one time. If you want to check scrollPos value every time your arrows get clicked, use a function:
function hideOrShow(scrollPos) {
if (scrollPos <= 1) {
$('#left_scroll').hide();
} else {
$('#left_scroll').show();
}
}
$('#left_scroll').click(function(){
scrollPos--;
hideOrShow(scrollPos)
});
$('#right_scroll').click(function(){
scrollPos++;
hideOrShow(scrollPos)
});

onmouseout and onmouseover

I am working on homework that involves working with javascript. Part of my homework assignment is to use the event handlers onmouseout and onmouseouver. What is supposed to happen when the user hovers over a specific div element, the font size grows by 25%, and when the user mouses out of the div element, the font size goes back to normal. My question is, is it possible to incorporate both an onmouseover function and an onmouseout function into one function? Somehow that is what my teacher wants us to do. I have this started so far.
function FontSize(x)
{
x.style.fonstSize = large;
}
I'm also thinking this isnt the correct code to make the font 25% larger, but I'm not sure how to really incorporate an onmouseout in this function.
As a teacher myself, I am 99% sure that by "one function" the instructor means one general-purpose function to change the font size, not one function which uses conditional statements to work backwards and figure out whether it should be doing onmouseout or onmouseover.
Your script should contain:
function resize(elem, percent) { elem.style.fontSize = percent; }
Your HTML should contain:
<div onmouseover="resize(this, '125%')" onmouseout="resize(this, '100%')"
Text within div..
</div>
Note: Situations such as here, are exactly why JavaScript has the keyword "this"--to save us from needing to use complicated document.getElementById() statements.
You can use "%" property for controlling font-size as described here with the following code.
document.getElementById("div1").onmouseover = function() {
document.getElementById("div1").style.fontSize = "125%"
};
document.getElementById("div1").onmouseout = function() {
document.getElementById("div1").style.fontSize = "100%";
};
Here is the working jsfiddle : http://jsfiddle.net/LxhdU/
Yes you can. Call the same function on both events, and pass a parameter to indicate whether the fontsize should increase or decrease.
ChangeFontSize = function(element, shouldIncreaseFontsize)
{
var small=14;
var large = small * 1.25;
if(shouldIncreaseFontsize) {
element.style.fontSize = large + "px";
}
else {
element.style.fontSize = small + "px";
}
}
http://jsfiddle.net/TMHbW/1/
I'd do something simple like the following. The large and small values can be whatever you need them to be for the font size to work or they can be variables you've defined in prior code.
Demo: http://jsfiddle.net/lucuma/EAbYn/
function doHover(e) {
if (e.type=='mouseover') {
this.style.fontSize = "large";
} else {
this.style.fontSize = "small";
}
}
var el = document.getElementById('myelement')
el.onmouseout =doHover;
el.onmouseover=doHover;
It is possible you do not need to call both the events on the element explicitly instead extension you create will do that.Extend the Element's prototype. Jquery also does similar to this.
Ref Prototype
See Fiddle:- http://jsfiddle.net/4fs7V/
Element.prototype.hover= function( fnOver, fnOut ) {
this.onmouseover=fnOver;
this.onmouseout=fnOut || fnOver;
return this;
};
document.getElementById('test').hover(function(){
//do your mouseover stuff
},
function(){
//do your mouseout stuff
});
Update
Same can be achieved with just one function too:-
Hover me
.largeFont {
font-size:125%;
}
Element.prototype.hover = function (fnOver, fnOut) {
this.onmouseover = fnOver;
this.onmouseout = fnOut || fnOver;
return this;
};
document.getElementById('test').hover(changeMe);
function changeMe()
{
if(this.hasAttribute('class'))
{
this.removeAttribute('class');
}
else
{
this.setAttribute('class', 'largeFont');
}
}

JavaScript/jQuery onmouseover problem

I want that when mouse is over an image, an event should be triggered ONCE, and it should be triggered again only after mouse is out of that image and back again, and also at least 2 seconds passed.
My current function is called continuously (refreshcash) if I leave the mouse over my image
<img src="images/reficon.png" onmouseover="refreshcash()" onmouseout="normalimg()" id="cashrefresh"/>
function refreshcash() {
$("#showname").load('./includes/do_name.inc.php');
$("#cashrefresh").attr("src","images/reficonani.gif");
}
function normalimg() {
$("#cashrefresh").attr("src","images/reficon.png");
}
code update
This code seems to have a bug,but the algorithm is kinda logical
<script type="text/javascript">
var canhover = 1;
var timeok = 1;
function redotimeok() {
timeok = 1;
}
//
function onmenter()
{
if (canhover == 1 && timeok == 1)
{
enter();
canhover = 0;
}
}
//
function onmleave()
{
leave();
canhover = 1;
setTimeout(redotimeok(), 2000);
leave();
}
//
$('#cashrefresh').hover(onmenter(),onmleave());
function enter(){
$("#showname").load('./includes/do_name.inc.php');
$("#cashrefresh").attr("src","images/reficonani.gif");
}
function leave(){
$("#cashrefresh").attr("src","images/reficon.png");
}
</script>
Try the hover:
$('#cashrefresh').hover(function(){
$("#showname").load('./includes/do_name.inc.php');
$("#cashrefresh").attr("src","images/reficonani.gif");
}, function(){
$("#cashrefresh").attr("src","images/reficon.png");
});
And your image should look like:
<img src="images/reficon.png" id="cashrefresh"/>
Update:
Modify your code like this:
var e = null;
var l = null;
$('#cashrefresh').hover(function(){
e = setTimeout(enter, 2000)
}, function(){
l = setTimeout(leave, 2000)
});
function enter(){
$("#showname").load('./includes/do_name.inc.php');
$("#cashrefresh").attr("src","images/reficonani.gif");
clearTimeout(e);
}
function leave(){
$("#cashrefresh").attr("src","images/reficon.png");
clearTimeout(l);
}
Do you have the images cached in some way? If you replace them by their src attribute without specifying width/height elsewhere (best would be CSS) or having them readily available then the hovered box (img element) will collapse into a smaller (or no) box until the image has been loaded far enough for the browser to know the correct dimensions of the image to resize the box (which may affect other elements being adjusted to the image). The exact effect depends on the browser but you may lose the hover state causing the call of your mouseout function.
I assume that both images are the same size, so if you didn't already, you could try adding the dimensions to your CSS for #cashrefresh and see if that fixes the problem.
For the delay I would recommend using the jQuery timers plugin (or a similar one) which eases handling of timers compared to doing it on your own. You would probably want to give your timers names and try to stop older ones before you add the next one.

Categories