PDA

View Full Version : jQuery - Carousel rotate to position



keyboard
09-13-2013, 12:08 PM
Hey Everyone!
I have a basic Carousel which consists of these two files:



<!doctype html>
<html lang="en">
<head>
<title>jQuery UI Carousel - Default functionality</title>
<script type="text/javascript" src="jquery-1.3.2.js"></script>
<script type="text/javascript" src="ui.core.js"></script>
<script type="text/javascript" src="ui.carousel.js"></script>
<link type="text/css" href="demos.css" rel="stylesheet" />
<style type="text/css">
body {
color:white;
background-color:#011015;
}
#step {
list-style-type:none;
margin:0;
padding:0;
color:black;
}
#step li {
width:30px;
padding:15px;
background-color:white;
display:inline;
}
#carousel {
margin:auto;
top:0;
position:relative;
height:160px;
margin:70px;
padding:0;
}
#carousel_border {
position:relative;
background-color:#010707;
border:1px solid #96FFFB;
width:500px;
height:330px;
border-radius:100%;
box-shadow:0 0 50px #3BB7ED;
margin:auto;
}
#carousel_mask{
position:relative;
background-color:#011015;
-khtml-opacity:.50;
-moz-opacity:.50;
-ms-filter:”alpha(opacity=50)”;
filter:alpha(opacity=50);
filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0.50);
opacity:.50;
border:1px solid #96FFFB;
width:500px;
height:330px;
border-radius:100%;
}
#innercircle {
position:absolute;
border:1px solid #DF740C;
width:250px;
height:165px;
left:50%;
top:50%;
border-radius:100%;
box-shadow: 0 0 50px #DF740C;
margin-left:-125px;
margin-top:-110px;
}
#carousel li {
float:left;
cursor:pointer;
cursor:hand;
list-style:none;
margin:0;
padding:0;
width:128px;
height:128px;
}
#carousel li img {
height:100%;
width:100%;
}
</style>
<script type="text/javascript">
$(function() {
//You don't need this timeout in your pages - Safari has stupid issues with our demo system
window.setTimeout(function() {
$("#carousel").carousel();
}, $.browser.safari ? 100 : 0);
});
</script>
</head>
<body>
<div id="step">
<ul id="stepList">
<li>Step 1</li>
<li>Step 2</li>
</ul>
</div>
<div id="carousel_border">
<div id="carousel_mask">
<div id="innercircle"></div>
<ul id="carousel">
<li><img src="1.png" /></li>
<li><img src="2.png" /></li>
<li><img src="3.png" /></li>
<li><img src="4.png" /></li>
<li><img src="5.png" /></li>
<li><img src="6.png" /></li>
</ul>
</div>
</div>
</body>
</html>


ui-carousel.js


/*
* jQuery UI Labs - Carousel
* - for experimental use only -
*
* Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about)
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPL (GPL-LICENSE.txt) licenses.
*
* Depends:
* ui.core.js
* effects.core.js
*/
(function($){

$.widget("ui.carousel", {

_init: function() {

var self = this;

//Prepare animation parameters and needed variables
this.items = $(this.options.items, this.element).css({ position: "absolute", top: 0, left: 0, zIndex: 1 });
$.extend(this, {
props: this.options.orientation == 'vertical' ? ['height', 'Height', 'top', 'Top'] : ['width', 'Width', 'left', 'Left'],
start: Math.PI/2,
speed: 0.03, //We need a default spead so the initialization works
direction: 'left', //This is a live property, toggled during interaction
step: 2*Math.PI/this.items.length,
paddingX: this.element.outerWidth() / 2,
paddingY: this.element.outerHeight() / 2,
itemHeight: this.options.height || this.items.height(),
itemWidth: this.options.width || this.items.width(),
offset: this.element.offset()
});

//Add pause/resume functionality when you hover a item
if(this.options.pausable) {
this.items
.bind('mouseenter.carousel', function() { self.pause(); })
.bind('mouseout.carousel', function() { self.resume(); });
}

//Little trick to jump to the start position
this.rotate("left"); this.rotate("right");

//Auto animation for the carousel
if(this.options.animate)
self._startAnimation();

$(this.options.handle || this.element)
.bind('mouseenter.carousel', function() {
self.offset = self.element.offset();
})
.bind('mouseleave.carousel', function() {
self.options.animate ? self._startAnimation() : self.interval && clearInterval(self.interval);
})
.bind("mousemove.carousel", function(e) {

if(self.paused || !self.options.animateByMouse) return;
var mod = ((e[self.options.orientation == 'vertical' ? 'pageY' : 'pageX']-self.offset[self.props[2]]) - this['offset'+self.props[1]]/2);

self.speed = Math.abs(mod)/5000;
self.direction = mod < 0 ? "right" : "left";

});

},

_setData: function(key, value) {
$.widget.prototype._setData.apply(this, arguments);
if(key == 'height') this.itemHeight = value;
if(key == 'width') this.itemWidth = value;
},

destroy: function() {

clearInterval(this.interval);
this.element.unbind('.carousel');

var self = this;
window.setTimeout(function() {
self.items.css({ left: '', top: '', position: '', height: '', width: '' }).unbind('.carousel');
self.element.removeData('carousel');
}, 0);

},

_startAnimation: function() {

var self = this;
this.speed = self.options.animate;

this.interval && clearInterval(this.interval);
this.interval = window.setInterval(function() { self.rotate(); }, 13);

},

resume: function() {
this.paused = false;
this.options.animate && this._startAnimation();
this._trigger('resume');
},

pause: function() {

var self = this;
this.paused = true;

this.options.pauseSpeed ? (this.speed = self.options.pauseSpeed) : (this.interval && clearInterval(this.interval));
this._trigger('pause');

},

select: function(item) {

this.currentItem = !isNaN(parseInt(item,10)) ? parseInt(item,10) : this.items.index(item);

this.start = Math.PI/2;
this.rotate('left', this.step * item);

this._trigger('select', null, {
value: item,
item: this.items[item]
});

},

rotate: function(direction, speed) {

var o = this.options, self = this;

direction = direction || this.direction;
this.speed = speed !== undefined ? speed : this.speed;
this.start = this.start + (direction == "right" ? -this.speed : this.speed);

self.items.each(function(i) {

//var x = Math.min(0, self.options.radius * Math.cos(angle)); w00t! this makes a half carousel
var angle = self.start + i * self.step,
x = self.options.radius * Math.cos(angle),
y = self.options.tilt * Math.sin(angle),
width = Math.max(self.itemWidth - (o.distance * self.itemWidth), self.itemWidth * ((self.options.tilt+y) / (2 * self.options.tilt))),
height = parseInt(width * self.itemHeight / self.itemWidth,10);

$.extend(this.style, {
top: self.paddingY + (self.options.orientation == 'vertical' ? x : y) - height/2 + "px",
left: self.paddingX + (self.options.orientation == 'vertical' ? y : x) - width/2 + "px",
width: width + "px",
height: height + "px",
zIndex: parseInt(100 * (self.options.tilt+y) / (2 * self.options.tilt),10)
});

});

}

});

$.extend($.ui.carousel, {
defaults: {
animate: 0, //TODO: Setting animate to false also currently blocks animateByMouse
animateByMouse: false,
distance: 0.7,
handle: false,
items: '> *',
orientation: 'horizontal',
pausable: false,
pauseSpeed: 0, //If you don't want to actually stop the carousel when hovering items, set it to something small, i.e. 0.001
radius: 200,
tilt: 125
}
});

})(jQuery);


There are also two other jscript files (both part of standard jQuery).

The issue is, I'd like it so that when you click on one of the images in the slider, it rotates that image to the closest point of the carousel (down the bottom center).

Any suggestions?
Thanks.

jscheuer1
09-14-2013, 05:40 PM
Could you link to a live demo? I started story boarding it to see what it does, when I saw it's using jQuery 1.3.2, which is way out of date. The current version of jQuery UI will not work with that, I'm not even sure where to get a version of the UI that will work with that version of jQuery or what version that would be. Can you tell me which version you have of the UI?. Plus, if you have or put up a live demo, it would have the images, saves time when making a mock up. Oh, and how important is:


<link type="text/css" href="demos.css" rel="stylesheet" />

That said, it looks like the answer would be in the creative use of and/or additions to the rotate and/or select functions.

jscheuer1
09-15-2013, 03:45 PM
OK, it was a slow weekend, so I figured all that out, I even got the step buttons to work:


/*
* jQuery UI Labs - Carousel
* - for experimental use only -
*
* Copyright (c) 2009 AUTHORS.txt (http://ui.jquery.com/about)
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPL (GPL-LICENSE.txt) licenses.
*
* Depends:
* ui.core.js
* effects.core.js
*/
(function($){
if(!window.console){
window.console = {log: function(){}};
}
$.widget("ui.carousel", {

_init: function() {

var self = this, timer, ttop, tleft;

//Prepare animation parameters and needed variables
this.items = $(this.options.items, this.element).css({ position: "absolute", top: 0, left: 0, zIndex: 1 });
this.items.bind('click.carousel', function(){
self.foreItem = self.items.index(this);
var $this = $(this);
clearInterval(timer);
ttop = ttop || self.items.eq(0).position().top + 0.5; //record where the top of an item should be to be in the bottom center
tleft = tleft || self.items.eq(0).position().left; //record a demarcation of which side of the carousel an item is on
if(Math.abs(Math.round($this.position().top) - ttop) < 1){return;} //it's already there, so stop
var direction = $this.position().left < tleft? 'right' : 'left';
timer = setInterval(function(){
if(Math.abs(Math.round($this.position().top) - ttop) < 1){
clearInterval(timer);
console.log($this.position().top +' - '+ttop);//for diagnostics
var count = direction === 'right'? 5 : 4;
timer = setInterval(function(){ //attempt at a fudge to get the item more nearly in its desired place:
if(!--count){
clearInterval(timer);
console.log($this.position().top +' - '+ttop); //for diagnostics
return;
}
self.rotate(direction, self.speed);
}, 1);
return;
}
self.rotate(direction, self.speed);
}, 1);
});
$('#stepList li').css({cursor: 'pointer'}).bind('click.carousel', function(){
var step = $('#stepList li').index(this) + 1, il = self.items.length;
self.items.eq(((self.foreItem || 0) - step + il) % il).trigger('click.carousel');
});
$.extend(this, {
props: this.options.orientation == 'vertical' ? ['height', 'Height', 'top', 'Top'] : ['width', 'Width', 'left', 'Left'],
start: Math.PI/2,
speed: 0.03, //We need a default spead so the initialization works
direction: 'left', //This is a live property, toggled during interaction
step: 2*Math.PI/this.items.length,
paddingX: this.element.outerWidth() / 2,
paddingY: this.element.outerHeight() / 2,
itemHeight: this.options.height || this.items.height(),
itemWidth: this.options.width || this.items.width(),
offset: this.element.offset()
});

//Add pause/resume functionality when you hover a item
if(this.options.pausable) {
this.items
.bind('mouseenter.carousel', function() { self.pause(); })
.bind('mouseout.carousel', function() { self.resume(); });
}

//Little trick to jump to the start position
this.rotate("left"); this.rotate("right");

//Auto animation for the carousel
if(this.options.animate)
self._startAnimation();

$(this.options.handle || this.element)
.bind('mouseenter.carousel', function() {
self.offset = self.element.offset();
})
.bind('mouseleave.carousel', function() {
self.options.animate ? self._startAnimation() : self.interval && clearInterval(self.interval);
})
.bind("mousemove.carousel", function(e) {

if(self.paused || !self.options.animateByMouse) return;
var mod = ((e[self.options.orientation == 'vertical' ? 'pageY' : 'pageX']-self.offset[self.props[2]]) - this['offset'+self.props[1]]/2);

self.speed = Math.abs(mod)/5000;
self.direction = mod < 0 ? "right" : "left";

});

},

_setData: function(key, value) {
$.widget.prototype._setData.apply(this, arguments);
if(key == 'height') this.itemHeight = value;
if(key == 'width') this.itemWidth = value;
},

destroy: function() {

clearInterval(this.interval);
this.element.unbind('.carousel');

var self = this;
window.setTimeout(function() {
self.items.css({ left: '', top: '', position: '', height: '', width: '' }).unbind('.carousel');
self.element.removeData('carousel');
}, 0);

},

_startAnimation: function() {

var self = this;
this.speed = self.options.animate;

this.interval && clearInterval(this.interval);
this.interval = window.setInterval(function() { self.rotate(); }, 13);

},

resume: function() {
this.paused = false;
this.options.animate && this._startAnimation();
this._trigger('resume');
},

pause: function() {

var self = this;
this.paused = true;

this.options.pauseSpeed ? (this.speed = self.options.pauseSpeed) : (this.interval && clearInterval(this.interval));
this._trigger('pause');

},

select: function(item) {

this.currentItem = !isNaN(parseInt(item,10)) ? parseInt(item,10) : this.items.index(item);

this.start = Math.PI/2;
this.rotate('left', this.step * item);

this._trigger('select', null, {
value: item,
item: this.items[item]
});

},

rotate: function(direction, speed) {

var o = this.options, self = this;

direction = direction || this.direction;
this.speed = speed !== undefined ? speed : this.speed;
this.start = this.start + (direction == "right" ? -this.speed : this.speed);

self.items.each(function(i) {

//var x = Math.min(0, self.options.radius * Math.cos(angle)); w00t! this makes a half carousel
var angle = self.start + i * self.step,
x = self.options.radius * Math.cos(angle),
y = self.options.tilt * Math.sin(angle),
width = Math.max(self.itemWidth - (o.distance * self.itemWidth), self.itemWidth * ((self.options.tilt+y) / (2 * self.options.tilt))),
height = parseInt(width * self.itemHeight / self.itemWidth,10);

$.extend(this.style, {
top: self.paddingY + (self.options.orientation == 'vertical' ? x : y) - height/2 + "px",
left: self.paddingX + (self.options.orientation == 'vertical' ? y : x) - width/2 + "px",
width: width + "px",
height: height + "px",
zIndex: parseInt(100 * (self.options.tilt+y) / (2 * self.options.tilt),10)
});

});

}

});

$.extend($.ui.carousel, {
defaults: {
animate: 0, //TODO: Setting animate to false also currently blocks animateByMouse
animateByMouse: false,
distance: 0.7,
handle: false,
items: '> *',
orientation: 'horizontal',
pausable: false,
pauseSpeed: 0, //If you don't want to actually stop the carousel when hovering items, set it to something small, i.e. 0.001
radius: 200,
tilt: 125
}
});

})(jQuery);



Notes: I only tested it as working as intended in current Chrome, current Firefox, IE 10. IE 9 (IE 10 in IE 9 mode) probably could handle it with IE 9 specific CSS (what's happening now in IE 9 is that all of the images are behind something (mask or inner circle probably) so are not seen). IE 8 sort of works, at least IE 10 in IE 8 mode, but the mask and inner circle don't render as intended and the 'fudge' in the script would have to be set differently for it to get it to come to rest at the exact or nearer to the exact spots desired. That should be fairly easy to do, just have IE 8 specific numbers here:


var count = direction === 'right'? 5 : 4;

Like 4 and 3, or 3 and 2, perhaps.

Oh, and I just tested in Opera, the action there is jerkier than the others and those numbers would have to be reduced for Opera as well.

I used these scripts (and the carousel one whose edited code is above) and found the demo site and used its demo.css:


<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7/jquery-ui.min.js"></script>

I think it would work with the scripts you have.

P.S. I have the IE 8 tweak worked out and the Opera one, mostly if you're interested.