I've built a webpage that's supposed to increase the size of images onmouseover.
I'm not replacing the images with bigger ones but rather "stretch" the existing ones because of system limitations.
Here's the webpage:
http://www.catmoviez.com/IMDBQueries.aspx
You can see that the movie images get bigger when you're on them.
Problem is when I move my mouse too quick that sometimes an image gets stuck open or it causes inifinite flickering.
attached is also the code I'm using for the resize:
function resizeImage(elem,width,height){
var myEffect = new Fx.Morph(elem, {duration: 350});
myEffect.start({'height': height,'width': width});
}
First thing, set this variable outside your functions
var imagegrow
And then mouseover this
function () {
imagegrow = setTimeout(function(){ resizeImage(elem,width,height); },1000);
}
And the mouseout this:
function () {
clearTimeout(imagegrow);
}
Adjust the 1000 number to suit your preferred delay (it's in milliseconds). I'd write the whole code for you, but I haven't used MooTools for a while.
Comment if you have any questions
Faruz, Gaussie is right you need to use a timeout. However, consider using mootools' addEvent function as described in the mootools docs as well as the $$ function which will allow you to achieve something much more elegant, along the lines of:
window.addEvent('domready', function() {
$$("tr td input").addEvent("mouseover", function() {
//anonymous function like Gaussie's here
});
});
Note that this isn't the exact code, it will take some modification but it is cleaner and should be more efficient then setting the onmouseover property of every image. Also, remember this goes in the head of your HTML document.
Related
I'm trying to create a generic function that can be placed just once in my site and work across multiple pages, nice and lightweight.
I want to be able to make certain divs on the site fade-in when you reach 10px above them on the scroll.
I want to do this by simply adding the following attributes to my divs:
.fade-in-block
#specific-block-name
The idea is that I could go through the site, add this class and an ID, and the animation would work.
I almost have it working except for one thing, the scroll listening constantly continues to console.log after the function has been called. I don't like this as it feels like it's going to be constantly trying to apply the animation, which won't really be seen from the front-end but I feel the constant maths behind the scenes could slow stuff down.
Here is my jQuery:
$('body .fade-in-block').each(function(){
var block = '#'+$(this).attr('id');
console.log('Block class is = '+block);
var offset = $(block).offset().top;
var $w = $(window).scroll(function () {
if ($w.scrollTop() > offset - 10) {
console.log('reached block turn-on point for '+block);
$(block).removeAttr('id'); // remove the ID from the element so the script doesn't continue to find the element
// fade and rise animation here
}
});
});
And here is a JSFiddle. It works just fine, but once you hit the block you'll see it logs constantly every pixel scrolled.
I tried to remedy this by removing the selecting id from the element once the event has occurred, but it continues to run.
Scroll and resize events both have this problem and the solution is said to be debouncing. However, I've never actually gotten debouncing to work properly. Instead I typically create a sort of switch that is turned off once the scroll condition has activated. In your case, since you have multiple elements, you would need to assign a switch to each element.
$(window).on('scroll', function(){
$('.fade-in-block').each(function(){
var appear = $(this).attr('data-appeared');
if(!appear){
$(this).attr('data-appeared', true);
//do something to $(this)
}
})
})
Here I'm adding a data attribute after it has appeared and checking for it again once it has.
I have this animation setup to indicate which SVG was selected. The animation adds a svg:use element, and 3 animate or animateTransform elements within the svg:use element. Thanks to some great help here on SO I was able to get this working properly.
My new problem however is that the animation only works once as designed once. If a second element is selected, the animation appears to try to take place, as you can see the stroke-width increase, but the scale doesn't happen.
I thought this would be a simple fix by using a setTimeout to call a function and remove the svg:use after the animation completed. I wasn't so lucky.
An example of my problem can be seen here: http://codepen.io/JoeyCinAZ/pen/GHhbw
The function I wrote to remove the animation is here
setTimeout( function() {removeAnimation(objID)}, 5000);
function removeAnimation(objID) {
var useEl = document.getElementById(objID);
useEl.nextSibling.remove();
}
You've two issues within the animation. The simplest is duration, it can't per the SVG specification begin with a . so
flash.setAttributeNS(null, 'dur', '.5s');
is strictly speaking not valid and Firefox rejects it. I believe there are plans to change the SVG specification to match Chrome's laxer behaviour but until that happens write it as
flash.setAttributeNS(null, 'dur', '0.5s');
Secondly your main issue is that once you run the animation the document timeline goes from 0 to 5.5 seconds (that's how long all your animations take). The next time you create the animation, the document timeline is therefore at 5.5 seconds and the initial animation doesn't run because it's in the past as it's supposed to start at 0s. You could solve this either by
a) calling setCurrentTime to reset the timeline to 0, or
b) having the initial animation trigger from the button press event.
I had a similar issue before and solved it by completely removing the content of the element that contains the generated SVG, and then simply reload the new SVG in the empty element.
Instead of using a setTimeout which make the whole thing a bit weird, I would simply call it on clicking the element selector:
var elem = document.getElementById('myElementSelector');
elem.addEventListener('click', function() {
document.getElementById(surroundingElementID).innerHTML = "";
//Check what has been clicked and call function that creates the SVG on the surroundingElementID
}, false);
This is probably basic to most reading, but I can't seem to figure it out.
I have a little test function that I want to execute if under a certain width. When the screen rotates or gets resized above that width, I want the function to cease to work. Here is some example code for simplicity sake.
enquire.register("screen and (max-width:500px)",{
match : function() {
$(".block .block-title").click(function(){
alert("Hello World!");
});
}
}).listen();
So if the page loads above 500px, it works as intended. Clicking won't execute. If the page loads at 500px or below, the click function executes. Only problem is that if you resize the viewport or change orientation to something above 500px, the function still executes. I'd like to be able to disable that.
The real world scenario I'm actually trying to do here is I have an un-ordered list of 4 items. Above a certain width they are displayed right away. If under a certain width, I just want to hide them and on click show them. I know there are a few ways to do it (.toggle(), .toggleClass("myclass"), etc).
I have done this a bunch of times but I always get caught with the entering / exiting break points and things not being reset, or working as intended. Usually it doesn't matter, but lately in some of my use cases it has mattered.
I know of the unmatch option but I'm not sure how to really kill the matched function above.
enquire.register("screen and (max-width:500px)",{
match : function() {
$(".block .block-title").click(function(){
alert("Hello World!");
});
},
{
unmatch : function() {
// what do I do here do kill above?
}
}
}).listen();
Any help would be appreciated. I am pretty sure it will help my current situation but will also help me expand my knowledge of enquire.js for other things.
Thanks.
edit: I forgot to mention... if you load the page under 500px, then resize or orientate wider then 500px, then go BACK under 500px, the click function won't work again.. which confuses me also. I basically was hoping it would work no matter what when under 500px, and not work at all when over 500px.
I'm the author of enquire.js, so hopefully I'll be able to help you ;-)
Basically, you want to add an event handler on match and remove event handler on unmatch. You seem to have the gist of how to do this above, but you've got the syntax a little wrong. Once the syntax is corrected it's just some jQuery knowledge to remove the click handler.
So let's look at how the syntax should be:
enquire.register("screen and (max-width:500px)", {
match: function() {
//match code here
},
unmatch: function() {
//unmatch code here
}
}).listen();
Notice that match and unmatch are part of a single object supplied to register.
Ideally you should be putting this in your document ready callback. To assign your click handler use jQuery's on method, as this allows you to use the off method to unassign:
$(".block .block-title").on("click", function() {
alert("hello");
});
$(".block .block-title").off("click");
This is great because you can even namespace your events, read up on the jQuery docs for more details on this. So to put it all together, we would have this:
$(document).ready(function() {
var $target = $(".block .block-title");
enquire.register("screen and (max-width:500px)", {
match: function() {
$target.on("click", function() {
alert("Hello World!");
});
},
unmatch: function() {
$target.off("click");
}
}).listen();
});
You can find a working example here: http://jsfiddle.net/WickyNilliams/EHKQj/
That should then be all you need :) Hope that helps!
We're trying to make sure our JavaScript menu, which loads content, doesn't get overrun with commands before the content in question loads and is unfurled via .show('blind', 500), because then the animations run many times over, and it doesn't look so great. So I've got about six selectors that look like this:
("#center_content:not(:animated)")
And it doesn't seem to be having any effect. Trying only :animated has the expected effect (it never works, because it doesn't start animated), and trying :not(div) also has this effect (because #center_content is a div). For some reason, :not(:animated) seems not to be changing the results, because even when I trigger the selector while the div in question is visibly animated, the code runs. I know I've had success with this sort of thing before, but the difference here eludes me.
$("#center_content:not(:animated)").hide("blind", 500, function () {
var selector_str = 'button[value="' + url + '"]';
//alert(selector_str);
var button = $(selector_str);
//inspectProperties(button);
$("#center_content:not(:animated)").load(url, CenterContentCallback);
if (button) {
$("#navigation .active").removeClass("active");
button.addClass("active");
LoadSubNav(button);
}
});
I hope this provides sufficient context. I feel like the second selector is overkill (since it would only be run if the first selector succeeded), but I don't see how that would cause it to behave in this way.
Here's the snippet that seemed to be working in the other context:
function clearMenus(callback) {
$('[id$="_wrapper"]:visible:not(:animated)').hide("blind", 500, function() {
$('[id^="edit_"]:visible:not(:animated)').hide("slide", 200, function() {
callback();
});
});
}
Here, the animations queue instead of interrupt each other, but it occurs to me that the selector still doesn't seem to be working - the animations and associated loading events shouldn't be running at all, because the selectors should fail. While the queueing is nice behavior for animations to display, it made me realize that I seem to have never gotten this selector to work. Am I missing something?
Sometimes it's helpful to use .stop() and stop the current animation before you start the new animation.
$("#center_content").stop().hide("blind", 500, function () {});
Really depends on how it behaves within your environment. Remember that .stop() will stop the animation as it was (eg. halfway through hiding or fading)
I don't know if I understand it correctly, but if you want to make sure the user doesn't trigger the menu animation again while it's currently animating(causing it to queue animations and look retarded, this works and should help. I use an if-statement. And before any mouseover/off animation I add .stop(false, true).
$('whatever').click(function(){
//if center_content is not currently animated, do this:
if ($("#center_content").not(":animated")) {
$(this).hide(etc. etc. etc.)
}
//else if center_content IS currently animated, do nothing.
else {
return false;}
});
another example i found elsewhere:
if($("#someElement").is(":animated")) {
...
}
if($("#someElement:animated").length) {
...
}
// etc
then you can do:
$("#showBtn").attr("disabled", $("#someElement").is(":animated"));
I'm required to develop a slideshow (not an existing one) with jQuery. I was able to change picture with a function that I created named changePic (takes an image link). It incorporates the fading animation from the jQuery library.
For the slideshow I'm trying to use a while loop. It kind of works, except that it doesn't wait for the animation to finish.
How do I, a) wait for the animation to finish, b) delay the changing picture so it display the picture for a couple of seconds?
Also tried Settimeout, and it doesn't work.
Edit:
Basically changing image is like this:
function changePic(imglink){
var imgnode = document.getElementById("galleryimg");
$(imgnode).fadeTo(500, 0, function(){
$(imgnode).attr("src", imglink);
$(imgnode).fadeTo(1000, 1);
})
}
and the slideshow code is like this, but obviously it shouldn't.
function slideshow(gallerylinks){
var i=0;
while (i<gallerylinks.length){
changePic(gallerylinks[i]);
i++;
}
}
You could always try ditching the while loop, and going with a perpetually recursive function...
on the .animate, you could add a timeout function (at whatever interval) that calls the changePic function. As I have no idea what your code looks like, I will provide a fantastically generic outline.
/* array of imgUrls */
var imgUrls = new Array(); //populate it however
changePic(slideToShowIndex, fadeOutSpeed, fadeInSpeed, slideDelay)
{
$('#slideHolder').animate({ opacity: 0}, fadeOutSpeed , function(){
$('#slideHolder').attr('src', imgUrls[slideToShowIndex]);
$('#slideHolder').animate({ opacity: 1 }, fadeInSpeed, function() {
setTimeout(function() { changePic(slideToShowIndex+1, fadeOutSpeed, fadeInSpeed, slideDelay);}, slideDelay});
});
}});
}
$(document).ready(function() {
changePic(0, 5000, 5000, 10000);
});
This should (in theory) fade the image out, swap it with the new one, and fade it in (both taking 5 seconds) and then adding a delay to call itself with the next slide index in 10 seconds.
This is in no way perfect, but does outline the general idea. Since we have no idea what your code looks like, I can only assume your setTimeout was in the wrong spot. Doing it like this will make sure that the animation has finished before the timeout is set. This guarantees that the slide wont change until after the animation has changed.
of course you could always use a combination of the ':not(:animated)' selector and a setInterval to achieve much the same effect.
EDIT: made a slight change to stack the animations properly. The thoery behind this still works even with the OPs addition of code.
You could have provided more details or example code but have a look at stop() and delay() functions.