I did jquery slider using this tutorial
http://css-plus.com/2010/09/create-your-own-jquery-image-slider/
, where the pictures are sliding automatically, but just once. How can I make them circle in an infinite loop?
on-line example :
www.vytvarkajablonec.jecool.net/ati
I'd really appreciate your help!
Replace the JS code from tutorial for this:
$(document).ready(function () {
// Gallery
if (jQuery("#gallery").length) {
// Declare variables
var totalImages = jQuery("#gallery > li").length,
imageWidth = jQuery("#gallery > li:first").outerWidth(true),
totalWidth = imageWidth * totalImages,
visibleImages = Math.round(jQuery("#gallery-wrap").width() / imageWidth),
visibleWidth = visibleImages * imageWidth,
stopPosition = (visibleWidth - totalWidth);
jQuery("#gallery").width(totalWidth);
jQuery("#gallery-prev").click(function () {
if (jQuery("#gallery").position().left < 0 && !jQuery("#gallery").is(":animated")) {
jQuery("#gallery").animate({
left: "+=" + imageWidth + "px"
});
}
if (jQuery("#gallery").position().left === 0) {
jQuery("#gallery > li:last").prependTo($("#gallery"));
}
return false;
});
jQuery("#gallery-next").click(function () {
if (jQuery("#gallery").position().left > stopPosition && !jQuery("#gallery").is(":animated")) {
jQuery("#gallery").animate({
left: "-=" + imageWidth + "px"
});
}
if (jQuery("#gallery").position().left === stopPosition) {
jQuery("#gallery > li:first").appendTo($("#gallery"));
}
return false;
});
}
});
Just animate the gallary back to it's initial position if it is at the end of the gallary.
var oGallary = $('#gallery');
var gallarWidth = oGallary.width();
if(oGalary.position().left > stopPosition && oGallary.is(":animated") == false)
{
oGallary.animate({left : "-=" + imageWidth + "px"});
}
else if ( oGalary.position().left <= stopPosition && oGallary.is(":animated") == false )
{
oGallary.animate({left : "+=" + gallaryWidht + "px"}) // Get full length of the entire gallary
}
Related
I'm attempting to output on a page multiple 'labels' over an image using absolute positioned divs. Each of these divs has a unique number and are placed according to an x and y position on the map (these are percentage based so the image may be scaled).
As some of these labels may overlap, I need a way to either stop them from overlapping, or to essentially 'bump' them off eachother so they no longer overlap. (At this point, it doesn't matter if they are not in their correct position as long as they are near enough as there is a separate 'Pin' view).
They need to stay within the confines of their container and not overlap with eachother.
HTML:
<div id="labelzone">
<div class="label" style="left:0%;top:8%">001</div>
<div class="label" style="left:0%;top:11%">002</div>
<div class="label" style="left:1%;top:10%">003</div>
</div>
CSS:
#labelzone{
float:left;
width:500px;
height:500px;
border: 1px solid black;
position: relative;
}
.label{
position:absolute;
border:1px solid black;
background-color:white;
}
Jsfiddle: https://jsfiddle.net/79cco1oy/
There's a simple example of what I have as an output, these pins could be placed anywhere and there is no limit to how many is on the page, however there shouldn't be any occasion where there are too many to fit in the area.
I'm toying around with doing some form of collision detection and currently attempting to figure out an algorithm of some sort to get them to no longer overlap, and ensure they also don't overlap another item.
My solution is a bit more object oriented.
One object (LabelPool) will contain labels and will be in charge of storing and accomodating them so that they don't collide. You can customize the x/y values that you want to add/substract of the Label's positions in order to avoid their collision. The other object (Label) defines a Label and has some convenient methods. The collision algorithm that I used in LabelPool was taken from this post
var Label = function ($el) {
var position = $el.position(),
width = $el.outerWidth(true),
height = $el.outerHeight(true);
this.getRect = function () {
return {
x: position.left,
y: position.top,
width: width,
height: height
};
};
this.modifyPos = function (modX, modY) {
position.top += modY;
position.left += modX;
updatePos();
};
function updatePos() {
$el.css({
top: position.top,
left: position.left
});
}
};
var LabelPool = function () {
var labelPool = [];
function collides(a, b) {
return !(((a.y + a.height) < (b.y)) || (a.y > (b.y + b.height)) || ((a.x + a.width) < b.x) || (a.x > (b.x + b.width)));
}
function overlaps(label) {
var a = label.getRect();
return labelPool.some(function (other) {
return collides(a, other.getRect());
});
}
this.accomodate = function (label) {
while (labelPool.length && overlaps(label)) {
label.modifyPos(0, 1);// You can modify these values as you please.
}
labelPool.push(label);
};
};
var labelPool = new LabelPool;
$(".label").each(function (_, el) {
labelPool.accomodate(new Label($(el)));
});
Here's the fiddle.
Hope it helps.
Using js and jquery, you can find a basic collision engine based on left/top abs position and size of the label.
https://jsfiddle.net/Marcassin/79cco1oy/6/
Every time you want to add a Label, you check if the positionning is overlaping any existing div, in this case, you translate the new Label to position. This operation may not be the most beautiful you can find, there can be a long process time in case of lots of labels.
$(document).ready (function () {
addLabel (0, 8);
addLabel (0, 11);
addLabel (1, 10);
addLabel (2, 7);
});
function addLabel (newLeft, newTop)
{
var newLab = document.createElement ("div");
newLab.className = "label";
$(newLab).css({"left": newLeft+"%", "top": newTop + "%"});
var labels = $("#labelzone > div");
newLab.innerHTML = "00" + (labels.length + 1); // manage 0s
$("#labelzone").append (newLab);
var isCollision = false;
var cpt = 1;
do
{
isCollision = false;
$(labels).each (function () {
if (! isCollision && collision (this, newLab))
isCollision = true;
});
if (isCollision)
$(newLab).css({"left": (newLeft + cpt++) + "%",
"top": (newTop + cpt++) + "%"});
} while (isCollision);
}
function isInside (pt, div)
{
var x = parseInt($(div).css("left"));
var y = parseInt($(div).css("top"));
var w = $(div).width () + borderWidth;
var h = $(div).height ();
if (pt[0] >= x && pt[0] <= x + w &&
pt[1] >= y && pt[1] <= y + h)
return true;
return false;
}
function collision (div1, div2)
{
var x = parseInt($(div1).css("left"));
var y = parseInt($(div1).css("top"));
var w = $(div1).width () + borderWidth;
var h = $(div1).height ();
var pos = [x, y];
if (isInside (pos, div2))
return true;
pos = [x + w, y];
if (isInside (pos, div2))
return true;
pos = [x + w, y + h];
if (isInside (pos, div2))
return true;
pos = [x, y + h];
if (isInside (pos, div2))
return true;
return false;
}
Here's another implementation of collision detection close to what you asked for. The two main goals being:
move vertically more than horizontally (because boxes are wider than tall)
stay within a reasonable range from the origin
Here goes:
function yCollision($elem) {
var $result = null;
$('.label').each(function() {
var $candidate = $(this);
if (!$candidate.is($elem) &&
$candidate.position().top <= $elem.position().top + $elem.outerHeight() &&
$candidate.position().top + $candidate.outerHeight() >= $elem.position().top) {
$result = $candidate;
console.log("BUMP Y");
}
});
return $result;
}
function xCollision($elem) {
var $result = null;
$('.label').each(function() {
$candidate = $(this);
if (!$candidate.is($elem) &&
yCollision($elem) &&
yCollision($elem).is($candidate) &&
$candidate.position().left <= $elem.position().left + $elem.outerWidth() &&
$candidate.position().left + $candidate.outerWidth() >= $elem.position().left) {
$result = $candidate;
console.log("BUMP X");
}
});
return $result;
}
function fuzzyMoveY($elem, direction) {
var newTop = $elem.position().top + $elem.outerHeight() / 4 * direction;
// stay in the canvas - top border
newTop = (newTop < 0 ? 0 : newTop);
// stay in the canvas - bottom border
newTop = (newTop + $elem.outerHeight() > $("#labelzone").outerHeight() ? $("#labelzone").outerHeight() - $elem.outerHeight() : newTop);
// stay close to our origin
newTop = (Math.abs(newTop - $elem.attr("data-origin-top")) > $elem.outerHeight() ? $elem.attr("data-origin-top") : newTop);
$elem.css({'top': newTop});
}
function fuzzyMoveX($elem, direction) {
var newLeft = $elem.position().left + $elem.outerWidth() / 4 * direction;
// stay in the canvas - left border
newLeft = (newLeft < 0 ? 0 : newLeft);
// stay in the canvas - right border
newLeft = (newLeft + $elem.outerWidth() > $("#labelzone").outerWidth() ? $("#labelzone").outerWidth() - $elem.outerWidth() : newLeft);
// stay close to our origin
newLeft = (Math.abs(newLeft - $elem.attr("data-origin-left")) > $elem.outerWidth() ? $elem.attr("data-origin-left") : newLeft);
$elem.css({'left': newLeft});
}
function bumpY($above, $below) {
if ($above.position().top > $below.position().top) {
$buff = $above;
$above = $below;
$below = $buff;
}
fuzzyMoveY($above, -1);
fuzzyMoveY($below, 1);
}
function bumpX($left, $right) {
if ($left.position().left > $right.position().left) {
$buff = $right;
$right = $left;
$left = $buff;
}
fuzzyMoveX($left, 1);
fuzzyMoveX($right, -1);
}
$('.label').each(function() {
$(this).attr('data-origin-left', $(this).position().left);
$(this).attr('data-origin-top', $(this).position().top);
});
var yShallPass = true;
var loopCount = 0;
while (yShallPass && loopCount < 10) {
yShallPass = false;
$('.label').each(function() {
var $this = $(this);
$collider = yCollision($this);
if ($collider) {
bumpY($this, $collider);
yShallPass = true;
}
});
loopCount++;
}
console.log("y loops", loopCount);
var xShallPass = true;
var loopCount = 0;
while (xShallPass && loopCount < 10) {
xShallPass = false;
$('.label').each(function() {
var $this = $(this);
$collider = xCollision($this);
if ($collider) {
bumpX($this, $collider);
xShallPass = true;
}
});
loopCount++;
}
console.log("x loops", loopCount);
This is not production code obviously but please report back if it helps.
I want this script not to change the sizes of the images but the same sizes anywhere they are during sliding. The issue is somewhere in this code but i don't know which one that is changing the size. I want an even size
/**
* Given the item and position, this function will calculate the new data
* for the item. One the calculations are done, it will store that data in
* the items data object
*/
function performCalculations($item, newPosition) {
var newDistanceFromCenter = Math.abs(newPosition);
// Distance to the center
if (newDistanceFromCenter < options.flankingItems + 1) {
var calculations = data.calculations[newDistanceFromCenter];
} else {
var calculations = data.calculations[options.flankingItems + 1];
}
var distanceFactor = Math.pow(options.sizeMultiplier, newDistanceFromCenter)
var newWidth = distanceFactor * $item.data('original_width');
var newHeight = distanceFactor * $item.data('original_height');
var widthDifference = Math.abs($item.width() - newWidth);
var heightDifference = Math.abs($item.height() - newHeight);
var newOffset = calculations.offset
var newDistance = calculations.distance;
if (newPosition < 0) {
newDistance *= -1;
}
if (options.orientation == 'horizontal') {
var center = data.containerWidth / 2;
var newLeft = center + newDistance - (newWidth / 2);
var newTop = options.horizon - newOffset - (newHeight / 2);
} else {
var center = data.containerHeight / 2;
var newLeft = options.horizon - newOffset - (newWidth / 2);
var newTop = center + newDistance - (newHeight / 2);
}
var newOpacity;
if (newPosition === 0) {
newOpacity = 1;
} else {
newOpacity = calculations.opacity;
}
// Depth will be reverse distance from center
var newDepth = options.flankingItems + 2 - newDistanceFromCenter;
$item.data('width',newWidth);
$item.data('height',newHeight);
$item.data('top',newTop);
$item.data('left',newLeft);
$item.data('oldPosition',$item.data('currentPosition'));
$item.data('depth',newDepth);
$item.data('opacity',newOpacity);
}
function moveItem($item, newPosition) {
// Only want to physically move the item if it is within the boundaries
// or in the first position just outside either boundary
if (Math.abs(newPosition) <= options.flankingItems + 1) {
performCalculations($item, newPosition);
data.itemsAnimating++;
$item
.css('z-index',$item.data().depth)
// Animate the items to their new position values
.animate({
left: $item.data().left,
width: $item.data().width,
height: $item.data().height,
top: $item.data().top,
opacity: $item.data().opacity
}, data.currentSpeed, options.animationEasing, function () {
// Animation for the item has completed, call method
itemAnimationComplete($item, newPosition);
});
} else {
$item.data('currentPosition', newPosition)
// Move the item to the 'hidden' position if hasn't been moved yet
// This is for the intitial setup
if ($item.data('oldPosition') === 0) {
$item.css({
'left': $item.data().left,
'width': $item.data().width,
'height': $item.data().height,
'top': $item.data().top,
'opacity': $item.data().opacity,
'z-index': $item.data().depth
});
}
}
}
I have jquery code that triggers the div to move on movement on a mouse wheel.
The code below works on mouse wheel movement.
What i am trying to implement is that i want the div to move when the mouse is moved to the left or right of the screen?
function scrollLeft() {
var $left = Math.abs(Number($galleryList.css("margin-left").replace("px", "")))
;
if ($left - itemWidth <= 0) {
$galleryList.css({"margin-left": ""});
}
else {
$galleryList.css({"margin-left": -1 * Number($left - itemWidth) + "px"});
}
$(document).trigger("mousemove");
}
function scrollRight() {
var $left = Math.abs(Number($galleryList.css("margin-left").replace("px", "")))
;
if ($galleryList.width() < itemWidth + $left + $window.width()) {
$galleryList.css({"margin-left": -1 * Number($galleryList.width() - $window.width()) + "px"});
}
else {
$galleryList.css({"margin-left": -1 * Number($left + itemWidth) + "px"});
}
$(document).trigger("mousemove");
}
$window.on("mousewheel", function (event) {
if (stackedMode) {
return true;
}
if (event.deltaY == 1) { // left
scrollLeft();
}
else if (event.deltaY == -1) { // right
scrollRight();
}
animating = true;
setTimeout(function () {
animating = false;
}, 500);
})
I'm trying to create a slider and one of its function is being able to be move to next and previous by mouse event.
It is already working but the problem is that when it reaches the end, it keeps scrolling. Here is my JSfiddle.
Any idea?
var sliding,
dir,
startClientX = 0,
prevClientX = 0,
$mainDiv = $('#main-div');
function move(dir, step) {
var $ul = $mainDiv.find('.slider'),
liWidth = $ul.find('div').width();
$ul.animate({
left: '+=' + (dir * liWidth)
}, 200);
}
$mainDiv.mousedown(function (event) {
sliding = true;
startClientX = event.clientX;
return false;
}).mouseup(function (event) {
var step = event.clientX - startClientX,
dir = step > 0 ? 1 : -1;
step = Math.abs(step);
move(dir, step);
});
Instead of writing custom javascript code, I would suggest going for using jQuery cycle2 plugin that will make your life easier.
http://jquery.malsup.com/cycle2/
Demo
You need to check if slider reached left or not;
var sliding,
dir,
startClientX = 0,
prevClientX = 0,
$mainDiv = $('#main-div');
function move(dir, step) {
var $ul = $mainDiv.find('.slider'),
liWidth = $ul.find('div').width();
var childCount = $(".slider div").length;
if (((childCount - 1) * liWidth + getLeftPos()) <= 0) {
return false;
}
$ul.animate({
left: '+=' + (dir * liWidth)
}, 200);
}
function getLeftPos() {
var childPos = $(".slider").offset();
var parentPos = $(".slider").parent().offset();
return (childPos.left - parentPos.left);
}
$mainDiv.mousedown(function (event) {
sliding = true;
startClientX = event.clientX;
return false;
}).mouseup(function (event) {
var step = event.clientX - startClientX,
dir = step > 0 ? 1 : -1;
step = Math.abs(step);
move(dir, step);
});
can anybody help me understand how Honda achieved this effect:
http://testdays.hondamoto.ch/
I mean the ease when you scroll.
var $pages = $(".page"),
tot = $pages.length,
c = 0, pagePos = 0, down = 0, listen = true;
$('html, body').on('DOMMouseScroll mousewheel', function(e) {
e.preventDefault();
if(!listen)return;
listen = false;
down = e.originalEvent.detail > 0 || e.originalEvent.wheelDelta < 0;
c = Math.min(Math.max(0, down ? ++c : --c), tot-1);
pagePos = $pages.eq(c).offset().top;
$(this).stop().animate({scrollTop: pagePos}, 650, function(){
listen = true;
});
});
*{margin:0;}
.page{min-height:100vh;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="page" style="background:#0bf">PAGE 1</div>
<div class="page" style="background:#fb0">PAGE 2</div>
<div class="page" style="background:#0fb">PAGE 3</div>
<div class="page" style="background:#b0f">PAGE 4</div>
P.S:
Use .position().top; if your .pages are inside a scrollable DIV like $("#pagesParent") (instead of $('html, body'))
Notice:
for mobile you might want to adjust the value accounting for the browser's tabs bar height (or best, prevent that behaviour at all). You got the idea
Open up their JS file : http://testdays.hondamoto.ch/js/script_2.js
and search for Utils - Navigation
/***********************************************************************************************/
/************************************ Utils - Navigation *************************************/
/***********************************************************************************************/
/**
* navigation
*/
function navigation(target){
//--Init Quiz
if(!quizRdy){
hideQuiz();
}
//Add class to body
var pageName = target.substr(1).split('-');
$('body').removeClass(lastPage);
$('body').addClass(pageName[0]);
lastPage = pageName[0];
if(resizeBg)retractBg();
resizeBg = false;
busy = true;
$('body').addClass('loading');
//Change Nav Color
$('#nav-wrapper ul.nav li a').each(function(){
$(this).removeClass('selected');
});
var currentNavNumber = currentNav +1;
$('#main_nav_'+currentNavNumber).addClass('selected')
var wHeight = $(window).height();
if(wHeight<1080){
var newMargin = 180 - ( (wHeight - 720)/2 ) ;
if(newMargin<0) newMargin=180;
}else{
var newMargin =0 - (wHeight - 1080)/2;
}
var navTop = $(target).offset().top + newMargin;
navTop += 'px';
trace('navTop : '+navTop);
//$('#nav-wrapper').css('top',navTop);
$('html,body').stop().animate({
scrollTop: $(target).offset().top + newMargin
}, 1000,'easeInOutExpo',function(){
trace('annime done - wHeight : '+wHeight+' target top : '+$(target).offset().top);
if(currentNav==2 && !quizRdy && !quizForm){
showQuiz();
}
if(currentNav==4){
//update social datas
$.getJSON('inc/socials.php', function(data) {
$('#count-fans').empty().append(data['fans-count']);
$('#count-followers').empty().append(data['followers-count']);
});
}
/*
if(currentNav==2){
$('#quiz-nav').livequery(function(){
$(this).show();
});
}else{
$('#quiz-nav').livequery(function(){
$(this).hide();
});
}
*/
$('body').removeClass('loading');
if(currentNav!=0 && currentNav!=4){
$('#nav-wrapper').fadeIn(200);
}else{
$('#nav-wrapper').fadeOut(200);
}
if(currentNav==3){
//--Init Google Map
if(!mapReady){
if(dealerReady){
//init map
initialize();
}else{
askMap = true;
}
}
}
if(wHeight>1080){
extendBg();
}
busy = false;
});
}
/**
* navigation next Page
*/
function nextPage(){
if(currentNav<navArray.length-1 && !busy){
currentNav++;
navigation(navArray[currentNav]);
}
}
/**
* navigation previous Page
*/
function prevPage(){
if(currentNav>0 && !busy){
currentNav--;
navigation(navArray[currentNav]);
}
}
/**
* Center content
*/
function centerContent(){
if(!busy){
//--Retract Background if expended for big screen
if(resizeBg)retractBg();
var wHeight = $(window).height();
var wWidth = $(window).width();
var imgHeight = 0;
//--Test image width / Height and fill the screen
if(wWidth / wHeight > ratioImg ){
//trace('case1 - width : ' + wWidth + ' height : '+wHeight);
if(wHeight > 1080 || wWidth > 1900){
var newImgHeight = wWidth * 1080 / 1920;
$(".bg-image").each(function(){
$(this).css({
'height':newImgHeight+'px',
'width':'100%'
});
});
imgHeight = newImgHeight;
}else{
$(".bg-image").each(function(){
$(this).css({
'height':'1080px',
'width':'1900px'
});
});
imgHeight = 1080;
}
}else{
if(wHeight > 1080 || wWidth > 1900){
$(".bg-image").each(function(){
var newImgWidth = wHeight * 1920 / 1080;
$(this).css({
'height':wHeight+'px',
'width':newImgWidth+'px'
});
});
imgHeight = wHeight;
}else{
$(".bg-image").each(function(){
$(this).css({
'height':'1080px',
'width':'1900px'
});
});
imgHeight = 1080;
}
}
//--Fix height if window > img height
if(wHeight>imgHeight){
$(".bg-image").each(function(){
var newImgWidth = wHeight * 1920 / 1080;
$(this).css({
'height':wHeight+'px',
'width':newImgWidth+'px'
});
});
}
//--Center horizontal bkg image
if(wWidth<1900){
$(".bg-image").each(function(){
var marginCenter = (wWidth - 1900) / 2;
marginCenter = marginCenter * -1;
if($(this).width() > (wWidth + marginCenter)){
$(this).css({'margin-left':-marginCenter+'px'});
}
});
}
//--Scroll to the good position
if(wHeight<1080){
var newMargin = 180 - ( (wHeight - 720)/2 ) ;
if(newMargin<0) newMargin=180;
}else{
var newMargin =0 - (wHeight - 1080)/2;
}
var navTop =$(navArray[currentNav]).offset().top + newMargin;
navTop += 'px';
//$('#nav-wrapper').css('top',navTop);
//trace('Scrool to good position, then expend bg : ' + navArray[currentNav] + ' '+ $(navArray[currentNav]).offset().top);
$('html,body').stop().animate({
scrollTop: $(navArray[currentNav]).offset().top + newMargin
}, 1000,'easeInOutExpo',function(){
if(wHeight>1080){
extendBg();
}
});
}
}
/**
* Extend the background image for big screen ( > 1080 px )
*/
function extendBg(){
var hWin = $(window).height();
if(hWin > 1080){
//--Get & save current page Name
lastBg = navArray[currentNav].split('-');
lastBg = lastBg[0].substr(1);
lastheight = $('#bg-'+lastBg).height();
//--Calculate the position from top to set the scroll position
posToTop = (hWin - $('#bg-'+lastBg).height())/2;
posToTop = $('#bg-'+lastBg).offset().top - posToTop;
lastPosToTop = $('#bg-'+lastBg).offset().top;
//trace('posToTop setting : '+posToTop+' page : ' + lastBg);
//--Set boolean resize to true to call the retract BG
resizeBg = true;
$('#bg-'+lastBg).css({'z-index':2});
//--Test if it's first or last
if(currentNav != 0 && currentNav != (navArray.length-1)){
$('#bg-'+lastBg).animate({
height:hWin+'px',
top:posToTop+'px'
},600);
}else{
if(currentNav==0){
posToTop=0;
$('#bg-'+lastBg).animate({
height:hWin+'px',
top:0
},600);
}else{
posToTop=0;
$('#bg-'+lastBg).animate({
height:hWin+'px',
top:4320+'px'
},600);
}
}
//--Scroll to the bottom for credits page
if(currentNav==(navArray.length-1)){
$('html,body').stop().animate({
scrollTop: $(document).height()
}, 1000,'easeInOutExpo');
}
}
}
/**
* Retrac the background to normal
*/
function retractBg(){
var hWin = $(window).height();
if(resizeBg && lastheight>0 && lastBg!=""){
$('#bg-'+lastBg).css({'z-index':0});
//trace('posToTop callback : '+posToTop + ' lastBg : ' + lastBg + ' lastheight : ' +lastheight);
if(posToTop>0){
//trace('reset pos top : ' + posToTop);
$('#bg-'+lastBg).animate({
height:lastheight+'px',
top:lastPosToTop+'px'
},600)
}else{
$('#bg-'+lastBg).animate({
height:lastheight+'px'
},600)
}
}
}