jQuery image Grid System - javascript

I have one question about image grid system.
I created this DEMO from codepen.io
In this demo you can see :
<div class="photo-row">
<div class="photo-item">
<!--Posted image here <img src="image/abc.jpg"/>-->
</div>
</div>
This DEMO is working fine but. My question is how can I use my grid system like in this css:
<div class="photo">
<div class="photo-row">
<img src="abc.jpg"/>
</div>
<div class="photo-row">
<img src="abc.jpg"/>
</div>
</div>
I created second demo for this: second DEMO. In the second demo you can see the grid system not working like first DEMO.
Also my jQuery code:
(function($,sr){
var debounce = function (func, threshold, execAsap) {
var timeout;
return function debounced () {
var obj = this, args = arguments;
function delayed () {
if (!execAsap)
func.apply(obj, args);
timeout = null;
};
if (timeout)
clearTimeout(timeout);
else if (execAsap)
func.apply(obj, args);
timeout = setTimeout(delayed, threshold || 100);
};
}
// smartresize
jQuery.fn[sr] = function(fn){ return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr); };
})(jQuery,'smartresize');
/* Wait for DOM to be ready */
$(function() {
// Detect resize event
$(window).smartresize(function () {
// Set photo image size
$('.photo-row').each(function () {
var $pi = $(this).find('.photo-item'),
cWidth = $(this).parent('.photo').width();
// Generate array containing all image aspect ratios
var ratios = $pi.map(function () {
return $(this).find('img').data('org-width') / $(this).find('img').data('org-height');
}).get();
// Get sum of widths
var sumRatios = 0, sumMargins = 0,
minRatio = Math.min.apply(Math, ratios);
for (var i = 0; i < $pi.length; i++) {
sumRatios += ratios[i]/minRatio;
};
$pi.each(function (){
sumMargins += parseInt($(this).css('margin-left')) + parseInt($(this).css('margin-right'));
});
// Calculate dimensions
$pi.each(function (i) {
var minWidth = (cWidth - sumMargins)/sumRatios;
$(this).find('img')
.height(Math.floor(minWidth/minRatio))
.width(Math.floor(minWidth/minRatio) * ratios[i]);
});
});
});
});
/* Wait for images to be loaded */
$(window).load(function () {
// Store original image dimensions
$('.photo-item img').each(function () {
$(this)
.data('org-width', $(this)[0].naturalWidth)
.data('org-height', $(this)[0].naturalHeight);
});
$(window).resize();
});
Anyone can help me in this regard ? Thank you in advance for your answer.

Since you'll be creating the HTML dynamically you should remove the .photo-row container but keep .photo-item like so:
<div class="photo-item">
<img src="..." />
</div>
<div class="photo-item">
<img src="..." />
</div>
<div class="photo-item">
<img src="..." />
</div>
...
Then what you can do is wrap your elements with .photo-row on page load. First starting with various sets of two:
var imgGrab = $('.photo-item'); //photos
var imgLength = imgGrab.length; //number of photos
for ( i=0; i<imgLength; i=i+3 ) {
imgGrab.eq(i+1).add( imgGrab.eq(i+1) ).add( imgGrab.eq(i+2) ).wrapAll('<div class="photo-row"></div>'); //wrap photos
}
Then find the remanding ones and wrap those with .photo-row as well:
$(".photo-item").each(function(){
if($(this).parent().is(":not(.photo-row)")){
$(this).wrap('<div class="photo-row"></div>');
}
});
This will wrap your images dynamically and let the CSS do its job regardless of the number of them:
CODEPEN

Related

Update jQuery plugin to build HTML and prevent it from rebuilding on multiple calls

I am working to convert my simple JavaScript Donut Chart into a jQuery Plugin.
It is my first jQuery plugin and I could use some help in a couple place please...
Demo of what I have so far: http://jsfiddle.net/jasondavis/qsgqebox/
Below is the JavaScript I have so far.
jQuery
jQuery.fn.updatePercentageGraph = function (options) {
var settings = $.extend({
// These are the defaults.
percent: 0,
}, options );
var percent = settings.percent;
if(typeof percent === 'undefined') {
var percent = parseInt(this.data('percent'));
}else{
if(percent === '') {
var percent = parseInt(this.data('percent'));
}else{
var percent = parseInt(percent);
this.attr('data-percent', percent);
}
}
var deg = 360*percent/100;
if (percent > 50) {
this.addClass('gt-50');
}else{
this.removeClass('gt-50');
}
$('.ppc-progress-fill').css('transform','rotate('+ deg +'deg)');
$('.ppc-percents span').html(percent+'%');
};
Usage:
$('#project_progress2').updatePercentageGraph(34);
What I need help with:
1)
It currently require the user to setup the HTML like this:
<div id="project_progress" class="progress-pie-chart" data-percent="40">
<div class="ppc-progress">
<div class="ppc-progress-fill4" style="transform: rotate(136.8deg);"></div>
</div>
<div class="ppc-percents4">
<div class="pcc-percents-wrapper">
<span>40%</span>
</div>
</div>
</div>
What I want to do though is make it where you can simply do something like this....
<div id="project_progress" class="progress-pie-chart" data-percent="40"></div>
and the jQuery plugin would then auto-create the proper child nodes.
The part jQuery would auto create:
<div class="ppc-progress">
<div class="ppc-progress-fill4" style="transform: rotate(136.8deg);"></div>
</div>
<div class="ppc-percents4">
<div class="pcc-percents-wrapper">
<span>40%</span>
</div>
</div>
2) Update some selectors to allow multiple Donut charts on page
Another issue in the plugin so far is the 3rd and 4th lines up from the bottom of the JavaScript shown above. It is calling $('.ppc-progress-fill') and $('.ppc-percents span') which would prevent the usage of multiple charts on the page so that need to be updated to target the class that exist in the current chart only.
3) Optimize to prevent the HTML structure from being re-created every time the function is called to update the percent value
If I convert this plugin to auto-generate the HTML structure, then I need to also consider optimizing it so that it doesn't have to keep on re-generating that structure over and over each time my code runs that will be calling $('#project_progress2').updatePercentageGraph(34); because in my project where I will use this, these charts will constantly be updating there percentage values.
Perhaps it might even be better to have a function that create the initial chart HTML and then a 2nd function that can be called over and over repeatedly that just handles the updating of the percentage and won't attempt to rebuild and inject the HTML structure over and over!
These issue I mention are the key areas I am a little stuck on at the moment and could use some help please.
JSFiddle Demo:
JSFiddle of what I have so far along with some buttons to test updating the percentage values: http://jsfiddle.net/jasondavis/qsgqebox/
1) The part jQuery would auto create
To solve this point you need to create the HTML structure on plugin creation.
2) Update some selectors to allow multiple Donut charts on page
Prevent using whole page selectors. Instead, you can keep a reference to the created HTML structure and work only on this subset. Not the entire DOM.
3) Optimize to prevent the HTML structure from being re-created every time the function is called to update the percent value
A usual pattern to solve multiple instances is to create a data attribute that holds the plugin instance. If an instance already exists, then you just act on that instance instead of creating a new one.
Having this instance is also useful for another jQuery pattern for adding methods to plugins. You can check if the parameter passed to the plugin is a string and then call a method with that name.
$('#project_progress').updatePercentageGraph('percent', percent);
Also you can get the value using the same method without parameter:
var percent = $('#project_progress').updatePercentageGraph('percent');
All in one, I would suggest something like this:
(function ($, undefined) {
'use strict';
function PercentageGraph(element, options) {
this.$percentageGraph = $(element).append(
'<div class="ppc-progress">' +
'<div class="ppc-progress-fill"></div>' +
'</div>' +
'<div class="ppc-percents">' +
'<div class="pcc-percents-wrapper">' +
'<span>0%</span>' +
'</div>' +
'</div>'
);
this.options = $.extend({}, $(element).data(), options);
this._init();
}
PercentageGraph.prototype = {
_init: function () {
this.percent(this.options.percent || 0);
},
_update: function () {
var percent = this.options.percent;
var deg = 360*percent/100;
if (percent > 50) {
this.$percentageGraph.addClass('gt-50');
}else{
this.$percentageGraph.removeClass('gt-50');
}
this.$percentageGraph.find('.ppc-progress-fill').css('transform','rotate('+ deg +'deg)');
this.$percentageGraph.find('.ppc-percents span').html(percent+'%');
},
percent: function (percent) {
// If no parameter, act as a getter. Otherwise act as a setter.
if (percent === undefined) {
return this.options.percent;
} else {
this.options.percent = percent;
this._update();
}
},
}
$.fn.updatePercentageGraph = function (options) {
var args = Array.prototype.slice.call(arguments, 1),
result;
this.each(function () {
var plugin = $(this).data('percentage-graph');
if (!plugin) {
$(this).data('percentage-graph', (plugin = new PercentageGraph(this, options)));
}
var method = typeof options === 'string' ? options : '_init';
result = plugin[method].apply(plugin, args);
// Break the .each iteration if it is a getter, that is, when the method returns something.
return result === undefined;
});
return result || this;
};
}(jQuery));
See demo
Am I crazy? Yes, I am!
Here you are http://jsfiddle.net/qsgqebox/3/
I'm not going to explain to you all this code. Just want to say that this is the way I usually code plugins for jQuery.
(function($) {
'use strict';
var PercentageGraph = function(element) {
// Setup settings
this.settings = $.extend({
percent: element.data('percent') ? element.data('percent') : 0
});
// Store the given element
this.element = element;
// Create the progress bar
this.create();
// Initialization
this.update();
}
PercentageGraph.prototype = {
create: function() {
// Create:
// <div class="ppc-progress">
// <div class="ppc-progress-fill4"></div>
// </div>
this.progress = $('<div />');
this.progress.addClass('ppc-progress');
this.progressFill = $('<div />');
this.progressFill
.addClass('ppc-progress-fill')
.appendTo(this.progress);
// Create:
// <div class="ppc-percents4">
// <div class="pcc-percents-wrapper">
// <span>40%</span>
// </div>
// </div>
this.percents = $('<div />');
this.percents.addClass('ppc-percents');
this.percentsWrapper = $('<div />');
this.percentsWrapper
.addClass('pcc-percents-wrapper')
.appendTo(this.percents);
this.percentsContent = $('<span />');
this.percentsContent
.text(this.settings.percent)
.appendTo(this.percentsWrapper);
// Append everything to the element
this.progress.appendTo(this.element);
this.percents.appendTo(this.element);
},
update: function(p) {
var percent = p ? p : this.settings.percent,
deg = 360 * percent / 100;
if (percent > 50) {
this.element.addClass('gt-50');
} else {
this.element.removeClass('gt-50');
}
this.progressFill.css('transform', 'rotate('+ deg +'deg)');
this.percentsContent.html(percent + '%');
}
}
jQuery.fn.percentageGraph = function() {
return new PercentageGraph(this);
}
})(jQuery);
(function($) {
$(document).ready(function() {
var progress = $('div#project_progress').percentageGraph();
// Handle it
$('.update-button').on('click', function() {
var percent = $(this).data('percent');
// Update it
progress.update(percent);
});
});
})(jQuery);

Javascript repeating function

recently I've tried to Design a slider Using Javascript and HTML . Here is what I have in HTML :
each slide is a division
<div id="sliderHolder">
<div id="slide1">Content For Slider1 </div>
<div id="slide2">Content For Slider2 </div>
<div id="slide3">Content For Slider3 </div>
</div>
And Here Is JS scripts :
function show_slider(){
document.getElementById('slide1').style.display="none";
document.getElementById('slide2').style.display="block";
document.getElementById('slide3').style.display="none";
}
function show_slider2(){
document.getElementById('slide1').style.display="none";
document.getElementById('slide2').style.display="none";
document.getElementById('slide3').style.display="block";
}
function show_slider3(){
document.getElementById('slide1').style.display="block";
document.getElementById('slide2').style.display="none";
document.getElementById('slide3').style.display="none";
}
window.onload = function() {
setTimeout(show_slider, 8000);
setTimeout(show_slider2, 16000);
setTimeout(show_slider3, 24000);
}
I'm New to JavaScript . This Works for 1 round of 24 seconds and shows each slide for 8 second and in the end shows the first slide . But what I'm looking for is to repeat the whole thing again after round finishes so the slider will continue forever .
Can You Please Help Me Out ??!
MORE To Say :
I'm not sure if I can write window.onload = function() inside another function . but I did something Like below After function show_slider3() :
function repeat() {
window.onload = function() {
setTimeout(show_slider, 8000);
setTimeout(show_slider2, 16000);
setTimeout(show_slider3, 24000);
}
}
and I added setTimeout(repeat, 25000); to window.onload = function() but it did not help me out .
Special Thanks ;
You can call the function on load, then run the function again in an interval.
window.onload = loop();
function loop() {
setTimeout(show_slider, 8000);
setTimeout(show_slider2, 16000);
setTimeout(show_slider3, 24000);
setTimeout(loop, 24000);
}
You should use the function window.setInterval to queue up a function which will run every eight seconds, eg.
var activeSlider = 0;
var sliders = [ "slide1", "slide2", "slide3" ];
function showNextSlider() {
document.getElementById('slide1').style.display="none";
document.getElementById('slide2').style.display="none";
document.getElementById('slide3').style.display="none";
var activeSliderName = sliders[ ++activeSlider % sliders.length ];
document.getElementById(activeSliderName).style.display="block";
}
window.setInterval( showNextSlider, 8000 );
Here is simple code with no requirement of function for each div, just added class "slide" to each div
<div id="sliderHolder">
<div id="slider_1" class="slide">Content For Slider1 </div>
<div id="slider_2" class="slide" style="display:none;">Content For Slider2 </div>
<div id="slider_3" class="slide" style="display:none;">Content For Slider3 </div>
</div>
And here is javascript code( no jquery)
var s=1;// start div
function show_slider() {
var cusid_ele = document.getElementsByClassName('slide');//getting all div by class name
console.log(s);
for (var i = 0; i < cusid_ele.length; ++i) {
var item = cusid_ele[i].style.display="none";// hiding all div of class "slide"
}
s++;
if( s>3 )// if reach at last div, set it to first again
s = 1;
document.getElementById('slider_'+s).style.display="block";//showing next div
}
window.setInterval(show_slider, 1000);
here is jsfiddle demo

Load blocking jQuery animate

I have built a gallery viewer with a preload function.
The preload function is as follows:
$.preloadFullImages = function() {
// Create array of images
var set = [];
$('.slide-item img').each(function() {
var img = $(this).data('src');
var id = $(this).parent().attr('id');
$(this).remove();
set.push([img,id]);
});
// Set current image
var current = 0;
var iterate = function() {
var current_src = set[current][0];
var current_id = set[current][1];
var temp = '<img src="'+current_src+'" />';
var target = '#'+current_id;
var targetImg = '#'+current_id+' img';
// Load 'temp' image
$(temp).bind('load', function() {
// Show image
$(target).append(temp);
$(targetImg).show();
$(this).remove();
});
if ( ++current < set.length ) iterate();
};
iterate();
};
On load of the page, images are loaded sequentially.
The problem is until all the images are loaded, the animation between images (prev and next arrows) is stunted and doesn't work correctly. I want the gallery viewer to transition smoothly between slides (images) even if not all images are loaded.
You can see a live demo here: http://www.davidclapp.net/portfolio
The issue is especially apparent on the iPhone (safari).
Is there a way to ensure the animation is smooth even whilst images are still loading?
Edit: I am using this plugin for CSS3 transitions - http://ricostacruz.com/jquery.transit/
$.preloadFullImages = function(callback) {
...
if ( ++current < set.length ) iterate();
else if(callback) callback(); //check if callback exists, then call it.
};
iterate();
};
These two lines being the important part.
$.preloadFullImages = function(callback) {
if ( ++current < set.length ) iterate();
else callback();
make a function to call the beginning of your animation, pass it to "preloadFullImages"

jQuery hover images carousel timeout overlaps

I'm building a webpage which shows products. When hovering over the product image, a slideshow-like event should start. You'll see photo's of the product in several states.
I've coded this with jQuery and I'm facing a kinda annoying bug.
When you hover over several products very fast and then leave your mouse on one product, it will slide through the images very fast.
The HTML structure looks like this:
<div class="products">
<div class="productContainer" data-product-id="1">
<img src="http://detestdivisie.nl/upload/images/hover-tests/inside/bmw-inside.jpg" class="mainProductImage" />
<div class="hoverImages">
<img src="" data-lazy-src="http://detestdivisie.nl/upload/images/hover-tests/inside/bmw-inside-1.jpg" />
<img src="" data-lazy-src="http://detestdivisie.nl/upload/images/hover-tests/inside/bmw-inside-2.jpg" />
<img src="" data-lazy-src="http://detestdivisie.nl/upload/images/hover-tests/inside/bmw-inside-3.jpg" />
<img src="" data-lazy-src="http://detestdivisie.nl/upload/images/hover-tests/inside/bmw-inside-4.jpg" />
<img src="" data-lazy-src="http://detestdivisie.nl/upload/images/hover-tests/inside/bmw-inside-5.jpg" />
</div>
</div>
<div class="productContainer" data-product-id="1">
<img src="http://detestdivisie.nl/upload/images/hover-tests/outside/bmw-outside.jpg" class="mainProductImage" />
<div class="hoverImages">
<img src="" data-lazy-src="http://detestdivisie.nl/upload/images/hover-tests/outside/bmw-outside-1.jpg" />
<img src="" data-lazy-src="http://detestdivisie.nl/upload/images/hover-tests/outside/bmw-outside-2.jpg" />
<img src="" data-lazy-src="http://detestdivisie.nl/upload/images/hover-tests/outside/bmw-outside-3.jpg" />
<img src="" data-lazy-src="http://detestdivisie.nl/upload/images/hover-tests/outside/bmw-outside-4.jpg" />
<img src="" data-lazy-src="http://detestdivisie.nl/upload/images/hover-tests/outside/bmw-outside-5.jpg" />
</div>
</div>
</div>
The Javscript class that is responsible for handling the events looks like this:
CategoryProductImages = function () {
this.className = 'CategoryProductImages';
this.version = '0.1.0';
this.mouseOver = false;
this.currentElement = null;
this.currentCategoryId = 0;
this.currentImageList = [];
this.currentImageKey = 0;
/**
* CategoryProductImages.init()
*
* Initializes the class that is reponsible for handling the
* mouse over and outs for the products.
*
* This method will call the createObserver method.
*/
this.init = function () {
console.log('Called ' + this.className + '.init()');
this.createObservers();
};
/**
* CategoryProductImages.createObservers()
*
* Will handle the mouse over and out events.
*/
this.createObservers = function () {
console.log('Called ' + this.className + '.createObservers()');
var thisObj = this;
jQuery('.productContainer').hover(
/** Called when mouse of the user moves over the element. **/
function () {
console.log('Mouse over .productContainer');
thisObj.mouseOver = true;
thisObj.currentElement = jQuery(this);
thisObj.currentCategoryId = thisObj.currentElement.data('category-id');
console.log('Lets\'s work for category id ' + thisObj.currentCategoryId);
thisObj.currentElement.find('.hoverImages img').each(function() {
thisObj.currentImageList.push(jQuery(this).data('lazy-src'));
});
thisObj.iterate();
},
/** Called immediatly after the mouse of the user leaves the element **/
function () {
console.log('Mouse out .productContainer');
thisObj.currentElement = null;
thisObj.mouseOver = false;
thisObj.currentImageList = new Array();
thisObj.currentImageKey = 0
}
);
};
this.iterate = function () {
console.log('Called ' + this.className + '.iterate()');
if (this.mouseOver && this.currentImageList.length > 0) {
console.log('Will now start the iteration process');
this.currentElement.find('img.mainProductImage').prop('src', this.currentImageList[0]);
thisObj = this;
setTimeout(function () {
console.log('First image shown, will now show next image.');
thisObj.nextImage(thisObj.currentCategoryId);
}, 3000)
} else {
console.log('Won\'t iterate, because the mouse of the user has left the element, of there are no images to show.');
}
};
this.nextImage = function (currentCategoryId) {
console.log('Called ' + this.className + '.nextImage()');
if (this.mouseOver && this.currentImageList.length > 0 && currentCategoryId == this.currentCategoryId) {
console.log('MouseOver still active, and images are found, show next image.');
this.currentImageKey += 1;
if (typeof this.currentImageList[this.currentImageKey] == 'undefined') {
console.log('OH NO! We\'ve reached the end of the list. Letst start all over again.');
this.currentImageKey = 0;
}
this.currentElement.find('img.mainProductImage').prop('src', this.currentImageList[this.currentImageKey]);
thisObj = this;
setTimeout(function () {
console.log('Okay, we\'ve waited for three seconds, NEXT! :)');
thisObj.nextImage(currentCategoryId)
}, 3000);
} else {
console.log('Iteration for ' + currentCategoryId + ' stopped');
console.log('Mouse over: ');
console.log(this.mouseOver);
console.log('Image list length: ');
console.log(this.currentImageList.length);
console.log('nextImage category id: ');
console.log(currentCategoryId);
console.log('Current category id:');
console.log(this.currentCategoryId);
console.log('#########################');
}
}
};
var categoryProductImagesObject = new CategoryProductImages();
categoryProductImagesObject.init();
The make it all more clear I've created a CodePen example. Please mouse over product 1 and product 2 very fast and then leave your mouse on product 1. You'll see it will loop through the product images way to fast.
http://codepen.io/wdivo/pen/lamsq
The time it should take before and image is replaced by another one is 3 seconds.
I am overlooking something, because obviously several setTimeouts are working near eachother, while there should only be 1 active setTimeout.
What should I do to make sure only 1 "active" setTimeout is running?
Simply said, I'd want to stop all the previous setTimeouts if a new one gets activated.
I'm now looking into clearInterval, but can't think of a way to implement it...

jQuery slider - last to first transition

I created this slider (didn't want to use plugins):
function slider(sel, intr, i) {
var _slider = this;
this.ind = i;
this.selector = sel;
this.slide = [];
this.slide_active = 0;
this.amount;
this.selector.children().each(function (i) {
_slider.slide[i] = $(this);
$(this).hide();
})
this.run();
}
slider.prototype.run = function () {
var _s = this;
this.slide[this.slide_active].show();
setTimeout(function () {
_s.slide[_s.slide_active].hide()
_s.slide_active++;
_s.run();
}, interval);
}
var slides = [];
var interval = 1000
$('.slider').each(function (i) {
slides[i] = new slider($(this), interval, i);
})
The problem I have is that I don´t know how to get it after the last slide(image), it goes back to the first slide again. Right now, it just .hide and .show till the end and if there is no image it just doesn´t start again.
Can someone help me out with a code suggestion to make it take the .length of the slider(the number of images on it) and if it is the last slide(image), then goes back to the first slide(image)... like a cycle.
Edit: Slider markup
<div class="small_box top_right slider">
<img class="fittobox" src="img/home10.jpg" alt="home10" width="854" height="592">
<img class="fittobox" src="img/home3.jpg" alt="home3" width="435" height="392">
<img class="fittobox" src="img/home4.jpg" alt="home4" width="435" height="392">
</div>
Created a fixed version for you here.
The easiest way to do this is to run a simple maths operation where you currently have
_s.slide_active++;
Instead, I get _s.slide_active, add 1, then run that through modulus (%) to the total length — which gives the remainder:
_s.slide_active = (_s.slide_active + 1) % _s.slide.length;
Take a look at this Fiddle link, this will help you create the slider in a cyclic way.If the slider reaches the last image it will start again from the first image.
var index = $selector.index();
if (index == (length - 1)) {
$('img').first().removeClass('invisible').addClass('visible');
}
I hope this will help you more. All the best.
You need to get to 0 after length-1.
One simple way to do that is to work modulo length:
_s.slide_active++;
_s.slide_active %= length;
not tested but hope helpful :
function slider(sel, intr , i){
...
this.count = this.selector.children().length;
this.run();
}
slider.prototype.run = function(){
var _s = this;
this.slide[this.slide_active].show();
setTimeout(function(){
_s.slide[_s.slide_active].hide()
if(_s.slide_active == this.count)
_s.slide_active = 0;
else
_s.slide_active++;
_s.run();
}, interval);
}

Categories