I'm dynamically adding images via a loop from the flickr.com database. I append these ul, li, img tags as you should do according to the galleryview example. I append it to a div then I call the galleryview function:
$('#gallery').galleryView({
panel_width: 800,
panel_height: 300,
frame_width: 50,
frame_height: 50,
transition_speed: 350,
easing: 'easeInOutQuad',
transition_interval: 0
});
It works if I manually add the ul, li, img tags on the front page but if I add them using jQuery append it doesn't work. But I found that if I make the page load slowly and instantly run the append code it works. How can I use append and afterwards use the galleryview on the appended elements?
Source code:
function initialize_flickr(_div){
var newDiv = $(document.createElement('div'));
//add some style to the div
$(newDiv).css('background-color', '#223');
$(newDiv).css('width', 800);
$(newDiv).css('height', 800);
$(newDiv).css('position', 'absolute');
$(newDiv).css('left', 500);
$(newDiv).css('top', 0);
//append it to the _div
newDiv.appendTo(_div);
// Our very special jQuery JSON function call to Flickr, gets details of the most recent 20 images
$.getJSON("http://api.flickr.com/services/feeds/groups_pool.gne?id=998875#N22&lang=en-us&format=json&jsoncallback=?", displayImages);
function displayImages(data) {
// Randomly choose where to start. A random number between 0 and the number of photos we grabbed (20) minus 9 (we are displaying 9 photos).
var iStart = Math.floor(Math.random()*(11));
// Reset our counter to 0
var iCount = 0;
// Start putting together the HTML string
var htmlString = "<ul id='gallery'>";
// Now start cycling through our array of Flickr photo details
$.each(data.items, function(i,item){
// Let's only display 9 photos (a 3x3 grid), starting from a random point in the feed
if (iCount > iStart && iCount < (iStart + 10)) {
// I only want the ickle square thumbnails
var sourceSquare = (item.media.m).replace("_m.jpg", "_s.jpg");
// Here's where we piece together the HTML
htmlString += '<li>';
htmlString += '<span class="panel-overlay">'+item.title+'</span>';
htmlString += '<img src="'+sourceSquare+'" />';
htmlString += '</li>';
}
// Increase our counter by 1
iCount++;
});
// Pop our HTML in the #images DIV
$(newDiv).append(htmlString + "</ul>").each(function(){
$('#gallery').galleryView({
panel_width: 800,
panel_height: 300,
frame_width: 50,
frame_height: 50,
transition_speed: 350,
easing: 'easeInOutQuad',
transition_interval: 0
});
});
// Close down the JSON function call
}
}
Try adding a callback(for galleryView) to your append. This way you are calling galleryView only after your append.
$(newDiv).append(htmlString + "</ul>").each(function(){ $('#gallery').galleryView({ panel_width: 800, panel_height: 300, frame_width: 50, frame_height: 50, transition_speed: 350, easing: 'easeInOutQuad', transition_interval: 0 }); });
Each Callback Example-
.appendTo('#element').each(function() {
//Call galleryView here
});
Are you trying to run your jQuery before the DOM has finishing parsing? Try executing your code after the browser has loaded.
$(document).ready(function() {
// put all your jQuery goodness in here.
});
http://www.learningjquery.com/2006/09/introducing-document-ready
Related
I'm working to create an image gallery where the images will be composed by progressively fading in layers one on top of the other to form the final image.
I have many such layers so instead of loading them into many different <img> elements all at once (which would slow load time) I want to start off with a single <img id="base"> and then progressively add image elements with the jQuery .after() method, assign them the relevant sources and fade them in with a delay.
The problem is that I can't attach animations to the newly created elements because (I'm assuming) they don't exist yet within the same function. Here is my code:
HTML
<div id="gallery">
<img id="base" src="image-1.jpg">
</div>
CSS
#base {
opacity: 0;
}
.layers {
position: absolute;
top: 0;
left: 0;
opacity: 0;
}
JavaScript
$(document).ready(function () {
$("#base").animate({opacity: 1}, 300); //fade in base
for (var i = 1; i <= numberOfLayers; i++, gap += 300) {
// create a new element
$("#base").after("<img class='layers' src='" + imgName + ".png'>");
// fade that new element in
$("#gallery").children().eq(i).delay(gap).animate({opacity: '1'}, 300);
}
}
Please note that I've altered my actual code to illustrate this better. I'm fairly new at JavaScript but I'm a quick learner so I'd appreciate if you could tell me what I'm doing wrong and what solution I should pursue.
EDIT: I've included my code inside your JSFiddle (all you need to do is add the library-X.jpg images) : http://jsfiddle.net/pgoevx03/
I've tried to replicate the intent of the code in a cleaner/more flexible way. Please let me know if I can do anything else to help.
I'm not saying this is the best way to do it, but it should be easy enough to understand and use.
The code is untested, but should work just fine. The comments should help you out if there's any compilation error.
Note that I removed the first image in the gallery (with ID "base") from the HTML file. It will be appended the same way as the rest.
// Array storing all the images to append to the gallery
var galleryImages = [
"image-1.jpg",
"image-2.jpg",
"image-3.jpg",
"image-4.jpg",
"image-5.jpg",
"image-6.jpg",
"image-7.jpg",
"image-8.jpg",
"image-9.jpg",
"image-10.jpg"
];
// Index of the image about to be appended
var imgIndex = -1;
var baseID = "base";
$(document).ready(function() {
// Start appending images
appendAllImages();
});
// Append the images, one at a time, at the end of the gallery
function appendAllImages() {
//Move to the next image
imgIndex++;
//We've reached the last image: stop appending
if (imgIndex >= galleryImages.length) return;
//Create image object
var img = $("<img>", {
src: galleryImages[imgIndex],
});
if (imgIndex === 0) { // It's the base!
//Give the base ID to the first image
img.attr("id", baseID);
//Append the image object
$("#gallery").append(img);
} else { // It's a layer!
//Give the base ID to the first image
img.attr("class", "layers");
//Append the image object
$("#" + baseID).after(img);
}
//Fade in the image appended; append the next image once it's done fading in
img.animate({
opacity: 1,
}, 300, appendAllImages);
}
I'm starting a project that will require that users be able to create multiple custom avatars. To do this, I want them to be able to send images that are in their inventory to a manipulation frame. Within this frame, users should be able to move and resize the images - double clicking them to remove the image from the frame and sending it back into their inventory. To the right of the manipulation frame, I would like a sortable list that will dictate the z-index of the corresponding item with the item at the top being in back of the manipulation frame. So far, I have this: http://jsfiddle.net/Thaikhan/e3Gd6/10/show/.
The list generates and is sortable but does not affect the z-index of the image. Also, the code is pretty buggy and often images will disappear off frame.
See JSFiddle here: http://jsfiddle.net/Thaikhan/e3Gd6/10/
Here is the JavaScript code:
//Click into Frame
$('.inventory').on('click', 'img', function () {
$(this).resizable({
aspectRatio: 1,
autoHide: true,
containment: "parent",
minHeight: 50,
minWidth: 50
});
$(this).parent().appendTo(".frame").draggable({
containment: "parent",
cursor: "move"
});
refreshIndexList();
});
//Double Click out of Frame
$('.frame').on('dblclick', '.ui-draggable', function () {
$(this).appendTo(".inventory");
$(this).draggable("destroy");
$("img", this).resizable("destroy").attr('style', '');
refreshIndexList();
});
//Updates List Items
function refreshIndexList() {
var listitems = $('.frame').children().length;
$('#sortable').empty();
var titles = $(".frame img:nth-of-type(1)").attr('title');
for (var count = 1; count <= listitems; count++) {
var title = $(".frame img").eq(count-1).attr('title');
var $li = $("<li class='ui-state-default'/>").text(title);
$('#sortable').append($li);
}
}
//Makes List Sortable
$(function () {
$("#sortable").sortable({
placeholder: "ui-state-highlight"
});
$("#sortable").disableSelection();
});
//Inventory Grid
$(function() {
$( "#grid" ).sortable();
$( "#grid" ).disableSelection();
});
I am a novice in JavaScript and have received much help in getting this far. I am hoping that once again I can receive help from the community and figure out how to have the sortable list change the z-index of the item. Additionally, if anyone sees why it's buggy, please let me know.
Ultimately, I want to be able to grab from the manipulation frame the image_id's, their locations, their z-indices, and their sizes and store it all in a database. This will hopefully allow users to return and edit their avatar creations.
A thousand thanks for your help!
create function with editing z-index:
function zindex() {
var title = "";
var i = 9999;
$(".ui-state-default").each(function () {
i--; //z-index position counter
title = $(this).text();
$(".frame img[title='" + title + "']").parent().css("z-index", i);
});
}
call it on adding img
$('.inventory').on('click', 'img', function () {
$(this).resizable({
aspectRatio: 1,
autoHide: true,
containment: "parent",
minHeight: 50,
minWidth: 50
});
$(this).parent().appendTo(".frame").draggable({
containment: "parent",
cursor: "move"
});
refreshIndexList();
zindex();
});
and use it on mouseup (drop event emulation)
$("#sortable").mouseup(function () {
setTimeout(function() {
zindex();}, 100);
});
FIDDLE
Here's what I'm trying to achieve:
Scrolling marquee content (with flexible length) makes a complete journey from right to left of the screen
Once it has disappeared off the screen, bring up some generic messages
In the background during generic messages, check for any new scrolling content and load it
Only when the generic messages have finished displaying, start scrolling again (if there is new content), otherwise repeat the generic messages
http://jsfiddle.net/Vbmm5/
(function($) {
$.fn.marquee = function(options) {
return this.each(function() {
var o = $.extend({}, $.fn.marquee.defaults, options),
$this = $(this),
$marqueeWrapper,
containerWidth,
animationCss,
elWidth;
o = $.extend({}, o, $this.data());
o.gap = o.duplicated ? o.gap : 0;
$this.wrapInner('<div class="js-marquee"></div>');
var $el = $this.find('.js-marquee').css({
'margin-right': o.gap,
'float':'left'
});
if(o.duplicated) {
$el.clone().appendTo($this);
}
$this.wrapInner('<div style="width:100000px" class="js-marquee-wrapper"></div>');
elWidth = $this.find('.js-marquee:first').width() + o.gap;
$marqueeWrapper = $this.find('.js-marquee-wrapper');
containerWidth = $this.width();
o.speed = ((parseInt(elWidth,10) + parseInt(containerWidth,10)) / parseInt(containerWidth,10)) * o.speed;
var animate = function() {
if(!o.duplicated) {
$marqueeWrapper.css('margin-left', o.direction == 'left' ? containerWidth : '-' + elWidth + 'px');
animationCss = { 'margin-left': o.direction == 'left' ? '-' + elWidth + 'px' : containerWidth };
}
else {
$marqueeWrapper.css('margin-left', o.direction == 'left' ? 0 : '-' + elWidth + 'px');
animationCss = { 'margin-left': o.direction == 'left' ? '-' + elWidth + 'px' : 0 };
}
$marqueeWrapper.animate(animationCss, o.speed , 'linear', function(){
getUpdates();
});
};
setTimeout(animate, o.delayBeforeStart);
});
};
})(jQuery);
$(function(){
$('#scrollerContent').marquee({
speed: 3000,
gap: 50,
delayBeforeStart: 0,
direction: 'right',
duplicated: false,
pauseOnHover: false,
});
});
function getUpdates()
{
alert("Hello"); // This is where the jQuery get function would be to update the text
alert("Show Details"); // This is where the generic details would be displayed
marquee();
}
The problem is the scrolling element requires a width, which obviously changes with every new 'load' of messages. I tried putting the getUpdates() function inside the main jQuery function, which does work almost perfectly but doesn't update the containerWidth variable, so messages longer than the original start half-way through, and shorter messages take ages to appear.
What I need is for the whole of the function to be re-run, including the re-setting of the width after the #scrollerText paragraph has been changed.
How do I do this?
If you had used console.log() instead of alert() you would have had the console open and seen
Uncaught ReferenceError: marquee is not defined
In getUpdates() you're calling a function marquee(); that does not exist. The script terminates there.
Go back a few steps (undoing what you've removed) and where the code triggers the animation, add the code to update the text before that, or if you're getting data you need to wrap that bit of code.
So, if you were getting data from the server, theurl.php would return text new text and nothing else. Move the code that triggers the animation to go again within the $.get callback function.
http://jsfiddle.net/Vbmm5/4/
$marqueeWrapper.animate(animationCss, o.speed , 'linear', function(){
// clear the text to prevent it from hanging at the end of the
// marquee while the script gets new data from the server
$this.find('#scrollerText').text('');
// get new text
$.get('theurl.php', function(response){
$this.find('#scrollerText').text(response);
// update the width
elWidth = $this.find('.js-marquee:first').width();
//fire event
$this.trigger('finished');
//animate again
if(o.pauseOnCycle) {
setTimeout(animate, o.delayBeforeStart);
}
else {
animate();
}
});
});
(the URL and post data in the example on jsfiddle is jsfiddle's way of returning html)
I've used $this.find('#scrollerText').text(response); even though there should be only one id and $('#scrollerText').text(response); would be fine. If you were to have multiple marquees you would target each marquee's text using $this.find, so if you want more than one use classes instead $this.find('.scrollerText').text(response);
I'm putting together a quick little status board that shows active and upcoming github issues.
I have them all pulled in and formatted as a simple list and found a nice jQuery plugin that cycles through each item as a sort of slideshow. However, it was requested that it show multiple issues at once to fill up the screen more.
So on each slide swap it would display, say 5 LI items at once versus just 1. And then swap to show the next 5 and so on.
HTML
...
<ul id="issue-list">
<li class="issue"></li>
...
<li class="issue"></li>
</ul>
...
<script type="text/javascript">
$(function() {
$('#issue-list').swapmyli({
swapTime: 900, // Speed of effect in animation
transitionTime: 700, // Speed of Transition of ul (height transformation)
time: 4000, // How long each slide will show
timer: 1, // Show (1) /Hide (0) the timer.
css: 0 // Apply plugin css on the list elements.
});
});
</script>
JS
(function(e) {
e.fn.swapmyli = function(t) {
function s() {
var e = i.parent().find(".timer span");
e.animate({
width: "100%"
}, r);
var n = i.find("li:first").outerHeight(true);
i.find("li:first").fadeOut(120);
i.animate({
height: n
}, t.transitionTime);
i.find("li").hide();
e.animate({
width: "0%"
}, 60);
i.find("li:first").remove().appendTo(i).fadeIn(t.swapTime)
}
var n = {
swapTime: 300,
transitionTime: 900,
time: 2e3,
timer: 1,
css: 1
};
var t = e.extend(n, t);
var r = t.time - t.swapTime;
var i = this;
i.wrap('<div class="swapmyli clearfix"></div>');
i.after('<div class="timer"><span></span></div><br class="clear" />');
e(window).load(function() {
var e = i.find("li:first").outerHeight(true);
i.height(e);
i.find("li").hide();
s()
});
if (t.timer == 0) {
i.parent().find(".timer").hide()
}
if (t.css == 0) {
i.parent().addClass("nocss")
}
setInterval(s, t.time)
}
})(jQuery)
I'm not sure if outerHeight() will function correctly with slice, but you may try changing these lines:
var n = i.find("li:first").outerHeight(true);
i.find("li:first").fadeOut(120);
To the following:
var n = i.find("li").slice(0, 4).outerHeight(true);
i.find("li").slice(0, 4).fadeOut(120);
That's sort of a quick answer, but hopefully you're catching my drift. Probably need to play around with it a little bit :)
I'm trying to use jcarousel to build a container with multiple rows, I've tried a few things but have had no luck. Can anyone make any suggestions on how to create it?
This is .js code substitutions according to #Sike and a little additional of me, the height was not set dynamically, now it is.
var defaults = {
vertical: false,
rtl: false,
start: 1,
offset: 1,
size: null,
scroll: 3,
visible: null,
animation: 'normal',
easing: 'swing',
auto: 0,
wrap: null,
initCallback: null,
setupCallback: null,
reloadCallback: null,
itemLoadCallback: null,
itemFirstInCallback: null,
itemFirstOutCallback: null,
itemLastInCallback: null,
itemLastOutCallback: null,
itemVisibleInCallback: null,
itemVisibleOutCallback: null,
animationStepCallback: null,
buttonNextHTML: '<div></div>',
buttonPrevHTML: '<div></div>',
buttonNextEvent: 'click',
buttonPrevEvent: 'click',
buttonNextCallback: null,
buttonPrevCallback: null,
moduleWidth: null,
rows: null,
itemFallbackDimension: null
}, windowLoaded = false;
this.clip.addClass(this.className('jcarousel-clip')).css({
position: 'relative',
height: this.options.rows * this.options.moduleWidth
});
this.container.addClass(this.className('jcarousel-container')).css({
position: 'relative',
height: this.options.rows * this.options.moduleWidth
});
if (li.size() > 0) {
var moduleCount = li.size();
var wh = 0, j = this.options.offset;
wh = this.options.moduleWidth * Math.ceil(moduleCount / this.options.rows);
wh = wh + this.options.moduleWidth;
li.each(function() {
self.format(this, j++);
//wh += self.dimension(this, di);
});
this.list.css(this.wh, wh + 'px');
// Only set if not explicitly passed as option
if (!o || o.size === undefined) {
this.options.size = Math.ceil(li.size() / this.options.rows);
}
}
This is the call in using the static_sample.html of the code bundle in the download of jscarousel:
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery('#mycarousel').jcarousel( {
scroll: 1,
moduleWidth: 75,
rows:2,
animation: 'slow'
});
});
</script>
In case you need to change the content of the carousel and reload the carousel you need to do this:
// Destroy contents of wrapper
$('.wrapper *').remove();
// Create UL list
$('.wrapper').append('<ul id="carousellist"></ul>')
// Load your items into the carousellist
for (var i = 0; i < 10; i++)
{
$('#carouselist').append('<li>Item ' + i + '</li>');
}
// Now apply carousel to list
jQuery('#carousellist').jcarousel({ // your config });
The carousel html definition needs to be like this:
<div class="wrapper">
<ul id="mycarousel0" class="jcarousel-skin-tango">
...<li></li>
</ul>
</div>
Thanks to Webcidentes
We have had to make a similar modifiaction. We do this by extending the default options, to include a rows value, and the width of each item (we call them modules) then divide the width by the number of rows.
Code added to jCarousel function...
Add to default options:
moduleWidth: null,
rows:null,
Then set when creating jCarousel:
$('.columns2.rows2 .mycarousel').jcarousel( {
scroll: 1,
moduleWidth: 290,
rows:2,
itemLoadCallback: tonyTest,
animation: 'slow'
});
The find and edit the lines in:
$.jcarousel = function(e, o) {
if (li.size() > 0) {
...
moduleCount = li.size();
wh = this.options.moduleWidth * Math.ceil( moduleCount / this.options.rows );
wh = wh + this.options.moduleWidth;
this.list.css(this.wh, wh + 'px');
// Only set if not explicitly passed as option
if (!o || o.size === undefined)
this.options.size = Math.ceil( li.size() / this.options.rows );
Hope this helps,
Tony Dillon
you might want to look at serialScroll or localScroll instead of jcarousel.
I found this post on Google Groups that has a working version for multiple rows. I have used this and it works great. http://groups.google.com/group/jquery-en/browse_thread/thread/2c7c4a86d19cadf9
I tried the above solutions and found changing the original jCarousel code to be troublesome - it introduced buggy behaviour for me because it didn't play nice with some of the features of jCarousel such as the continous looping etc.
I used another approach which works great and I thought others may benefit from it as well. It is the JS code I use to create the li items to support a jCarousel with multiple rows with elegant flow of items, i.e. fill horizontally, then vertically, then scrollpages:
123 | 789
456 | 0AB
It will add (value of var carouselRows) items to a single li and as such allows jCarousel to support multiple rows without modifying the original jCarousel code.
// Populate Album photos with support for multiple rows filling first columns, then rows, then pages
var carouselRows=3; // number of rows in the carousel
var carouselColumns=5 // number of columns per carousel page
var numItems=25; // the total number of items to display in jcarousel
for (var indexpage=0; indexpage<Math.ceil(numItems/(carouselRows*carouselColumns)); indexpage++) // for each carousel page
{
for (var indexcolumn = 0; indexcolumn<carouselColumns; indexcolumn++) // for each column on that carousel page
{
// handle cases with less columns than value of carouselColumns
if (indexcolumn<numItems-(indexpage*carouselRows*carouselColumns))
{
var li = document.createElement('li');
for (var indexrow = 0; indexrow < carouselRows; indexrow++) // for each row in that column
{
var indexitem = (indexpage*carouselRows*carouselColumns)+(indexrow*carouselColumns)+indexcolumn;
// handle cases where there is no item for the row below
if (indexitem<numItems)
{
var div = document.createElement('div'), img = document.createElement('img');
img.src = imagesArray[indexitem]; // replace this by your images source
div.appendChild(img);
li.appendChild(div);
}
}
$ul.append(li); // append to ul in the DOM
}
}
}
After this code has filled the ul with the li items jCarousel should be invoked.
Hope this helps someone.
Jonathan
If you need a quick solution for a fixed or one-off requirement that definitely doesn't involve changing core library code which may be updated from time to time, the following may suit. To turn the following six items into two rows on the carousel:
<div class="item">contents</div>
<div class="item">contents</div>
<div class="item">contents</div>
<div class="item">contents</div>
<div class="item">contents</div>
<div class="item">contents</div>
you can use a little JS to wrap the divs into LI groups of two then initialise the carousel. your scenario may allow you to do the grouping on the server isn't always possible. obviously you can extend this to however many rows you need.
var $pArr = $('div.item');
var pArrLen = $pArr.length;
for (var i = 0;i < pArrLen;i+=2){
$pArr.filter(':eq('+i+'),:eq('+(i+1)+')').wrapAll('<li />');
};