I would love to have a gallery website with multiple thumbnails including 3 images that rotate as soon as I mousemove over each one.
I've found this amazing responsive fiddle in another thread from #matthias_h going through multiple thumbnail images while mousemove over the thumbnail box.
His fiddle: http://jsfiddle.net/matthias_h/2f2tth47/
The HTML
<article>
<figure data-image-list="http://dummyimage.com/200x200/000000/cccccc.png&text=img1,http://dummyimage.com/200x200/dedede/cccccc.png&text=img2,http://dummyimage.com/200x200/b31031/cccccc.png&text=img3">
<img class="imageHolder" data-src="http://dummyimage.com/200x200/cdcdcd/dddddd.png&text=+" src="http://dummyimage.com/200x200/cdcdcd/dddddd.png&text=+" />
</figure>
The Javascript
$(".imageHolder").mousemove(function (event) {
var xPos = event.pageX,
imgPos = $(".imageHolder").offset().left,
imgWidth = $(".imageHolder").width();
console.log("xPos: ", xPos, ", imgPos: ", imgPos, ", imgWidth: ", imgWidth);
var change1 = imgPos,
change2 = imgPos + imgWidth / 3,
change3 = imgPos + 2 * imgWidth / 3;
console.log("change1: ", change1, "change2: ", change2, "change3: ", change3);
$images = $("figure").data("imageList");
var array = $images.split(',');
if (xPos > change1) {
$("img").attr("src", array[0]);
}
if (xPos > change2) {
$("img").attr("src", array[1]);
}
if (xPos > change3) {
$("img").attr("src", array[2]);
}});$("img").mouseout(function (){$("img").attr("src", $("img").data("src"));});
Unfortunately there are two issues with this.
When duplicating it, moving over any of them also switches the
images on the other ones.
It takes single images instead of bg positions via css which is less efficient since I'm personally using image sprites for all my work.
I have good experience with html/css but no experience with javascript. Would love to get some insight how I can fix these two issues. Mainly the first one to make a gallery with multiple images work in the first place.
Thanks in advance!
Now that you duplicated the elements, it is targeting a collection instead of just one element.
In general, jQuery method's setter applies to all matching elements, and getter return a value for the first matching element.
Question #1:
Use
$(this) instead of $("img")
$(this) instead of $(".imageHolder")
$(this).parent("figure") instead of $("figure")
Question #2:
You will have to use .css() to change the background position instead of changing the href.
That would be something like $(this).css({background-position: newPosition}) where newPosition has to be defined...
CodePen
Related
So I am very new (as I am sure my code shows :P) and I must create code that contains an image in a div tag. It must be this way. Once the document is opened the image(div) is to be displayed at a random position. Each time the image(div) is clicked, the image alone moves to another random position. It does not replicate itself. Just moves. I have had other "better" attempts but with all my editing and changing all I get is the image in the top left corner.
I tried numerous things that all failed to work. Obviously failed because the code was terrible.
I have tried a variation of onclick events etc...I know many errors are visible. This is not one of those instances where I believe the logic is sound and it should work. This is a "what am I at" instance
<script>
function fpos () {
var img = document.getElementById('myImage') //is this needed at all?
var x = Math.floor(Math.random()*600);
var y = Math.floor(Math.random()*600);
var z = Math.floor(Math.random()*600);
}
function rmove() {
img.style.top = x + 'px';
img.style.left = y + 'px';
}
</script>
</head>
<body onload="fpos">
<div style = position:absolute; onclick="rmove" >
<img id="myImage" src='images/iasip.jpeg'> </img>
</div>
</body>
So, first, don't take this the wrong way my man but you gotta post some code to show us what you're working with. Makes all the difference for troubleshooting.
That said, you're gonna need to do with with JS. First target the image element. Can use querySelector to hit either the class or id or just getElementById.
Then add an event listener to render it at a random coordinate. Like this.
<div id="imageContainer">
<img src="your-image-source" alt="your-image-description">
</div>
<script>
// get the image container element
var imageContainer = document.getElementById("imageContainer");
// set the initial random position for the image container
imageContainer.style.left = Math.floor(Math.random() * window.innerWidth) + "px";
imageContainer.style.top = Math.floor(Math.random() * window.innerHeight) + "px";
// when the image container is clicked, set a new random position
imageContainer.addEventListener("click", function() {
imageContainer.style.left = Math.floor(Math.random() * window.innerWidth) + "px";
imageContainer.style.top = Math.floor(Math.random() * window.innerHeight) + "px";
});
</script>
Can either do that inline like in the example or add it to your script file.
Here is a working example I just threw together.
Basically you need to create a function that moves the image each time by calculating a random number for the height and width and then multiplying by the size of the window so that number can span the full width/length of the screen.
Then you can add 'px' to the end of the calculation to use pixels as the unit and set that to the left and top properties of the image to move it that far from the left and top of the screen using absolute position (coordinates).
window.onload = function() {
move()
}
function move() {
let img = document.getElementById('logo')
img.style.left = Math.floor(Math.random() * window.innerWidth) + "px"
img.style.top = Math.floor(Math.random() * window.innerHeight) + "px"
}
#logo {
height: 100px;
position: absolute;
}
<div>
<img onclick='move()' id='logo' src='https://upload.wikimedia.org/wikipedia/commons/thumb/2/24/LEGO_logo.svg/2048px-LEGO_logo.svg.png' />
</div>
Don't worry, try to isolate some code so we can review it.
Once the document is opened the image(div) is to be displayed at a
random position.
By inspecting an element's properties with Right Click > Inspect > Property you'll find all javascript properties that you have access to once you select the element with a selector (document.querySelector for example)
Try something with that, i think that the easiest way is to use
element.style.transform = "translate(x,y)"
like x.style.transform = "translate(10px, 20px)";
This may seem like an easily answered question but it's one I've been struggling for a little while.
Let me first explain what I'm trying to achieve.
I have a gallery of images and I want each of the images to centered vertically inside their container. The images are of varying shapes, sizes and aspect ratios so my code needs to be variable for each image therein. Here is what I have so far:
<div id="cbp-fwslider" class="cbp-fwslider">
<img src="images/large/1.jpg" alt="img01"/>
<img src="images/large/2.jpg" alt="img02"/>
<img src="images/large/3.jpg" alt="img03"/>
</div>
And here is my javascript:
var $img = $('div#cbp-fwslider img');
var ih = $img.height();
var $div = $('div#cbp-fwslider');
var dh = $div.height();
if (dh > ih) {
var dif = (dh - ih);
$img.css('margin-top', + dif / 2 + "px");
}
Now, this works in part. What it does is calculates the correct "margin-top" to vertically center the first image within the container but then applies it to all involved. I have no doubt that this is because I have set the javascript to set the "margin-top" as the same for all the images.
My question is, how do I set a variable to make it so it does this separately for all the items that I put in my gallery?
Forgive me if this is a basic question that I could have found the answer for elsewhere, I am pretty wet behind the ears when it comes to javascript.
Also if anybody knows of an easier/more efficient way of achieving what I want then it would be great if you could point me in the right direction.
I must advise that the container has a dynamic height and so do all images. With the nature of how the gallery works, I can't use absolute positioning and THIS technique doesn't seem to work either.
Thanks in advance for any help.
You'll want to run your code individually on each image rather than on the collection of images. You can do this by using each to loop through the collection:
$('div#cbp-fwslider img').each(function(){
var $img = $(this);
var ih = $img.height();
var $div = $('div#cbp-fwslider');
var dh = $div.height();
if (dh > ih) {
var dif = (dh - ih);
$img.css('margin-top', + dif / 2 + "px");
}
});
You can just use css to vertically align all images to center.
<div id="cbp-fwslider" class="cbp-fwslider">
<img src="images/large/1.jpg" alt="img01"/>
<img src="images/large/2.jpg" alt="img02"/>
<img src="images/large/3.jpg" alt="img03"/>
</div>
css
img {
vertical-align: middle;
}
see http://jsfiddle.net/vishnurajv/xR28t/
Try to find the maximum height of img in your div, after that set margin-top for all of other img. This is my idea, you or someone can do better.
var maxHeight = 0;
$('div#cbp-fwslider img').each(function(){
if($(this).height() > maxHeight) maxHeight = $(this).height();
});
$('div#cbp-fwslider img').each(function(){
$(this).css('margin-top', Number(maxHeight - $(this).height()) / 2 + 'px');
});
Hope help!
PLEASE DO NOT RECOMMEND JQUERY - I AM DOING THIS EXERCISE FOR LEARNING PURPOSES.
I have implemented a JavaScript, which rotates images (_elementSlideChange) on a timer, using a set interval of 10 seconds. Also I have added a slide functionality to this, which is 7 milliseconds (_slideImage).
The image rotates automatically every 10 seconds on page load, and I have also provided next and previous buttons, which allow the user to change the images manually.
_elementSlideChange: function () {
var myString;
var myText;
for (var i = 0; i < this._imgArray.length; i++) {
var imageArr = "url(" + this._imgArray[i].src + ")";
var imageBg = this._imageHolder.style.background + "";
if (imageArr == imageBg) {
if (i == (this._imgArray.length - 1)) {
myString = "url(" + this._imgArray[0].src + ")";
myText = this._infoArray[0];
} else {
myString = "url(" + this._imgArray[(i + 1)].src + ")";
myText = this._infoArray[i + 1];
}
}
}
this._imageNextSlide.style.background = myString;
this._imageNextSlide.style.background);
this._infoElement.innerHTML = myText;
this._myTimer = setInterval(MyProject.Utils.createDelegate(this._slideImage, this), 7);
},
_slideImage: function () {
if (parseInt(this._imageHolder.style.width) >= 0 && parseInt(this._imageNextSlide.style.width) <= 450) {
this._imageHolder.style.backgroundPosition = "right";
this._imageHolder.style.width = (parseInt(this._imageHolder.style.width) - 1) + 'px';
console.log(this._imageNextSlide.style.background);
this._imageNextSlide.style.width = (parseInt(this._imageNextSlide.style.width) + 1) + 'px';
} else {
console.log("reached 0px");
if (parseInt(this._imageHolder.style.width) == 0) {
this._imageHolder.style.background = this._imageNextSlide.style.background;
this._imageHolder.style.width = 450 + 'px';
this._imageHolder === this._imageNextSlide;
this._imageHolder.className = "orginalImage";
this._imageNextSlide.style.width = 0 + "px";
this._imageNextSlide = this._dummyImageNextSlide;
this._imagesElement.appendChild(this._imageHolder);
this._imagesElement.appendChild(this._imageNextSlide);
clearInterval(this._myTimer);
}
clearInterval(this._myTimer);
clearInterval(this._elementSlideChange);
}
}
So when the user clicks on the Next arrow button, the event listener for "click" is triggered. This creates a div for the current image on display, and creates a new div, which will contain the next image. The image slide and rotation works correctly (whether it's onLoad or onClick). The issue I have is if I click the Next button, while the new div image is sliding into position, it causes it to run into an infinite loop, so the same div with the image to be displayed keeps sliding in, and the more you click the Next button, the faster the image starts to rotate.
I have tried putting a clear interval for the image rotation and slider, but I do understand my code is wrong, which causes the infinite loop of the sliding image. And I know I am close to finishing the functionality.
Can anyone please advise where I could be going wrong? Or should I try to implement the sliding DIV in another way?
Once again please don't recommend jQuery.
And thank you for your help in advance.
Kush
To solve the issue, I did re-write the entire code, where I had a next and previous button event listener.
myProject.Utils.addHandler(this._nextImageElement, "click", myProject.Utils.createDelegate(this._changeImage, this));
Both the buttons will call the same function :
_changeImage: function (e)
In this function I check to see if the function is Transition (changing images),
I declare a boolean var forward = e.target == this._nextImageElement;
Then check to see the current index if forward ? Add 1 else minus 1
this._currentImageIndex += forward ? 1 : -1;
If its at the end of the Array and forward is true, assign the this._currentImageIndex to reset to 0 or Array.length – 1 if it’s in reverse
Then call another function which gives the ‘div’ a sliding effect. In this case call it this._transitionImage(forward);
In this function, set the this._inTranstion to true. (Because the div’s are sliding in this case).
The following code solved the issue i was having.
this._slideImageElement.style.backgroundImage = "url(\"" + this._imgArray[this._currentImageIndex].src + "\")";
this._slideImageElement.style.backgroundPosition = forward ? "left" : "right";
this._slideImageElement.style.left = forward ? "auto" : "0px";
this._slideImageElement.style.right = forward ? "0px" : "auto";
The above code is very important as the object is to place the “sliding in div” Left or Right of the current Visible “div” to the user, and this is mainly dependent on if the forward variable is true or false.
var i = 0;
Then start the transition by
setInterval( function() {
this._currentImageElement.style.backgroundPosition = (forward ? -1 : 1) * (i + 1) + "px";
this._slideImageElement.style.width = (i + 1) + "px";
Notice the forward will determine if the bgPosition will go to the left if its forward as we multiple by -1 or +1,
So for example
If the user clicks NEXT BUTTON,
Forward = true
So the first thing we do is set the
this._slideImageElement.style.backgroundPosition = "left"
Then
this._slideImageElement.style.left = "auto"
this._slideImageElement.style.right = "0px"
This means when the sliding image moves in its background position is LEFT but the div is placed on the RIGHT to 0px;
then this._currentImageElement.style.backgroundPosition = -1 * (i + 1)
Which moves the position of the currentImageElement to the left by 1px,
Increase the width of the slideImage which in this case is right of the current div,
and as the current div moves to the left the sliding image starts to appear from the right. (By default set the width of slideImageElement to 0px so the div exists but isn’t visible to the user). This gives it the slide effect of moving forward new image coming from the right.
this._slideImageElement.style.width = (i + 1) + "px";
then declare it to stop when it it’s the image width. In this case it will be 500px.
if ((i = i + 2) == 500) {
In this if statement reset the currentImageElement background and the background position “right” or “left” don’t really matter as long it has been reset.
Clear the interval
Set the transition to false again
Then call a setTimeout for the function changeImage, which will continue until the slide is completed.
The following shows the reset code as this is very important to prevent repeating the same image (This solved my entire issue)
// set the current image to the "new" current image and reset it's background position
this._currentImageElement.style.backgroundImage = "url(\"" + this._imgArray[this._currentImageIndex].src + "\")";
this._currentImageElement.style.backgroundPosition = "right";
// reset the slide image width
this._slideImageElement.style.width = "0px";
// clear the transition interval and mark as not in transition
clearInterval(this._transitionInterval);
this._inTransition = false;
// setup the next image timer
this._nextImageTimeout = setTimeout(myProject.Utils.createDelegate(this._changeImage, this), 2500);
}
I have provided a thorough detail because then it easier to understand the logic of the problem, and even if your not having the same issue, this may help you fingure out any problem.
I couldn't provide a JSfiddle, as i have created my CSS using Javascript, there are different ways of doing this, but i wanted to understand the logic behind the forward and reverse, and having a timer which continuously goes forward.
It seems like you want to cancel the animation on the slide (perhaps have it fade out while the next slide animates in, cancel its animation abruptly or let it finish and ignore the button click)
What I usually do, personally, is check for the animated state (yes, I use jquery, but you should be able to test the CSS or positioning values you are using to animate in the same way) you could even add an "active" class or data type during animation to make testing easier. Global flags work, too. If there is animation, ignore the button. (For my work... Depends on your intention)
Like I said, the problem may be with button behaviour not with the animation routine. It would be useful to see how you are calling this from the button click, and what your intended results are going to be.
How about CSS3 transitions?
transition: all 1s ease 0.5s;
Simple example on JS Fiddle.
This takes care of the animation, so you just need to set the intended destination using JavaScript, i.e.
this.style.left = '100px';
Or
this.style.top = '30px';
And CSS3 transitions will smoothly slide the element.
Cross Browser Note!
The transition property may need a vendor prefix for some browsers, I am using the latest production Firefox and you don't need -moz for that. Same goes for Opera, no '-o' required. Internet Exporer 10 needs no prefix. You may need to use -webkit for Safari / Chrome, but test without first.
I'm trying to dynamicly resize text within a div so that the text does not run outside of the box it was intended for. I'm trying to do this so that I can make a printable form.
Geeky Monkey has a jquery plugin that works great but my problem is I can't loop it to do it over and over for different div's to make sure they're all properly sized. If I make all my div's the same class they all get the same text size so obviously this doesn't work.
This is Geeky Monkey's unedited code
(function($) {
$.fn.textfill = function(options) {
var fontSize = options.maxFontPixels;
var ourText = $('span:visible:first', this);
var maxHeight = $(this).height();
var maxWidth = $(this).width();
var textHeight;
var textWidth;
do {
ourText.css('font-size', fontSize);
textHeight = ourText.height();
textWidth = ourText.width();
fontSize = fontSize - 1;
} while ((textHeight > maxHeight || textWidth > maxWidth) && fontSize > 3);
return this;
}
})(jQuery);
$(document).ready(function() {
$('.jtextfill').textfill({ maxFontPixels: 36 });
});
And the html code that goes with it
<div class='jtextfill' style='width:100px;height:50px;'>
<span>My Text Here</span>
</div>
This is what I tried to do to change it and make it a loop
$(document).ready(
for(i=1;i<3;i++){
function() {
$('.jtextfill' + i).textfill({ maxFontPixels: 72 });
})};
And the html to go with my revision
<div class='jtextfill1' style='width:400px;height:200px;'>
<span>THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG</span>
</div>
<div class='jtextfill2' style='width:50px;height:25px;'>
<span>THIS IS THE SECOND PART OF MY TEXT</span>
</div>
As I'm sure you could guess it's not working. jquery does still confuse me so please forgive me if it is an obvious mistake. Any help would be greatly appreciated.
Thanks
OK, as I understand it you want to have various divs each with a different class so that you can give each its own font size (and potentially other individual properties). You want to be able to process each div to - if necessary - shrink the font of the span in the div so that it will fit in the div without overflowing.
If so, calling the textfill() method in a loop but passing the same maxFontPixels parameter to it for every div won't work, because obviously they'll all then start out with the same default maximum font size. You could update your loop to pass in different font sizes, but instead I would suggest changing the textfill() to start with the current font-size of the div, rather than taking it as a parameter.
Then, rather than trying to do a loop to repeatedly call textfill(), you can use a single JQuery selector that selects all of the divs you want to process. Following is just one way to do what I've described. (Note: I haven't actually tested it, but I hope it will get you on your way.)
EDIT: In the original code there was also a basic problem with the .textfill plugin, that (as with any JQuery plugin) its this was a JQuery object that - depending on the selector - may be a list of many DOM elements, but it was treating it as a single DOM element. Just needed to add a this.each() loop around the rest of the function code and it works.
<style>
.someclass1 { font-size: 36px; }
.someclass2 { font-size: 48px; }
</style>
<div class='someclass1 jtextfill' style='width:400px;height:200px;overflow:hidden;'>
<span>THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG</span>
</div>
<div class='someclass2 jtextfill' style='width:50px;height:25px;overflow:hidden;'>
<span>THIS IS THE SECOND PART OF MY TEXT</span>
</div>
<script>
(function($) {
$.fn.textfill = function() {
// EDIT: added the .each()
this.each(function() {
var fontSize = parseInt($(this).css('font-size'),10);
var ourText = $('span:visible:first', this);
var maxHeight = $(this).height();
var maxWidth = $(this).width();
var textHeight;
var textWidth;
do {
ourText.css('font-size', fontSize + "px");
textHeight = ourText.height();
textWidth = ourText.width();
fontSize = fontSize - 1;
} while ((textHeight > maxHeight || textWidth > maxWidth) && fontSize > 3);
// EDIT: added the closing brackets for the .each
});
return this;
}
})(jQuery);
$(document).ready(function() {
$('.jtextfill').textfill();
});
</script>
Notes: in this case the 'jtextfill' class isn't actually defined in the stylesheet, it is used solely as a convenient way to let JQuery select all of the divs that you want to process. The actual font stylings are applied via the 'someClass1', etc., classes. (In case you weren't aware, HTML/CSS allows you to apply multiple classes to the same element.)
I've changed only twothree things in the textfill() method: (1) I get the font-size from the element, which should be returned as a string like '36px', then use parseInt to grab the integer part of that (throwing away the 'px'). (2) When the font is set inside the loop I append 'px' back onto the font size. (3) Added a .each() loop within the plugin function.
after exaclty six attempts begging the original auhtor of an image popup javascript code to make his script compatible with the newer JQuery libraries, all six in vain, I decided its time for me to fix it without him the seventh attempt, and salvage this otherwise perfectly working (after numerous customisations by me) image popup script.
Problem: works when JQuery 1.3.2 ~ 1.4.2 is loaded, but NOT when JQuery 1.4.3 ~ 1.5.1 is loaded. On new builds, images don't enlarge after click on the thumbnails, whereas on the old builds, the do!
Any suggesion/help is kindly welcome and appreciated by me highly. Thanks!
The problem lies somehwere here:
//display content
var displayContent = function(img) {
if (visible) {
var newImg = jQuery.extend(true, {}, img);
resizeImg(newImg);
var imgWidth = newImg.width;
var imgHeight = newImg.height;
var outerWidth = imgWidth + hBound;
var outerHeight = imgHeight + vBound;
$lightbox.stop(true).animate({width:imgWidth, height:(imgHeight + cpHeight),
left: Math.round(($(window).width() - outerWidth)/2),
top:Math.round(($(window).height() - outerHeight)/2)},
tranSpeed,
function() {
enableCtrl();
$innerBox.height(imgHeight);
$info.html(langArrows + " " + langImage + " " + (currIndex+1) + "/" + numItems);
$cpanel.css({top:imgHeight, display:"block"});
$mainImg.css({width:imgWidth, height:imgHeight})
.attr("src", newImg.src).animate({opacity:1}, tranSpeed, startTimer);
showDesc();
}
);
}
}
On line 336 add .show() to the end of the chain. While LekisS was on to the right answer, if you add it there, its not properly hidden so the next time you click the image you will see the image display as its thumbnail size for a brief second.