ok so i have this javascript to use the arrow keys to send these javascripts when i press arrowkeys. i have a collaborating script that makes the right('img') command move the image but im trying to change the image as it moves with src changes and delays. Help?
<script type="text/javascript">
document.onkeydown = KeyCheck;
function KeyCheck(event) {
var spacebar=32
var KeyID = event.keyCode;
switch(KeyID) {
case 39:
right('img');
document.getElementById('img').src = 'guyr.png';
setTimeout("right('img');
document.getElementById('img').src = 'runr.png';
setTimeout("right('img');
document.getElementById('img').src = 'guyr.png';",100);",100);
break;
}
}
</script>
Changing the src attribute of an image is going to trigger an asynchronous GET request, and may be slow at first before the browser has cached the images. It looks like you are implementing a game of some sort? Instead of changing the src of a single image, I would keep all of the images hidden initially, and toggle the visibility CSS attribute of images you want to show/hide. That way, you can pre-fetch all of the images that you'll need during load time, and simply show/hide elements as the handlers for your onkeydown events.
If you want to do some sort of a game or animation, try to read a little about it, how to structure your game loop, animations and etc.
But if you are doing just some sort of test try something like this, is not a beautiful code but the idea of an animation should work:
document.onkeydown = KeyCheck;
function KeyCheck(event) {
var spacebar = 32;
var KeyID = event.keyCode;
switch (KeyID) {
case 39:
function guy(fn) {
right('img');
document.getElementById('img').src = 'guyr.png';
setTimeout(function() {
fn(guy);
}, 100);
}
function run(fn) {
right('img');
document.getElementById('img').src = 'runr.png';
setTimeout(function() {
fn(run);
}, 100);
}
guy(run);
break;
}
}
One function calls another, receiving it by parameter, in order to to continue the animation.
Related
So I have so an image will show when certain text is moused over, it will delay when the mouse is taken off before disappearing and that works just fine. But I have multiple images that can show up depending on the text hovered, I want to have the first image skip it's delay if other text is moused over so it doesn't expand the page and stack the images. Is this possible? Or will I just need to pull the delay off? This is done within JQuery
$("h2").mouseover(function ()
{
let mouseText = $(this).attr("class").split(" ")[0];
switch(mouseText)
{
case "wh-light":
imgID += mouseText;
break;
case "wh-hl-ll":
imgID += mouseText;
break;
case "part-hh-ll":
imgID += mouseText;
break;
}
$(imgID).show();
});
$("h2").mouseout(function ()
{
$(imgID).delay(1000).hide(0);
});
I can supply the HTML but I don't think it is too relevant to this. Thank you in advance for your help!
Without having your template and complete code, I'd have to contrive a full example... but the below snippet should give you a good example of what you'll have to do. You'll need to keep track of the current image and your callback has to know what the current image was when the delay was kicked off and compare it to the current to know whether it should do anything or not.
For this reason I pulled the code into separate javascript functions and used setTimeout instead of the jquery delay(). The documentation on the actual jquery site even mentions that the delay function is limited and has no way to cancel itself and as such should not be treated as a replacement for setTimeout().
Ref https://api.jquery.com/delay/
The .delay() method is best for delaying between queued jQuery effects. Because it is limited—it doesn't, for example, offer a way to cancel the delay—.delay() is not a replacement for JavaScript's native setTimeout function, which may be more appropriate for certain use cases.
Without knowing how you were building the imgID variable or clearing it out... I added the baseImageID and targetImageID variables so that you don't end up just continuously concatenating the new strings onto the end of imgID...
As a last note... I like to make things very modular and verbose when talking through a solution so please dont hate on the extra functions... I think they make the solution easier to understand. The actual implementation can be streamlined...
let baseImageID = 'image-';
let targetImageID = '';
let currentImageID = '';
const hideImageNow = function(imageID) {
$(imageID).hide();
if (currentImageID == imageID) {
currentImageID = '';
}
};
const hideImageLater = function(imageID, delay) {
setTimeout(hideImageNow, delay, imageID);
};
const showImage = function(imageID) {
if (currentImageID != '') {
hideImageNow(currentImageID);
}
currentImageID = imageID;
$(imageID).show();
};
$("h2").mouseover(function() {
targetImageID = baseImageID;
let mouseText = $(this).attr("class").split(" ")[0];
switch (mouseText) {
case "wh-light":
targetImageID += mouseText;
break;
case "wh-hl-ll":
targetImageID += mouseText;
break;
case "part-hh-ll":
targetImageID += mouseText;
break;
}
showImage(targetImageID);
});
$("h2").mouseout(function() {
hideImageLater(currentImageID, 1000);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I have a site that has an image gallery that changes images every few seconds using JavaScript; however, I want to know how to STOP the images from changing when a user clicks on one of the images.
So far, the images are rotating as planned, but I can't seem to get the "onClick" scripting to STOP the rotation when the user clicks on an image. I don't need to have an alert popup or need it to do anything, I just need it to STOP the image rotation when someone clicks on one of the pictures.
Here's the HTML code I have:
else (getValue=='STOP')
{
alert("STOPPED");
}
That won't do what you probably want it to do. It should be:
else if (getValue=='STOP')
{
alert("STOPPED");
}
First of all, you missed out on the keyword "IF" in one of the lines of your code.
However, the way to create a terminable repetitive action is to setInterval and then use clearInterval to terminate the repetition.
semaphore = setInterval(somefunction, someinterval);
clearInterval(semaphore);
Example (I wrote this off-the-cuff, so there might be some errors, but you shd get the idea):
<img src="./images/image1.jpg" id="imageGallery" name="imageGallery"
onclick="chooseImg(this)" />
<script>
var turn = setInterval(function(){imgTurn()},5000);
var images = function2CreateImgArray();
var imageN = 0;
function chooseImg(img){
clearInterval(turn);
function2DisplayImg(imageN); // or do whatever
}
function imgTurn(){
if (imageN++ >= images.length) imageN = 0;
function2DisplayImg(imageN++);
}
</script>
You could replace the setInterval with setTimeout.
var turn = setTimeout(function(){imgTurn()},5000);
But then you need to use clearTimeout to stop it:
clearTimeout(turn);
But if you use setTimeout, you would need to setTimeout for the next image display, so you would not even need to clearTimeout to stop the rotation.
<img src="./images/image1.jpg" id="imageGallery" name="imageGallery"
onclick="chooseImg(this)" />
<script>
setTimeout(function(){imgTurn()},5000);
var images = function2CreateImgArray();
var imageN = 0;
var turn = 1;
function chooseImg(img){
turn = 0;
function2DisplayImg(imageN); // or do whatever
}
function imgTurn(){
if (turn==0) return;
if (imageN++ >= images.length) imageN = 0;
function2DisplayImg(imageN++);
}
</script>
I have been building my own carasol over the past few days.
My Jquery is based on tutorials on the web and also from help and advice from SO.
I am not a Jquery guru just an enthusiast and think my code is a little sloppy, hence the post.
here is a link to the working code: http://jsfiddle.net/JHqBA/2/ (updated link)
basically what happens is:
if someone hits the page with a # values in the url it will show the appropriate slide and example would be www.hello.com#two, this would slide to slide two
if someone clicks the numbers it will show the appropriate slide
next and prev also slide through the slides.
The question is, is there anything i could have wrote better as i know there is alot of duplicate code.
I understand its a big ask but it would help me learn a little more (i think my code is a little old school)
if anyone has any questions please feel free to ask and ill answer what it does or is supposed to do.
Sluap
--- Edit ----
I have made only one aniamtion function now which has got rid of alot of duplicate code.
I have yet to look into on function but will do soon.
I would like to know more about the create a new function, outside of the jQuery ready block as i cant get this working or quite understand how i can get it to work sorry
any more tips would be great ill carry on working on this project till i am happy with it.
also is there a better way to write:
if ($slideNumber == 1) {
$('#prev').attr("class", "not_active")
$('#next').attr("class", "active")
}
else if ($slideNumber == divSum) {
$('#next').attr("class", "not_active");
$('#prev').attr("class", "active");
}
else {
$('#prev').attr("class", "active")
$('#next').attr("class", "active")
};
Jquery full:
$(document).ready(function () {
//////////////////////////// INITAL SET UP /////////////////////////////////////////////
//Get size of images, how many there are, then determin the size of the image reel.
var divWidth = $(".window").width();
var divSum = $(".slide").size();
var divReelWidth = divWidth * divSum;
//Adjust the image reel to its new size
$(".image_reel").css({ 'width': divReelWidth });
//set the initial not active state
$('#prev').attr("class", "not_active");
//////////////////////////// SLIDER /////////////////////////////////////////////
//Paging + Slider Function
rotate = function () {
var triggerID = $slideNumber - 1; //Get number of times to slide
var image_reelPosition = triggerID * divWidth; //Determines the distance the image reel needs to slide
//sets the active on the next and prev
if ($slideNumber == 1) {
$('#prev').attr("class", "not_active")
$('#next').attr("class", "active")
}
else if ($slideNumber == divSum) {
$('#next').attr("class", "not_active");
$('#prev').attr("class", "active");
}
else {
$('#prev').attr("class", "active")
$('#next').attr("class", "active")
};
//Slider Animation
$(".image_reel").animate({
left: -image_reelPosition
}, 500);
};
//////////////////////////// SLIDER CALLS /////////////////////////////////////////////
//click on numbers
$(".paging a").click(function () {
$active = $(this); //Activate the clicked paging
$slideNumber = $active.attr("rel");
rotate(); //Trigger rotation immediately
return false; //Prevent browser jump to link anchor
});
//click on next button
$('#next').click(function () {
if (!$(".image_reel").is(':animated')) { //prevent clicking if animating
var left_indent = parseInt($('.image_reel').css('left')) - divWidth;
var slideNumberOn = (left_indent / divWidth);
var slideNumber = ((slideNumberOn * -1) + 1);
$slideNumber = slideNumber;
if ($slideNumber <= divSum) { //do not animate if on last slide
rotate(); //Trigger rotation immediately
};
return false; //Prevent browser jump to link anchor
}
});
//click on prev button
$('#prev').click(function () {
if (!$(".image_reel").is(':animated')) { //prevent clicking if animating
var left_indent = parseInt($('.image_reel').css('left')) - divWidth;
var slideNumberOn = (left_indent / divWidth);
var slideNumber = ((slideNumberOn * -1) - 1);
$slideNumber = slideNumber;
if ($slideNumber >= 1) { //do not animate if on first slide
rotate(); //Trigger rotation immediately
};
}
return false; //Prevent browser jump to link anchor
});
//URL eg:www.hello.com#one
var hash = window.location.hash;
var map = {
one: 1,
two: 2,
three: 3,
four: 4
};
var hashValue = map[hash.substring(1)];
//animate if hashValue is not null
if (hashValue != null) {
$slideNumber = hashValue;
rotate(); //Trigger rotation immediately
return false; //Prevent browser jump to link anchor
};
});
Question and answer has been moved over to https://codereview.stackexchange.com/questions/8634/jquery-carasol-build-finished-and-would-like-advice-on-best-practice-neateni/8635#8635
1) Separation of Concerns
Start by refactorring your code in to more granular functions.
You can read more about SoF at http://en.wikipedia.org/wiki/Separation_of_concerns
Update:
E.g. Instead of having your reel resizing code inline, put it in it's own function, like this:
function setImageReelWidth () {
//Get size of images, how many there are, then determin the size of the image reel.
var divWidth = $(".window").width();
var divSum = $(".slide").size();
var divReelWidth = divWidth * divSum;
//Adjust the image reel to its new size
$(".image_reel").css({ 'width': divReelWidth });
}
This achieves 2 things:
a. First, it groups a block of code that is logically cohesive, removing it from the main code which results in a much cleaner code habitat.
b. It effectively gives a label to the code block via the function name that is descriptive of what it does, and therefore makes understanding of the code much simpler.
Later, you can also encapsulate the whole thing in it's own "class" (function) and you can move it into it's own js file.
2) The jQuery "on" function
Use the "on" function to attach your click events, rather than the "click" function.
http://api.jquery.com/on/
This has the added advantage of also binding it to future elements matching your selector, even though they do not exist yet.
3) The ready function
// I like the more succinct:
$(handler)
// Instead of:
$(document).ready(handler)
But you might like the more obvious syntax.
Those are just a few things to start with.
-- Update 1 --
Ok, StackOverflow is not really suited to a refactoring work in progress, but we'll make do. I think you should keep your original code block in your question, so that future readers can see where it started and how it systematically improved.
I would like to know more about the create a new function, outside of
the jQuery ready block as i cant get this working or quite understand
how i can get it to work sorry
I am not familiar with jsfiddle.net, but it looks cool and helpful, but might also be a bit confusing if you don't know what is going on. I am not sure I do :), but I think that script editor window results in a .js file that is automatically referenced by the html file.
So here is an example of a function defined outside of the ready block, but referenced from within.
function testFunction () {
alert ('it works');
}
$(document).ready(function () {
testFunction();
// ... other code
});
This should pop up an alert box that says, "it works" when the page is loaded.
You can try it for yourself.
Then, once you got that working, you can refactor other logically cohesive blocks of code into their own functions. Later you can wrap them all up into their own javascript 'class'. But we'll get to that.
I want to be able to do a cross fade transition on large images whose width is set to 100% of the screen. I have a working example of what I want to accomplish. However, when I test it out on various browsers and various computers I don't get a buttery-smooth transition everywhere.
See demo on jsFiddle: http://jsfiddle.net/vrD2C/
See on Amazon S3: http://imagefader.s3.amazonaws.com/index.htm
I want to know how to improve the performance. Here's the function that actually does the image swap:
function swapImage(oldImg, newImg) {
newImg.css({
"display": "block",
"z-index": 2,
"opacity": 0
})
.removeClass("shadow")
.animate({ "opacity": 1 }, 500, function () {
if (oldImg) {
oldImg.hide();
}
newImg.addClass("shadow").css("z-index", 1);
});
}
Is using jQuery animate() to change the opacity a bad way to go?
You might want to look into CSS3 Transitions, as the browser might be able to optimize that better than Javascript directly setting the attributes in a loop. This seems to be a pretty good start for it:
http://robertnyman.com/2010/04/27/using-css3-transitions-to-create-rich-effects/
I'm not sure if this will help optimize your performance as I am currently using IE9 on an amped up machine and even if I put the browser into IE7 or 8 document mode, the JavaScript doesn't falter with your current code. However, you might consider making the following optimizations to the code.
Unclutter the contents of the main photo stage by placing all your photos in a hidden container you could give an id of "queue" or something similar, making the DOM do the work of storing and ordering the images you are not currently displaying for you. This will also leave the browser only working with two visible images at any given time, giving it less to consider as far as stacking context, positioning, and so on.
Rewrite the code to use an event trigger and bind the fade-in handling to the event, calling the first image in the queue's event once the current transition is complete. I find this method is more well-behaved for cycling animation than some timeout-managed scripts. An example of how to do this follows:
// Bind a custom event to each image called "transition"
$("#queue img").bind("transition", function() {
$(this)
// Hide the image
.hide()
// Move it to the visible stage
.appendTo("#photos")
// Delay the upcoming animation by the desired value
.delay(2500)
// Slowly fade the image in
.fadeIn("slow", function() {
// Animation callback
$(this)
// Add a shadow class to this image
.addClass("shadow")
// Select the replaced image
.siblings("img")
// Remove its shadow class
.removeClass("shadow")
// Move it to the back of the image queue container
.appendTo("#queue");
// Trigger the transition event on the next image in the queue
$("#queue img:first").trigger("transition");
});
}).first().addClass("shadow").trigger("transition"); // Fire the initial event
Try this working demo in your problem browsers and let me know if the performance is still poor.
I had the same problem too. I just preloaded my images and the transitions became smooth again.
The point is that IE is not W3C compliant, but +1 with ctcherry as using css is the most efficient way for smooth transitions.
Then there are the javascript coded solutions, either using js straight (but need some efforts are needed to comply with W3C Vs browsers), or using libs like JQuery or Mootools.
Here is a good javascript coded example (See demo online) compliant to your needs :
var Fondu = function(classe_img){
this.classe_img = classe_img;
this.courant = 0;
this.coeff = 100;
this.collection = this.getImages();
this.collection[0].style.zIndex = 100;
this.total = this.collection.length - 1;
this.encours = false;
}
Fondu.prototype.getImages = function(){
var tmp = [];
if(document.getElementsByClassName){
tmp = document.getElementsByClassName(this.classe_img);
}
else{
var i=0;
while(document.getElementsByTagName('*')[i]){
if(document.getElementsByTagName('*')[i].className.indexOf(this.classe_img) > -1){
tmp.push(document.getElementsByTagName('*')[i]);
}
i++;
}
}
var j=tmp.length;
while(j--){
if(tmp[j].filters){
tmp[j].style.width = tmp[j].style.width || tmp[j].offsetWidth+'px';
tmp[j].style.filter = 'alpha(opacity=100)';
tmp[j].opaque = tmp[j].filters[0];
this.coeff = 1;
}
else{
tmp[j].opaque = tmp[j].style;
}
}
return tmp;
}
Fondu.prototype.change = function(sens){
if(this.encours){
return false;
}
var prevObj = this.collection[this.courant];
this.encours = true;
if(sens){
this.courant++;
if(this.courant>this.total){
this.courant = 0;
}
}
else{
this.courant--;
if(this.courant<0){
this.courant = this.total;
}
}
var nextObj = this.collection[this.courant];
nextObj.style.zIndex = 50;
var tmpOp = 100;
var that = this;
var timer = setInterval(function(){
if(tmpOp<0){
clearInterval(timer);
timer = null;
prevObj.opaque.opacity = 0;
nextObj.style.zIndex = 100;
prevObj.style.zIndex = 0;
prevObj.opaque.opacity = 100 / that.coeff;
that.encours = false;
}
else{
prevObj.opaque.opacity = tmpOp / that.coeff;
tmpOp -= 5;
}
}, 25);
}
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.