Navigate to any step in a Bootstrap step-wizard - javascript

Here is my JSFiddle : DEMO
On click of "Save & Continue", the step navigates to the next step of the wizard.
How do I navigate to any step on click of a specific step? (instead of the step-by-step sequence that already exists)
$('.f1 .btn-next').on('click', function() {
var parent_fieldset = $(this).parents('fieldset');
var next_step = true;
// navigation steps / progress steps
var current_active_step = $(this).parents('.f1').find('.f1-step.active');
var progress_line = $(this).parents('.f1').find('.f1-progress-line');
// fields validation
parent_fieldset.find('input[type="text"], input[type="password"], textarea').each(function() {
if( $(this).val() == "" ) {
$(this).addClass('input-error');
next_step = true;
}
else {
$(this).removeClass('input-error');
}
});

Edit:- Buttons added to jump to specific steps. Fiddle
EDIT:- I modified your fiddle check this
Try this JsFiddle demo
I modified the html slightly to connect steps div and corresponding fieldset by adding a data-step parameter to both. After the modification the below function will allow you to jump between steps by clicking on the icon.
$(this).parents('.f1').find('.f1-progress-line');
fieldsetToActivate = $(this).data('step');
let direction;
if (current_active_step.data('step') > fieldsetToActivate) {
direction = 'left';
} else {
direction = 'right';
}
$("form.f1 fieldset").hide();
current_active_step.removeClass('active');
// bar_progress(progress_line, direction);
// ************* //
var number_of_steps = progress_line.data('number-of-steps');
var now_value = progress_line.data('now-value');
var new_value = 0;
if (direction == 'right') {
new_value = fieldsetToActivate * (100 / number_of_steps);
} else if (direction == 'left') {
new_value = fieldsetToActivate * (100 / number_of_steps);
}
console.log('now:' + now_value + '- new: ' + new_value);
progress_line.attr('style', 'width: ' + new_value + '%;').data('now-value', new_value);
// ****************** //
$('.f1').find(`fieldset[data-step='${fieldsetToActivate}']`).fadeIn('slow');
// change icons
$('.f1-step').removeClass('activated');
$(this).addClass('active');
for (let j = 0; j < fieldsetToActivate; j++) {
$('.f1').find(`.f1-step[data-step='${j}']`).addClass('activated');
}
});
This is not the best solution, but this will get your job done

Related

horizontal timeline fixed distance and centered on mobile devices

I am trying to reach a horizontal timeline like this:
https://codepen.io/ritz078/pen/LGRWjE
My problem is, that I've got no real dates (DD/MM/YYYY) but only years like 1998-2002 or just 2009. So there is a problem, I am struggling to fix, which ends up like this:
So my aims are:
Set a fixed distance between elements
Make it work just with years
When on a device less than 768px wide ensure a single element is displayed and it appears in the center
This is my solution for 3., but the other things, I couldnt solute:
if ($(window).width() < 768 {
eventsMinDistance = $('.cd-horizontal-timeline .events-wrapper').width(/2;)
}
(timelines.length > 0) && initTimeline(timelines);
$(window).resize(function(){
if ($(window).width() < 768 {
eventsMinDistance = $('.cd-horizontal-timeline .events-wrapper').width(/2;)
} else{
eventsMinDistance = 155;
}
}
Do you guys know how do adjust it, as I am struggling since hours without any success. Thank you very much for your help!
the first part of your code works fine, but it was faulty on the syntax, I fixed it and use it and also add a couple of changes to acomplished the desired fixed width amount between each date.
Actually it was pretty easy, when you debug and you know exactly what the developer wants to do.
This is the code I wrote:
jQuery(document).ready(function($){
var timelines = $('.cd-horizontal-timeline'),
eventsRelativeDistance = false;
if ($(window).width() < 768) {
eventsMinDistance = Number($('.cd-horizontal-timeline .events-wrapper').width())/2;
}else{
var eventsMinDistance = 100;
}
(timelines.length > 0) && initTimeline(timelines);
$(window).resize( function(){
if ($(window).width() < 768) {
eventsMinDistance = Number($('.cd-horizontal-timeline .events-wrapper').width())/2;
} else{
eventsMinDistance = 100;
}
});
function initTimeline(timelines) {
timelines.each(function(){
var timeline = $(this),
timelineComponents = {};
//cache timeline components
timelineComponents['timelineWrapper'] = timeline.find('.events-wrapper');
timelineComponents['eventsWrapper'] = timelineComponents['timelineWrapper'].children('.events');
timelineComponents['fillingLine'] = timelineComponents['eventsWrapper'].children('.filling-line');
timelineComponents['timelineEvents'] = timelineComponents['eventsWrapper'].find('a');
timelineComponents['timelineDates'] = parseDate(timelineComponents['timelineEvents']);
timelineComponents['eventsMinLapse'] = minLapse(timelineComponents['timelineDates']);
timelineComponents['timelineNavigation'] = timeline.find('.cd-timeline-navigation');
timelineComponents['eventsContent'] = timeline.children('.events-content');
if(!eventsRelativeDistance){
// Set up space to store the distance in pixels.
timelineComponents['distanceInPx'] = [];
}
//assign a left postion to the single events along the timeline
setDatePosition(timelineComponents, eventsMinDistance, eventsRelativeDistance);
//assign a width to the timeline
var timelineTotWidth = setTimelineWidth(timelineComponents, eventsMinDistance, eventsRelativeDistance);
//the timeline has been initialize - show it
timeline.addClass('loaded');
//detect click on the next arrow
timelineComponents['timelineNavigation'].on('click', '.next', function(event){
event.preventDefault();
updateSlide(timelineComponents, timelineTotWidth, 'next');
});
//detect click on the prev arrow
timelineComponents['timelineNavigation'].on('click', '.prev', function(event){
event.preventDefault();
updateSlide(timelineComponents, timelineTotWidth, 'prev');
});
//detect click on the a single gallery - show new gallery content
timelineComponents['eventsWrapper'].on('click', 'a', function(event){
event.preventDefault();
timelineComponents['timelineEvents'].removeClass('selected');
$(this).addClass('selected');
updateOlderEvents($(this));
updateFilling($(this), timelineComponents['fillingLine'], timelineTotWidth);
updateVisibleContent($(this), timelineComponents['eventsContent']);
});
//on swipe, show next/prev gallery content
timelineComponents['eventsContent'].on('swipeleft', function(){
var mq = checkMQ();
( mq == 'mobile' ) && showNewContent(timelineComponents, timelineTotWidth, 'next');
});
timelineComponents['eventsContent'].on('swiperight', function(){
var mq = checkMQ();
( mq == 'mobile' ) && showNewContent(timelineComponents, timelineTotWidth, 'prev');
});
//keyboard navigation
$(document).keyup(function(event){
if(event.which=='37' && elementInViewport(timeline.get(0)) ) {
showNewContent(timelineComponents, timelineTotWidth, 'prev');
} else if( event.which=='39' && elementInViewport(timeline.get(0))) {
showNewContent(timelineComponents, timelineTotWidth, 'next');
}
});
});
}
function updateSlide(timelineComponents, timelineTotWidth, string) {
//retrieve translateX value of timelineComponents['eventsWrapper']
var translateValue = getTranslateValue(timelineComponents['eventsWrapper']),
wrapperWidth = Number(timelineComponents['timelineWrapper'].css('width').replace('px', ''));
//translate the timeline to the left('next')/right('prev')
(string == 'next')
? translateTimeline(timelineComponents, translateValue - wrapperWidth + eventsMinDistance, wrapperWidth - timelineTotWidth)
: translateTimeline(timelineComponents, translateValue + wrapperWidth - eventsMinDistance);
}
function showNewContent(timelineComponents, timelineTotWidth, string) {
//go from one gallery to the next/previous one
var visibleContent = timelineComponents['eventsContent'].find('.selected'),
newContent = ( string == 'next' ) ? visibleContent.next() : visibleContent.prev();
if ( newContent.length > 0 ) { //if there's a next/prev gallery - show it
var selectedDate = timelineComponents['eventsWrapper'].find('.selected'),
newEvent = ( string == 'next' ) ? selectedDate.parent('li').next('li').children('a') : selectedDate.parent('li').prev('li').children('a');
updateFilling(newEvent, timelineComponents['fillingLine'], timelineTotWidth);
updateVisibleContent(newEvent, timelineComponents['eventsContent']);
newEvent.addClass('selected');
selectedDate.removeClass('selected');
updateOlderEvents(newEvent);
updateTimelinePosition(string, newEvent, timelineComponents);
}
}
function updateTimelinePosition(string, event, timelineComponents) {
//translate timeline to the left/right according to the position of the selected gallery
var eventStyle = window.getComputedStyle(event.get(0), null),
eventLeft = Number(eventStyle.getPropertyValue("left").replace('px', '')),
timelineWidth = Number(timelineComponents['timelineWrapper'].css('width').replace('px', '')),
timelineTotWidth = Number(timelineComponents['eventsWrapper'].css('width').replace('px', ''));
var timelineTranslate = getTranslateValue(timelineComponents['eventsWrapper']);
if( (string == 'next' && eventLeft > timelineWidth - timelineTranslate) || (string == 'prev' && eventLeft < - timelineTranslate) ) {
translateTimeline(timelineComponents, - eventLeft + timelineWidth/2, timelineWidth - timelineTotWidth);
}
}
function translateTimeline(timelineComponents, value, totWidth) {
var eventsWrapper = timelineComponents['eventsWrapper'].get(0);
value = (value > 0) ? 0 : value; //only negative translate value
value = ( !(typeof totWidth === 'undefined') && value < totWidth ) ? totWidth : value; //do not translate more than timeline width
setTransformValue(eventsWrapper, 'translateX', value+'px');
//update navigation arrows visibility
(value == 0 ) ? timelineComponents['timelineNavigation'].find('.prev').addClass('inactive') : timelineComponents['timelineNavigation'].find('.prev').removeClass('inactive');
(value == totWidth ) ? timelineComponents['timelineNavigation'].find('.next').addClass('inactive') : timelineComponents['timelineNavigation'].find('.next').removeClass('inactive');
}
function updateFilling(selectedEvent, filling, totWidth) {
//change .filling-line length according to the selected gallery
var eventStyle = window.getComputedStyle(selectedEvent.get(0), null),
eventLeft = eventStyle.getPropertyValue("left"),
eventWidth = eventStyle.getPropertyValue("width");
eventLeft = Number(eventLeft.replace('px', '')) + Number(eventWidth.replace('px', ''))/2;
var scaleValue = eventLeft/totWidth;
setTransformValue(filling.get(0), 'scaleX', scaleValue);
}
function setDatePosition(timelineComponents, min, relativeDistance) {
var distance,
distanceNorm = 0,
distancesInPx =[];
for (i = 0; i < timelineComponents['timelineDates'].length; i++) {
if (relativeDistance){
distance = daydiff(timelineComponents['timelineDates'][0], timelineComponents['timelineDates'][i]);
distanceNorm = Math.round(distance/timelineComponents['eventsMinLapse']) + 2;
}else{
distance = 5;
distanceNorm = Math.round(distance/timelineComponents['eventsMinLapse']) + 2 + distanceNorm;
// Save am array of sizes to track the distance in pixels from the left.
timelineComponents['distanceInPx'].push(distanceNorm*min);
}
timelineComponents['timelineEvents'].eq(i).css('left', distanceNorm*min+'px');
}
}
function setTimelineWidth(timelineComponents, width, relativeDistance) {
var timeSpan = 0, timeSpanNorm, totalWidth;
if(relativeDistance){
// If relative Time Distance daydiff caclulates the first date and the last one.
timeSpan = daydiff(timelineComponents['timelineDates'][0], timelineComponents['timelineDates'][timelineComponents['timelineDates'].length-1]);
timeSpanNorm = timeSpan/timelineComponents['eventsMinLapse'];
timeSpanNorm = Math.round(timeSpanNorm) + 4;
totalWidth = timeSpanNorm*width;
}else{
// However if no relative Distance we obtain the amount of distance in pixels from the last position of the array which is the farthest element on the array.
totalWidth = timelineComponents['distanceInPx'][timelineComponents['distanceInPx'].length-1];
}
timelineComponents['eventsWrapper'].css('width', totalWidth+'px');
updateFilling(timelineComponents['eventsWrapper'].find('a.selected'), timelineComponents['fillingLine'], totalWidth);
updateTimelinePosition('next', timelineComponents['eventsWrapper'].find('a.selected'), timelineComponents);
return totalWidth;
}
function updateVisibleContent(event, eventsContent) {
var eventDate = event.data('date'),
visibleContent = eventsContent.find('.selected'),
selectedContent = eventsContent.find('[data-date="'+ eventDate +'"]'),
selectedContentHeight = selectedContent.height();
if (selectedContent.index() > visibleContent.index()) {
var classEnetering = 'selected enter-right',
classLeaving = 'leave-left';
} else {
var classEnetering = 'selected enter-left',
classLeaving = 'leave-right';
}
selectedContent.attr('class', classEnetering);
visibleContent.attr('class', classLeaving).one('webkitAnimationEnd oanimationend msAnimationEnd animationend', function(){
visibleContent.removeClass('leave-right leave-left');
selectedContent.removeClass('enter-left enter-right');
});
eventsContent.css('height', selectedContentHeight+'px');
}
function updateOlderEvents(event) {
event.parent('li').prevAll('li').children('a').addClass('older-gallery').end().end().nextAll('li').children('a').removeClass('older-gallery');
}
function getTranslateValue(timeline) {
var timelineStyle = window.getComputedStyle(timeline.get(0), null),
timelineTranslate = timelineStyle.getPropertyValue("-webkit-transform") ||
timelineStyle.getPropertyValue("-moz-transform") ||
timelineStyle.getPropertyValue("-ms-transform") ||
timelineStyle.getPropertyValue("-o-transform") ||
timelineStyle.getPropertyValue("transform");
if( timelineTranslate.indexOf('(') >=0 ) {
var timelineTranslate = timelineTranslate.split('(')[1];
timelineTranslate = timelineTranslate.split(')')[0];
timelineTranslate = timelineTranslate.split(',');
var translateValue = timelineTranslate[4];
} else {
var translateValue = 0;
}
return Number(translateValue);
}
function setTransformValue(element, property, value) {
element.style["-webkit-transform"] = property+"("+value+")";
element.style["-moz-transform"] = property+"("+value+")";
element.style["-ms-transform"] = property+"("+value+")";
element.style["-o-transform"] = property+"("+value+")";
element.style["transform"] = property+"("+value+")";
}
//based on http://stackoverflow.com/questions/542938/how-do-i-get-the-number-of-days-between-two-dates-in-javascript
function parseDate(events) {
var dateArrays = [];
events.each(function(){
var singleDate = $(this),
dateComp = singleDate.data('date').split('T');
if( dateComp.length > 1 ) { //both DD/MM/YEAR and time are provided
var dayComp = dateComp[0].split('/'),
timeComp = dateComp[1].split(':');
} else if( dateComp[0].indexOf(':') >=0 ) { //only time is provide
var dayComp = ["2000", "0", "0"],
timeComp = dateComp[0].split(':');
} else { //only DD/MM/YEAR
var dayComp = dateComp[0].split('/'),
timeComp = ["0", "0"];
}
var newDate = new Date(dayComp[2], dayComp[1]-1, dayComp[0], timeComp[0], timeComp[1]);
dateArrays.push(newDate);
});
return dateArrays;
}
function daydiff(first, second) {
return Math.round((second-first));
}
function minLapse(dates) {
//determine the minimum distance among events
var dateDistances = [];
for (i = 1; i < dates.length; i++) {
var distance = daydiff(dates[i-1], dates[i]);
dateDistances.push(distance);
}
return Math.min.apply(null, dateDistances);
}
/*
How to tell if a DOM element is visible in the current viewport?
http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
*/
function elementInViewport(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top < (window.pageYOffset + window.innerHeight) &&
left < (window.pageXOffset + window.innerWidth) &&
(top + height) > window.pageYOffset &&
(left + width) > window.pageXOffset
);
}
function checkMQ() {
//check if mobile or desktop device
return window.getComputedStyle(document.querySelector('.cd-horizontal-timeline'), '::before').getPropertyValue('content').replace(/'/g, "").replace(/"/g, "");
}
});
Did you ever get this to work?? Have come across the same problem. If i change the default distance from 60 to 1 the gap between is not enough and the whole timeline breaks. The calculations for the distance as described in the article is as follows
First of all, in the main.js file, we set a minimum distance between two consecutive dates, using the eventsMinDistance variable; in our case, we set eventsMinDistance = 60 (so the minimum distance will be 60px). Then we evaluate all the differences between a date and the following one; to do that we use the data-date attribute added to each date. The minimum difference is then used as a reference to evaluate the distances between two consecutive dates.
For example, let's suppose the minimum found difference is 5 days; that means that the distance, along the timeline, between two dates separated by a lapse of 5days will be 60px, while the one between two events separated by a lapse of 10 days will be 120px.
source:: www.codyhouse.org
From what i read the min distance is here:~
var timelines = $('.cd-horizontal-timeline'),
eventsMinDistance = 60;
(timelines.length > 0) && initTimeline(timelines);
This creates a variable called timelines and sets it to the class .cd-hor... and sets the min distance to 60px. changing this to 1 breaks the application as the distance between the times are too small.
function setDatePosition(timelineComponents, min) {
for (i = 0; i < timelineComponents['timelineDates'].length; i++) {
var distance = daydiff(timelineComponents['timelineDates'][0], timelineComponents['timelineDates'][i]),
distanceNorm = Math.round(distance/timelineComponents['eventsMinLapse']) + 2;
timelineComponents['timelineEvents'].eq(i).css('left', distanceNorm*min+'px');
}
}
I might be wrong but here is the section calculating the distance and the last distanceNorm*min+'px'. min i believe is 60 and distance norm is the calculation of the 5 days etc. if you remove distance norm the app breaks so you cant just add min+'px' this is because you remove the original distance.
All distances are calculated from the first timeline. Thats why the app breaks. Need to find the code that tells which to calc from which is the
var distance = daydiff(timelineComponents['timelineDates'][0], timelineComponents['timelineDates'][i]),
distanceNorm = Math.round(distance/timelineComponents['eventsMinLapse']) + 2;
this sets distance as the first element of the index and then for each timelineDates within the loop [i].
I've been at it for days but have come to the conclusion the tutorial is good as is but it is not a library and should be used as reference to write your own from scratch which is what i am now doing.
If you did ever manage it though please update as so far i managed to manipulate the dates to get equal spacing but if you insert too many it breaks which is no good hence the rewrite!

jQuery: change class after conditional is met

I created this site where you have multiple sliders moving vertically using this example on stackoverflow > here < along with this fiddle.
The site when loaded has an overflow: hidden on the body and position fixed on my main content div(div class="content-fs row"). The idea is that when you first arrive on the page, you scroll through each slide and once you hit the last one, the position changes on the main content div(div class="content-fs row") from fixed to static and the overflow: hidden is removed from the body. I'm having trouble writing the conditional statement that says "if its the last slider, change the position." The jquery below is the code i'm using for the site along with the conditional statement that doesn't work.
Any pointers/advice would be greatly appreciated!
jquery:
function scrollLax(){
/*
initialize
*/
var scrollDown = false;
var scrollUp = false;
var scroll = 0;
var $view = $('#portfolio');
var t = 0;
var h = $view.height() - 250;
$view.find('.portfolio-sliders').each(function() {
var $moving = $(this);
// position the next moving correctly
if($moving.hasClass('from-bottom')) {
$moving.css('top', h); // subtract t so that a portion of the other slider is showing
}
// make sure moving is visible
$moving.css('z-index', 10);
});
var $moving = $view.find('.portfolio-sliders:first-child');
$moving.css('z-index', 10);
/*
event handlers
*/
var mousew = function(e) {
var d = 0;
if(!e) e = event;
if (e.wheelDelta) {
d = -e.wheelDelta/3;
} else if (e.detail) {
d = e.detail/120;
}
parallaxScroll(d);
}
if (window.addEventListener) {
window.addEventListener('DOMMouseScroll', mousew, false);
}
window.onmousewheel = document.onmousewheel = mousew;
/*
parallax loop display loop
*/
window.setInterval(function() {
if(scrollDown)
parallaxScroll(4);
else if(scrollUp)
parallaxScroll(-4);
}, 50);
function parallaxScroll(scroll) {
// current moving object
var ml = $moving.position().left;
var mt = $moving.position().top;
var mw = $moving.width();
var mh = $moving.height();
// calc velocity
var fromBottom = false;
var vLeft = 0;
var vTop = 0;
if($moving.hasClass('from-bottom')) {
vTop = -scroll;
fromBottom = true;
}
// calc new position
var newLeft = ml + vLeft;
var newTop = mt + vTop;
// check bounds
var finished = false;
if(fromBottom && (newTop < t || newTop > h)) {
finished = true;
newTop = (scroll > 0 ? t : t + h);
}
// set new position
$moving.css('left', newLeft);
$moving.css('top', newTop);
// if finished change moving object
if(finished) {
// get the next moving
if(scroll > 0) {
$moving = $moving.next('.portfolio-sliders');
if($moving.length == 0)
$moving = $view.find('.portfolio-sliders:last');
//this is where I am trying to add the if conditional statement.
if ('.portfolio-sliders:last')
$('.content-fs.row').css({'position': 'static'});
if('.portfolio-sliders:last' && (mt == 0))
$('html, body').removeClass('overflow');
} else {
$moving = $moving.prev('.portfolio-sliders');
if($moving.length == 0)
$moving = $view.find('.portfolio-sliders:first-child');
//reverse the logic and if last slide change position
if('.portfolio-sliders:first-child')
$('.content-fs.row').css({'position': 'fixed'});
}
}
// for debug
//$('#direction').text(scroll + "/" + t + " " + ml + "/" + mt + " " + finished + " " + $moving.text());
}
}
Your code as it is simply asks whether .portfolio-sliders:last exists. Seems you should be doing:
if ($moving == $('.portfolio-sliders:last') )
or something along those lines, instead checking whether the active slide is the last.

jQuery add row number as class on the divs on current row

I need to make jquery fill all the rows in a layout as the first row in the fiddle
not sure if I explained well enough but the fiddle should clear out what I want.
first five divs have width changed a bit to make sure the row is filled, but I can't make the rest of rows fill the container
basically I want to justify all the divs by increasing their widths
http://jsfiddle.net/SG9Vx/
so far I have this function, modified from here: jQuery Find number of items per row in floated li's:
var lisInRow = 0;
$('#posts div').each(function() {
if($(this).prev().length > 0) {
if($(this).position().top != $(this).prev().position().top) return false;
lisInRow++;
$(this).addClass("row1");
}
else {
lisInRow++;
$(this).addClass("row1");
}
});
var itemNumber = $(".row1").length
var widthRow = 0;
$('.row1').each(function() {
widthRow += $(this).outerWidth( true );
});
var widthContainer = $("#posts").width();
var remaining = widthContainer - widthRow;
leftMargin = Math.floor(remaining / itemNumber);
$(".row1").each(function(){
var addedwidth = $(this).width() + leftMargin;
$(this).width(addedwidth);
});
What I do for the first row is calculate what's left of the container, divide it by number of items on the row, and add the result to the width of each item on the row.
If I understood what you're trying to do, I made some small changes to the code
var lisInRow = 0;
var lisInRow2 = 0;
var row = 0;
$('div div').each(function() {
if($(this).prev().length > 0) {
if($(this).position().top != $(this).prev().position().top) row++;
lisInRow++;
$(this).addClass("row"+row);
//console.log($(this).prev().length)
}
else {
lisInRow++;
$(this).addClass("row0");
}
});
for(var i=0;i<=row;i++){
var itemNumber = $(".row"+i).length
console.log(row);
var widthRow = 0;
$(".row"+i).each(function() {
widthRow += $(this).outerWidth( true );
});
var widthContainer = $("#posts").width();
var remaining = widthContainer - widthRow;
leftMargin = Math.floor(remaining / itemNumber);
$(".row"+i).each(function(){
var addedwidth = $(this).width() + leftMargin;
$(this).width(addedwidth);
$(this).find("img").width(addedwidth);
});
}
Here you have it:
http://jsfiddle.net/SG9Vx/3/
Here's a simplified version of what I think you're trying to achieve:
var lisInRow = 0;
$('div div').each(function() {
if($(this).prev().length > 0) {
if($(this).position().top != $(this).prev().position().top){
lisInRow++;
}
$(this).addClass("row" + lisInRow);
}
});
Fiddle: http://jsfiddle.net/568mP/

Jquery - making tabs animate synchronously

Here is the jsfiddle demo.
I am trying to animate the tabs in my carousel synchronously, i.e. they all should slide left/right together. However, as you will notice from the demo, sometimes they do, othertimes they don't.
Could someone please point out where I am going wrong? Im not just looking for the correct code but logic & explanation please.
Ive tried to comments the code as much as I can so that its easier to follow & pinpoint the problem. The line that has the 'animate' code has the comment: // ***** NOTE -- THIS IS THE LINE THATS ANIMATING THE TABS TO SCROLL RIGHT *****
Code:
var eLeftScrollButton = document.getElementById("t_l_nav");
var eRightScrollButton = document.getElementById("t_r_nav");
var eArrowForTabs = document.getElementById("arrow");
var iActiveNo = 0; //var. for storing the active tab. no.
var iTabSlideNo = 0;
var iTabWidth = 147; // a tab's width
var eTabsDiv = document.getElementById("tabs");
var iTabsCount = eTabsDiv.childNodes.length; //tabs count
var bClickable = true; // bool whether left & right buttons are clickable or not
var iButtonsPage = 1; // button page no.
var iStonesPage = 1; // stones page no.
var iRibbonsPage = 1; // ribbons page no.
var iLacesPage = 1; // laces page no.
var iPipingPage = 1; // laces page no.
displayTabNo_onstart();
/* ---------- displaying the current tab, hiding the other non-current tabs ---------- */
function displayTabNo_onstart()
{
for ( var i = 0; i < iTabsCount; i++)
{
if (i === iActiveNo)
{
eTabsDiv.children[i].style.color = "black";
eTabsDiv.children[i].style.fontWeight = "bold";
} else
{
eTabsDiv.children[i].style.opacity = "0.2";
eTabsDiv.children[i].style.fontWeight = "normal";
}
}
}
/* ---------- activate the button, ribbons etc based on what tab is active right now, & hide others ---------- */
function activateFeaturesContainer (direction)
{
var eFeaturesContainerDiv = document.getElementById("features");
eFeaturesContainerDiv.children[iActiveNo].style.display = "block";
(direction === "right") ? ((eFeaturesContainerDiv.children[iActiveNo - 1].style.display = "none") & (bClickable = true)) : ((eFeaturesContainerDiv.children[iActiveNo + 1].style.display = "none") & (bClickable = true));
}
/* ---------- called when the right button for tabs is pressed, calls the below two 'right' functions ---------- */
function pressRightButton ()
{
if (bClickable === true)
{
bClickable = false;
pressRightButtonEffect();
activateRightTab();
} else {
return;
}
}
/* ---------- called when the left button for tabs is pressed, calls the below two 'left' functions ---------- */
function pressLeftButton ()
{
if (bClickable === true)
{
bClickable = false;
pressLeftButtonEffect();
activateLeftTab();
} else {
return;
}
}
/* ---------- effect on right button when pressed ---------- */
function pressRightButtonEffect()
{
eRightScrollButton.style.top = "29px";
window.setTimeout(function()
{
var eStyle = window.getComputedStyle(eRightScrollButton);
var pBackgroundColorProperty = eStyle.backgroundColor; // getting the CSS backgroundColor
eRightScrollButton.style.top = "28px";
}, 150);
}
/* ---------- effect on left button when pressed ---------- */
function pressLeftButtonEffect()
{
eLeftScrollButton.style.top = "29px";
window.setTimeout(function()
{
var eStyle = window.getComputedStyle(eLeftScrollButton);
var pBackgroundColorProperty = eStyle.backgroundColor; // getting the CSS backgroundColor
eLeftScrollButton.style.top = "28px";
}, 150);
}
/* ---------- tabs indicator, tabs & other animations on right button when pressed ---------- */
function activateRightTab()
{
var direction = "right";
if (iActiveNo < iTabsCount - 1 && iActiveNo >= 0)
{
iActiveNo = iActiveNo + 1;
(iActiveNo > 0) ? eLeftScrollButton.childNodes[0].setAttribute("src", "Img/WA03_Container_LeftScrollButton_Active.png") : false; //reinstate leftScrollbutton to active
(iTabSlideNo < iTabsCount - 1) ? iTabSlideNo++ : iTabSlideNo;
// ***** NOTE -- THIS IS THE LINE THATS ANIMATING THE TABS TO SCROLL RIGHT *****
$(".c_tabs").animate ({"right": ("+=147px")}, 500, "swing", function()
{
$(eTabsDiv.childNodes[iActiveNo]).animate ({"opacity" : "1"}, 191,"linear");
$(eTabsDiv.childNodes[iActiveNo - 1]).animate ({"opacity" : "0.2"}, 191,"linear");
});
window.setTimeout (function ()
{
eTabsDiv.childNodes[iActiveNo].style.fontWeight = "bold";
eTabsDiv.childNodes[iActiveNo-1].style.fontWeight = "normal";
},500);
$(eArrowForTabs).animate ({"top" : "69px"}, 191, "linear", function()
{
window.setTimeout (function()
{ $(eArrowForTabs).animate ({"top" : "55px"}, 191, "linear"); }, 75);
});
(iTabSlideNo + 1 === iTabsCount) ? eRightScrollButton.childNodes[0].setAttribute ("src", "Img/WA02_Container_RightScrollButton_Passive.png"):false;
window.setTimeout (function() {activateFeaturesContainer(direction);}, 600);
} else {
bClickable = true;
} // close -> first if statement of this function
if (iActiveNo === iTabsCount - 1 && eRightScrollButton.childNodes[0].getAttribute("src") === "Img/WA02_Container_RightScrollButton_Passive.png") //springy effect on last tab
{
$(eTabsDiv.childNodes[iActiveNo]).animate({"right" : (((iTabSlideNo * iTabWidth) + 10) + "px")}, 100).animate({"right" : (((iTabSlideNo * iTabWidth) - 5) + "px")}, 45).animate({"right" : (((iTabSlideNo * iTabWidth) + 0) + "px")}, 10);
} // close -> springy effect if statement
} // close -> activateRightTab function
/* ---------- tabs indicator, tabs & other animations on left button when pressed ---------- */
function activateLeftTab()
{
var direction = "left";
if (iActiveNo <= iTabsCount -1 && iActiveNo > 0) //because length doesn't count 0 & we are substracting 1 below
{
iActiveNo = iActiveNo - 1;
(iActiveNo < iTabsCount - 1) ? eRightScrollButton.childNodes[0].setAttribute("src", "Img/WA01_Container_RightScrollButton_Active.png") : false; (iTabSlideNo > 0) ? iTabSlideNo-- : false;
$(".c_tabs").animate ({"right": ("-=147px")}, 500, "linear", function()
{
$(eTabsDiv.childNodes[iActiveNo]).animate ({"opacity" : "1"}, 250,"linear");
$(eTabsDiv.childNodes[iActiveNo + 1]).animate ({"opacity" : "0.2"}, 250,"linear");
});
window.setTimeout ( function ()
{
eTabsDiv.childNodes[iActiveNo].style.fontWeight = "bold";
eTabsDiv.childNodes[iActiveNo-1].style.fontWeight = "normal";
},500);
$(eArrowForTabs).animate ({"top" : "69px"}, 191, "linear", function()
{
window.setTimeout( function()
{ $(eArrowForTabs).animate ({"top" : "55px"}, 191, "linear"); }, 75);
});
(iTabSlideNo === 0) ? eLeftScrollButton.childNodes[0].setAttribute ("src", "Img/WA04_Container_LeftScrollButton_Passive.png") : false;
window.setTimeout( function() {activateFeaturesContainer(direction)}, 600);
} else { // close -> first if statement of this function
bClickable = true;
}
if (iActiveNo === 0 && eLeftScrollButton.childNodes[0].getAttribute("src") === "Img/WA04_Container_LeftScrollButton_Passive.png") //springy effect on last tab
{
$(eTabsDiv.childNodes[iActiveNo]).animate({"right" : (((iTabSlideNo * iTabWidth) - 10) + "px")}, 100).animate({"right" : (((iTabSlideNo * iTabWidth) + 5) + "px")}, 45).animate({"right" : (((iTabSlideNo * iTabWidth) + 0) + "px")}, 10);
} // close -> springy effect if statement
} // close -> activateRightTab function

Only swipeone is working with jGestures

I'm trying to implement touch evens with jGestures. swipeone works fine but anything else (swipeleft, swiperight etc) is not firing.
<div id="wrap" style="height:500px; width:500px; background: blue;">
</div>
<script type="text/javascript">
$('#wrap').bind('swipeleft', function(){
alert("test");
});
</script>
This is just a test page I did. It was actually working at one point in my main project but seemed to have stopped for no reason at all, not even when I reverted to an older version. I've tried a different version of jGestures with no luck.
SwipeLeft, SwipeRight, -Up and -Down are kind of poorly implemented. They are only triggered if you stay EXACTLY on the axis where you started the touch event.
For example, SwipeRight will only work if your finger moves from (X,Y) (120, 0) to (250, 0).
If the Y-Coordinates from Start- and Endpoint differ, it's not gonna work.
jGestures.js (ca. line 1095) should better look something like this (readable):
/**
* U Up, LU LeftUp, RU RightUp, etc.
*
* \U|U/
* LU\|/RU
*L---+---R
* LD/|\RD
* /D|D\
*
*/
if ( _bHasTouches && _bHasMoved === true && _bHasSwipeGesture===true) {
_bIsSwipe = true;
var deltaX = _oDetails.delta[0].lastX;
var deltaY = _oDetails.delta[0].lastY;
var hor = ver = '';
if (deltaX > 0) { // right
hor = 'right';
if (deltaY > 0) {
ver = 'down'
} else {
ver = 'up';
}
if (Math.abs(deltaY) < deltaX * 0.3) {
ver = '';
} else if (Math.abs(deltaY) >= deltaX * 2.2) {
hor = '';
}
} else { // left
hor = 'left';
if (deltaY > 0) {
ver = 'down'
} else {
ver = 'up';
}
if (Math.abs(deltaY) < Math.abs(deltaX) * 0.3) {
ver = '';
} else if (Math.abs(deltaY) > Math.abs(deltaX) * 2.2) {
hor = '';
}
}
// (_oDetails.delta[0].lastX < 0) -> 'left'
// (_oDetails.delta[0].lastY > 0) -> 'down'
// (_oDetails.delta[0].lastY < 0) -> 'up'
// alert('function swipe_' + hor + '_' + ver);
_oDetails.type = ['swipe', hor, ver].join('');
_$element.triggerHandler(_oDetails.type, _oDetails);
}
try this:
$('#wrap').bind('swipeone', function (event, obj) {
var direction=obj.description.split(":")[2]
if(direction=="left"){
doSomething();
}
});
This is already answered here:
stackoverflow about jGesture swipe events
The trick is:
… .bind('swipeone swiperight', …
You have to bind it to both events. only swiperight won't work. took me 3 hrs to figure that out :D
Best,
Rico
replace the cases on line 1326 in version 0.90.1 with this code
if ( _bHasTouches && _bHasMoved === true && _bHasSwipeGesture===true) {
_bIsSwipe = true;
_oDetails.type = 'swipe';
_vLimit = $(window).height()/4;
_wLimit = $(window).width()/4;
_sMoveY = _oDetails.delta[0].lastY;
_sMoveX = _oDetails.delta[0].lastX;
_sMoveYCompare = _sMoveY.toString().replace('-','');
_sMoveXCompare = _sMoveX.toString().replace('-','');
if(_sMoveX < 0){
if(_oDetails.delta[0].lastY < _vLimit) {
if(_sMoveYCompare < _vLimit) {
_oDetails.type += 'left';
}
}
}else if(_sMoveX > 0){
if(_sMoveYCompare < _vLimit) {
_oDetails.type += 'right'
}
}else{
_oDetails.type += '';
}
if(_sMoveY < 0){
if(_sMoveXCompare < _wLimit) {
_oDetails.type += 'up'
}
}else if(_sMoveY > 0){
if(_sMoveXCompare < _wLimit) {
_oDetails.type += 'down'
}
}else{
_oDetails.type += '';
}
// alert(_oDetails.type);
_$element.triggerHandler(_oDetails.type, _oDetails);
}
You could try both:
$('#wrap').bind('swipeleftup', function(){
doSomething();
});
$('#wrap').bind('swipeleftdown', function(){
doSomething();
});
And forget about 'swipeleft' as is quite difficult to trigger, as mentioned before.
I was just looking for the same thing and figured out that you can try all in the same function like so:
$("#wrap").on('swipeleft swipeleftup swipeleftdown', function(e){
doSomething();
});
as well as the equivalent for right:
$("#wrap").on('swiperight swiperightup swiperightdown', function(e){
doSomething();
});
You can list multiple events together with the on method.
I'm using Willian El-Turk's solution like this:
// jGestures http://stackoverflow.com/a/14403116/796538
$('.slides').bind('swipeone', function (event, obj) {
var direction=obj.description.split(":")[2]
if (direction=="left"){
//alert("left");
} else if (direction=="right"){
//alert("right");
}
});
Excellent solution, except because it executes as soon as there's movement left to right it's really sensitive even with more of a vertical swipe. it'd be great to have a minimum swipe distance on the x axis. Something like:
if (direction=="left" && distance>=50px){
Except i'm not sure how... Please feel free to edit this !
Edit - You can check distance (x axis) like this, it works for me :
$('.slides').bind('swipeone', function (event, obj) {
var xMovement = Math.abs(obj.delta[0].lastX);
var direction=obj.description.split(":")[2]
//I think 75 treshold is good enough. You can change this.
if(xMovement >= 75) {
//continue to event
//ONLY x axis swipe here. (left-right)
if (direction=="left"){
//alert("left");
} else if (direction=="right"){
//alert("right");
}
}
}

Categories

Resources