Link to the project: click here
Fiddle link: click here
I have this slider that my client wanted to work, without any plugin.
The html involved is as follows:
The js/jQuery involved is as follows:
Following is the main part of js involved:
var newSliderWidth = $('#oCarol').width(); // container width is recalculated and updated
liW = newSliderWidth; // new li width
liFW = (liW * $slider.find('li').length); // new width is calculated for the container
$('.panel-inner li').css('width', liW); // new width is assigned to the li(s)
$slider.width(liFW); // new width is assigned to the container
$('.button a').on('click', function (e) { // this determines the left and right buttons' functionality
e.preventDefault(); // prevent the default
if (!animating) {
var left = Math.abs(parseInt($slider.css('left'))); // find the current slider position
// 'side' is the amount of distance in pixels that the slider needs to move whenever a left or right arrow is pressed, respectively
var side = ($(this).data('direction') == 'right') ? (((left + (liW * iXS)) >= liFW) ? 0 : -(left + liW)) : ((left > 0) ? -(left - liW) : -(liFW - (liW * iXS)));
rotate(side);
console.log('Current position is: '+side);
}
});
// whenever a screen resize happens, the slider moves to the first slide
$('.panel-inner').animate({
left: 0
});
At the moment, whenever the screen resize happens, I have to reset the slider to first slide or else the current slide position gets messed up and half of it is shown and half from the next slide gets displayed as well, at the same time.
What I need, is, to somehow display the current slide correctly so that I don't have to reset the slider position to "left: 0px"
Here is an example, this happens when I comment the code where I reset '.panel-inner' to 'left: 0':
2 Answers
First, you should move the code that binds the click-handlers for the buttons so it is outside of the window resize-handler. You are rebinding those click-handlers over and over as the windows gets resized.
Second, I think your code is unnecessarily complicated. I think it is easier to keep track of the index of the currently displayed panel and have a function that slides to a panel by its index.
Note that I am using the "margin-left" css property to do the sliding, rather than "left". That's the way I've seen sliding like this implemented before, but I'm not saying one way is better than the other.
Here is what it could look like:
$(function() {
var animating = false,
$container = $('.panel'),
$slider = $('.panel-inner'),
$panels = $slider.children(),
currentPanelIndex = 0,
panelWidth,
resizeTimerId = null;
function slideTo(panelIndex) {
animating = true;
$slider.stop(true, true).animate({
"margin-left": -(panelIndex * panelWidth)
}, 1000, function () {
animating = false;
currentPanelIndex = panelIndex;
});
}
function resizeSlider() {
panelWidth = $container.width();
$panels.css('width', panelWidth);
$slider.width(panelWidth * $panels.length);
$slider.css({ "margin-left": -(currentPanelIndex * panelWidth) });
}
$(window).on('resize', function() {
clearTimeout(resizeTimerId);
resizeTimerId = setTimeout(function () {
resizeSlider();
}, 100);
});
$('.button a').on('click', function(e) {
e.preventDefault();
if (!animating) {
var direction = $(this).data('direction');
var panelIndex = currentPanelIndex + ((direction == 'right') ? 1 : -1);
if (panelIndex < 0) {
panelIndex = $panels.length - 1;
} else if (panelIndex > ($panels.length - 1)) {
panelIndex = 0;
}
slideTo(panelIndex);
}
});
resizeSlider();
});
Note: It could call slideTo(currentPanelIndex) when the window is resized to make the adjustment, but then it would be animated and if the user keeps resizing, the animations will queue up.
Looks like this will get the expected result :
$(function () {
var conH = $('#knowledge .container').width();
$('.panel-inner li').css({width: conH});
var animating = false,
iXS = 1,
$slider = $('.panel-inner'),
liW = $slider.find('li:first').width(),
liFW = (liW*$slider.find('li').length),
first = true,
index;
$slider.width(liFW);
$(window).on('resize', function () {
clearTimeout(timeout);
if (first) {
first = false;
var positioned = parseInt($slider.css('left'));
index = Math.round(positioned/liW);
}
var timeout = setTimeout(function () {
first = true;
var newSliderWidth = $('#oCarol').width();
liW = newSliderWidth;
liFW = (liW * $slider.find('li').length);
$('.panel-inner li').css('width', liW);
$slider.width(liFW);
$('.button a').off('click').on('click', function(e) {
e.preventDefault();
if (!animating) {
var left = Math.abs(parseInt($slider.css('left')));
var side = ($(this).data('direction') == 'right') ? (((left + (liW * iXS)) >= liFW) ? 0 : -(left + liW)) : ((left > 0) ? -(left - liW) : -(liFW - (liW * iXS)));
rotate(side);
}
});
$('.panel-inner').css({left: index*liW});
}, 200);
});
$(window).trigger('resize');
var rotate = function(leftY) {
if (!animating) {
animating = true;
$slider.stop(true, true).animate({left: leftY}, 1000, function () {
animating = false;
});
}
}
});
I've added a check on the first resize and then keep clearing the timeout until the user has stopped resizing. Then 200ms after that, it recalculates and repositions.