Full Code of fredleblanc/roundabout for AI

master dceb04cbb92e cached
2 files
69.8 KB
19.3k tokens
1 requests
Download .txt
Repository: fredleblanc/roundabout
Branch: master
Commit: dceb04cbb92e
Files: 2
Total size: 69.8 KB

Directory structure:
gitextract_6h2mdl76/

├── README.md
└── jquery.roundabout.js

================================================
FILE CONTENTS
================================================

================================================
FILE: README.md
================================================
# Roundabout

**Note: Roundabout is no longer under active development. I've moved the documentation over here to support the exists plugin, but there are known issues and such that won't be fixed. Use at your own risk.**

Roundabout is a jQuery plugin that easily converts unordered lists & other nested HTML structures into entertaining, interactive, turntable-like areas.

It’s ready-to-go straight out of the box, but if you want to get crazy, Roundabout is highly-customizable with an extensive API that allows for some pretty amazing results.

Roundabout requires jQuery (at least version 1.2).


## Add-Ons

Roundabout is equipped to play nicely with a couple of other plugins if they’re made available.

- [Roundabout Shapes](http://fredhq.com/projects/roundabout-shapes) by Fred LeBlanc
  Roundabout can move in more ways than just a turntable. With Shapes, you have many other ways you can move your content around the page.
  
- [jQuery Easing](http://gsgd.co.uk/sandbox/jquery/easing/) by George McGinley Smith
  jQuery comes with two easing styles built in, but this plugin adds many, many more. Include this script and use any of its defined easing functions in your Roundabout animations.
  
- [Event.drag](http://threedubmedia.com/code/event/drag) & [Event.drop](http://threedubmedia.com/code/event/drop) by ThreeDubMedia
  In addition to rotating on click, Roundabout can also move by clicking and dragging on the Roundabout element itself. Include these scripts and turn on enableDrag.
  
  
### But That’s Not All!
The list above is only a list of the plugins that have support baked in, but Roundabout will play nicely with many other plugins. (It’s up to you to integrate those yourself.)


## Using Roundabout

Include the `jquery.roundabout.js` JavaScript file on your page after you include jQuery itself. Also, either link to the included CSS file, or copy the CSS styles from that file and paste them into your site's CSS file.

To activate Roundabout in its simplest form, you can do this:

```javascript
$('ul').roundabout();
```

Of course, this will change *all* of your `ul` elements into Roundabouts, which probably isn't what you want, but you can easily change the selector to only target the elements you wish to convert


### Setting Options

You can set options on Roundabout to change how it behaves. Do this by passing in an object of options into the main Roundabout call upon initialization, like so:

```javascript
$('ul').roundabout({
    btnNext: ".next"
});
```


### Incorporating Roundabout Shapes

If you're using the sister plugin Roundabout Shapes, be sure to include the `jquery.roundabout-shapes.js` file after you include the main Roundabout JavaScript file. Next, you'll select the shape as on of the options that you pass into Roundabout upon initialization:

```javascript
$('ul').roundabout({
    btnNext: ".next",
    shape: "figure8"
});
```

### Calling Roundabout Methods

Roundabout comes with a number of methods you can call to better control how it works. Calling those methods are done by re-calling `roundabout` on the element that Roundabout is already working on and passing in the name of the method to use as the first parameter. If the method requires other parameters, pass those in as subsequent parameters.

For example, instead of using the `btnNext` option, you can manually implement this yourself like this:

```javascript
$('.btnNext', function(e) {
    e.stopPropagation();
    e.preventDefault();
    
    // this is the action
    $('ul#myRoundabout').roundabout('animateToNextChild');
    
    return false;
});
```

### Enabling Drag & Drop

Lately it seems that this doesn't work as well as it once did. Not sure why, but you can still enable it. To do this, you'll need to grab v2 of the `jquery.event.drag` and `jquery.event.drop` plugins by ThreeDubMedia. Include them on your page after Roundabout is included.

Next, enable your Roundabout to use drag and drop like so:

```javascript
$('ul').roundabout({
    enableDrag: true
});
```

### Using Autoplay

Autoplay lets you have Roundabout automatically animate on an interval. This functionality is included with the Roundabout core, so no additional scripts are needed to get this working.

To enable autoplay, there are three options you can set:

```javascript
$('ul').roundabout({
    autoplay: true,
    autoplayDuration: 5000,
    autoplayPauseOnHover: true
});
```

The first option, `autoplay` will turn on autoplay. The second, `autoplayDuration` is the length of time in milliseconds between animation triggers. The final option, `autoplayPauseOnHover` will force autoplay never to figure while the user has their cursor over the Roundabout itself.


## Support

Version 2 (the current version) works reasonably well, although if you look in the issues you'll see a number of things that don't work for some people. As mentioned above, this plugin is no longer under active development. Feel free to continue submitting issues for others to see, but no further official action can be guaranteed at all.

## API

### Settable Options

Roundabout comes with many settable configuration options that let you customize how it operates.

<table>
	<thead>
		<tr>
			<th scope="col">Option</th>
			<th scope="col">Description</th>
			<th scope="col">Data Type</th>
			<th scope="col" class="default-value">Default</th>
		</tr>
	</thead>
	<tbody>
		<tr id="bearing">
			<td class="option"><code>bearing</code></td>
			<td>
				The starting direction in which Roundabout should
				face relative to the <code>focusBearing</code>.
			</td>
			<td class="data-type">float</td>
			<td class="default-value"><code>0.0</code></td>
		</tr>

		<tr id="tilt">
			<td class="option"><code>tilt</code></td>
			<td>
				Slightly alters the calculations of moving elements.
				In the default <code>shape</code>,
				it adjusts the apparent <code>tilt</code>. Other shapes
				will differ.
			</td>
			<td class="data-type">float</td>
			<td class="default-value"><code>0.0</code></td>
		</tr>

		<tr id="minZ">
			<td class="option"><code>minZ</code></td>
			<td>
				The lowest z-index that will be assigned to a moving
				element. This occurs when the moving element is
				opposite of (that is, 180° away from) the 
				<code>focusBearing</code>.
			</td>
			<td class="data-type">integer</td>
			<td class="default-value"><code>100</code></td>
		</tr>

		<tr id="maxZ">
			<td class="option"><code>maxZ</code></td>
			<td>
				The greatest z-index that will be assigned to a
				moving element. This occurs when the moving element
				is at the same bearing as the 
				<code>focusBearing</code>.
			</td>
			<td class="data-type">integer</td>
			<td class="default-value"><code>280</code></td>
		</tr>

		<tr id="minOpacity">
			<td class="option"><code>minOpacity</code></td>
			<td>
				The lowest opacity that will be assigned to a moving
				element. This occurs when the moving element is
				opposite of (that is, 180° away
				from) the <code>focusBearing</code>.
			</td>
			<td class="data-type">float</td>
			<td class="default-value"><code>0.4</code></td>
		</tr>

		<tr id="maxOpacity">
			<td class="option"><code>maxOpacity</code></td>
			<td>
				The greatest opacity that will be assigned to a
				moving element. This occurs when the moving element
				is at the same bearing as the
				<code>focusBearing</code>.
			</td>
			<td class="data-type">float</td>
			<td class="default-value"><code>1.0</code></td>
		</tr>

		<tr id="minScale">
			<td class="option"><code>minScale</code></td>
			<td>
				The lowest size (relative to its starting size) that
				will be assigned to a moving element. This occurs
				when the moving element is opposite of (that is, 180°
				away from) the
				<code>focusBearing</code>.
			</td>
			<td class="data-type">float</td>
			<td class="default-value"><code>0.4</code></td>
		</tr>
	
		<tr id="maxScale">
			<td class="option"><code>maxScale</code></td>
			<td>
				The greatest size (relative to its starting size)
				that will be assigned to a moving element. This
				occurs when the moving element is at the same bearing
				as the
				<code>focusBearing</code>.
			</td>
			<td class="data-type">float</td>
			<td class="default-value"><code>1.0</code></td>
		</tr>
	
		<tr id="duration">
			<td class="option"><code>duration</code></td>
			<td>
				The length of time Roundabout will take to move from
				one child element being in focus to another (when an
				animation is triggered). This value acts as the
				default for Roundabout, but each animation action can
				be given a custom duration for that animation.
			</td>
			<td class="data-type">integer</td>
			<td class="default-value"><code>600</code></td>
		</tr>
	
		<tr id="btnNext">
			<td class="option"><code>btnNext</code></td>
			<td>
				A jQuery selector of page elements that, when
				clicked, will trigger the Roundabout to animate to
				the next moving element.
			</td>
			<td class="data-type">string</td>
			<td class="default-value"><code>null</code></td>
		</tr>
	
		<tr id="btnNextCallback">
			<td class="option"><code>btnNextCallback</code></td>
			<td>
				A function that will be called once the animation
				triggered by a
				<code>btnNext</code>-related 
				click has finished.
			</td>
			<td class="data-type">function</td>
			<td class="default-value"><code>function() {}</code></td>
		</tr>
	
		<tr id="btnPrev">
			<td class="option"><code>btnPrev</code></td>
			<td>
				A jQuery selector of page elements that, when
				clicked, will trigger the Roundabout to animate to
				the previous moving element.
			</td>
			<td class="data-type">string</td>
			<td class="default-value"><code>null</code></td>
		</tr>
	
		<tr id="btnPrevCallback">
			<td class="option"><code>btnPrevCallback</code></td>
			<td>
				A function that will be called once the animation
				triggered by a
				<code>btnPrev</code>-releated 
				click has finished.
			</td>
			<td class="data-type">function</td>
			<td class="default-value"><code>function() {}</code></td>
		</tr>
	
		<tr id="btnToggleAutoplay">
			<td class="option"><code>btnToggleAutoplay</code></td>
			<td>
				A jQuery selector of page elements that, when
				clicked, will toggle the Roundabout’s <a
				href="#autoplay"><code>autoplay</code></a> state
				(either starting or stopping).
			</td>
			<td class="data-type">string</td>
			<td class="default-value"><code>null</code></td>
		</tr>
	
		<tr id="btnStartAutoplay">
			<td class="option"><code>btnStartAutoplay</code></td>
			<td>
				A jQuery selector of page elements that, when
				clicked, will start the Roundabout’s 
				<code>autoplay</code> feature
				(if it’s currently stopped).
			</td>
			<td class="data-type">string</td>
			<td class="default-value"><code>null</code></td>
		</tr>
	
		<tr id="btnStopAutoplay">
			<td class="option"><code>btnStopAutoplay</code></td>
			<td>
				A jQuery selector of page elements that, when
				clicked, will stop the Roundabout’s
				<code>autoplay</code>
				feature (if it’s current playing).
			</td>
			<td class="data-type">string</td>
			<td class="default-value"><code>null</code></td>
		</tr>
	
		<tr id="easing">
			<td class="option"><code>easing</code></td>
			<td>
				The easing function to use when animating Roundabout.
				With no other plugins, the standard jQuery easing
				functions are available. When using the 
				jQuery easing plugin, 
				all of its easing functions will also be available.
			</td>
			<td class="data-type">string</td>
			<td class="default-value"><code>"swing"</code></td>
		</tr>
	
		<tr id="clickToFocus">
			<td class="option"><code>clickToFocus</code></td>
			<td>
				When <code>true</code>, Roundabout will bring
				non-focused moving elements into focus when they’re
				clicked. Otherwise, click events won’t be captured
				and will be passed through to the moving child
				elements.
			</td>
			<td class="data-type">boolean</td>
			<td class="default-value"><code>true</code></td>
		</tr>
	
		<tr id="clickToFocusCallback">
			<td class="option"><code>clickToFocusCallback</code></td>
			<td>
				A function that will be called once the 
				<code>clickToFocus</code> 
				animation has completed.
			</td>
			<td class="data-type">function</td>
			<td class="default-value"><code>function() {}</code></td>
		</tr>
	
		<tr id="focusBearing">
			<td class="option"><code>focusBearing</code></td>
			<td>
				The bearing that Roundabout will use as the focus
				point. All animations that move Roundabout between
				children will animate the given child element to this
				bearing.
			</td>
			<td class="data-type">float</td>
			<td class="default-value"><code>0.0</code></td>
		</tr>
	
		<tr id="shape">
			<td class="option"><code>shape</code></td>
			<td>
				The path that moving elements follow. By default,
				Roundabout comes with one shape, which is
				<code>lazySusan</code>. When using Roundabout with the
				Roundabout Shapes
				plugin, there are many other shapes available.
			</td>
			<td class="data-type">string</td>
			<td class="default-value"><code>"lazySusan"</code></td>
		</tr>
	
		<tr id="debug">
			<td class="option"><code>debug</code></td>
			<td>
				When <code>true</code>, Roundabout will replace the
				contents of moving elements with information about
				the moving elements themselves.
			</td>
			<td class="data-type">boolean</td>
			<td class="default-value"><code>false</code></td>
		</tr>
	
		<tr id="childSelector">
			<td class="option"><code>childSelector</code></td>
			<td>
				A jQuery selector of child elements within the elements Roundabout
				is called upon that will become the moving elements within
				Roundabout. By default, Roundabout works on unordered lists, but it
				can be changed to work with any nested set of child elements.
			</td>
			<td class="data-type">string</td>
			<td class="default-value"><code>"li"</code></td>
		</tr>
	
		<tr id="startingChild">
			<td class="option"><code>startingChild</code></td>
			<td>
				The child element that will start at the Roundabout’s 
				<code>focusBearing</code>
				on load. This is a zero-based counter based on the
				order of markup.
			</td>
			<td class="data-type">integer</td>
			<td class="default-value"><code>0</code></td>
		</tr>
	
		<tr id="reflect">
			<td class="option"><code>reflect</code></td>
			<td>
				When <code>true</code>, reverses the direction in which
				Roundabout will operate. By default, <em>next</em>
				animations will rotate moving elements in a clockwise
				direction and <em>previous</em> animations will be
				counterclockwise. Using reflect will flip the two.
			</td>
			<td class="data-type">boolean</td>
			<td class="default-value"><code>false</code></td>
		</tr>
	
		<tr id="floatComparisonThreshold">
			<td class="option"><code>floatComparisonThreshold</code></td>
			<td>
				The maximum distance two values can be from one
				another to still be considered equal by Roundabout’s
				standards. This prevents JavaScript rounding errors.
			</td>
			<td class="data-type">float</td>
			<td class="default-value"><code>0.001</code></td>
		</tr>
	
		<tr id="autoplay">
			<td class="option"><code>autoplay</code></td>
			<td>
				When true, Roundabout will automatically advance the
				moving elements to the next child at a regular
				interval (settable as
				<code>autoplayDuration</code>).
			</td>
			<td class="data-type">boolean</td>
			<td class="default-value"><code>false</code></td>
		</tr>
	
		<tr id="autoplayInitialDelay">
			<td class="option"><code>autoplayInitialDelay</code><small>added in v2.4</small></td>
			<td>
				The length of time (in milliseconds) to delay the start of 
				Roundabout’s configured <code>autoplay</code>
				option. This only works with setting <code>autoplay</code> to
				<code>true</code>, and only on the first start of <code>autoplay</code>.
			</td>
			<td class="data-type">integer</td>
			<td class="default-value"><code>0</code></td>
		</tr>
	
		<tr id="autoplayDuration">
			<td class="option"><code>autoplayDuration</code></td>
			<td>
				The length of time (in milliseconds) between
				animation triggers when a
				Roundabout’s <code>autoplay</code>
				is playing.
			</td>
			<td class="data-type">integer</td>
			<td class="default-value"><code>1000</code></td>
		</tr>
	
		<tr id="autoplayPauseOnHover">
			<td class="option"><code>autoplayPauseOnHover</code></td>
			<td>
				When <code>true</code>, Roundabout will pause 
				<code>autoplay</code> when the
				user moves the cursor over the Roundabout container.
			</td>
			<td class="data-type">boolean</td>
			<td class="default-value"><code>false</code></td>
		</tr>
	
		<tr id="enableDrag">
			<td class="option"><code>enableDrag</code></td>
			<td>
				Requires event.drag 
				and 
				event.drop
				plugins by 
				ThreeDubMedia. 
				Allows a user to rotate Roundabout be clicking and
				dragging the Roundabout area itself.
			</td>
			<td class="data-type">boolean</td>
			<td class="default-value"><code>false</code></td>
		</tr>
	
		<tr id="dropDuration">
			<td class="option"><code>dropDuration</code></td>
			<td>
				The length of time (in milliseconds) the animation
				will take to animate Roundabout to the appropriate
				child when the Roundabout is “dropped.”
			</td>
			<td class="data-type">integer</td>
			<td class="default-value"><code>600</code></td>
		</tr>
	
		<tr id="dropEasing">
			<td class="option"><code>dropEasing</code></td>
			<td>
				The easing function to use when animating Roundabout
				after it has been “dropped.” With no other plugins, 
				the standard jQuery easing functions are available. 
				When using the 
				jQuery easing plugin
				all of its easing functions will also be available.
			</td>
			<td class="data-type">string</td>
			<td class="default-value"><code>"swing"</code></td>
		</tr>
	
		<tr id="dropAnimateTo">
			<td class="option"><code>dropAnimateTo</code></td>
			<td>
				The animation method to use when a dragged Roundabout
				is “dropped.” Valid values are <em>next</em>,
				<em>previous</em>, or <em>nearest</em>.
			</td>
			<td class="data-type">string</td>
			<td class="default-value"><code>"nearest"</code></td>
		</tr>
	
		<tr id="dropCallback">
			<td class="option"><code>dropCallback</code></td>
			<td>
				A function that will be called once the dropped
				animation has completed.
			</td>
			<td class="data-type">function</td>
			<td class="default-value"><code>function() {}</code></td>
		</tr>
	
		<tr id="dragAxis">
			<td class="option"><code>dragAxis</code></td>
			<td>
				The axis along which drag events are measured. Valid
				values are <em>x</em> and <em>y</em>.
			</td>
			<td class="data-type">string</td>
			<td class="default-value"><code>"x"</code></td>
		</tr>
	
		<tr id="dragFactor">
			<td class="option"><code>dragFactor</code></td>
			<td>
				Alters the rate at which dragging moves the
				Roundabout’s moving elements. Higher numbers will
				cause the moving elements to move less.
			</td>
			<td class="data-type">integer</td>
			<td class="default-value"><code>4</code></td>
		</tr>
	
		<tr id="triggerFocusEvents">
			<td class="option"><code>triggerFocusEvents</code></td>
			<td>
				When <code>true</code>, a <code>focus</code> event will
				be triggered on the child element that moves into
				focus when it does so.
			</td>
			<td class="data-type">boolean</td>
			<td class="default-value"><code>true</code></td>
		</tr>
	
		<tr id="triggerBlurEvents">
			<td class="option"><code>triggerBlurEvents</code></td>
			<td>
				When <code>true</code>, a <code>blur</code> event will be
				triggered on the child element that moves out of the
				focused position when it does so.
			</td>
			<td class="data-type">boolean</td>
			<td class="default-value"><code>true</code></td>
		</tr>
	
		<tr id="responsive">
			<td class="option"><code>responsive</code><small>added in v2.1</small></td>
			<td>
				When <code>true</code>, attaches a resize event onto the 
				window and will automatically relayout Roundabout’s
				child elements as the holder element changes size.
			</td>
			<td class="data-type">boolean</td>
			<td class="default-value"><code>false</code></td>
		</tr>
	</tbody>
</table>

### Callable Methods

Roundabout does a lot on its own, but all of the methods it uses internally to perform actions are publicly usable as well. Manually calling these methods give even more control over how Roundabout functions.

---

#### `roundabout`

Starts the Roundabout.

##### Usage

```javascript
.roundabout()
.roundabout(options)
.roundabout(callback)
.roundabout(options, callback)
```

##### Parameters
<table class="parameters">
	<tbody>
		<tr>
			<td class="type">object</td>
			<td class="parameter">
				<code>options</code> is an object of
				options to configure how
				Roundabout acts
			</td>
		</tr>
		<tr>
			<td class="type">function</td>
			<td class="parameter">
				<code>callback</code> is a function 
				that is called once the Roundabout is ready
			</td>
		</tr>
	</tbody>
</table>

Returns a *jQuery object*.

---

#### `setBearing`

Changes the `bearing` of the Roundabout.

##### Usage

```javascript
.roundabout("setBearing", bearing)
.roundabout("setBearing", bearing, callback)
```

##### Parameters

<table class="parameters">
	<tbody>
		<tr>
			<td class="type">float</td>
			<td class="parameter">
				<code>bearing</code> is a value
				between <code>0.0</code> and <code>359.9</code>
			</td>
		</tr>
		<tr>
			<td class="type">function</td>
			<td class="parameter">
				<code>callback</code> is a function 
				that is called once the change&nbsp;completes
			</td>
		</tr>
	</tbody>
</table>

Returns a *jQuery object*.

---

#### `adjustBearing`

Alters the `bearing` of the Roundabout by a given amount, either positive or negative degrees.

##### Usage

```javascript
.roundabout("adjustBearing", delta)
.roundabout("adjustBearing", delta, callback)
```

##### Parameters

<table class="parameters">
	<tbody>
		<tr>
			<td class="type">float</td>
			<td class="parameter">
				<code>delta</code> is the amount by
				which the <code>bearing</code> will change
				(either positive or&nbsp;negative)
			</td>
		</tr>
		<tr>
			<td class="type">function</td>
			<td class="parameter">
				<code>callback</code> is a function 
				that is called once the change&nbsp;completes
			</td>
		</tr>
	</tbody>
</table>

Returns a *jQuery object*.

---

#### `setTilt`

Changes the `tilt` of the Roundabout.

##### Usage

```javascript
.roundabout("setTilt", tilt)
.roundabout("setTilt", tilt, callback)
```

##### Parameters

<table class="parameters">
	<tbody>
		<tr>
			<td class="type">tilt</td>
			<td class="parameter">
				<code>tilt</code> is a value 
				typically between <code>-2.0</code> and 
				<code>10.0</code>
			</td>
		</tr>
		<tr>
			<td class="type">function</td>
			<td class="parameter">
				<code>callback</code> is a function 
				that is called once the change&nbsp;completes
			</td>
		</tr>
	</tbody>
</table>

Returns a *jQuery object*.

---

#### `adjustTilt`

Alters the `tilt` of the Roundabout by a given amount, either in positive or negative mounts.

##### Usage

```javascript
.roundabout("adjustTilt", delta)
.roundabout("adjustTilt", delta, callback)
```

##### Parameters

<table class="parameters">
	<tbody>
		<tr>
			<td class="type">tilt</td>
			<td class="parameter">
				<code>delta</code> is the amount by
				which the <code>tilt</code> will change
				(either positive or&nbsp;negative)
			</td>
		</tr>
		<tr>
			<td class="type">function</td>
			<td class="parameter">
				<code>callback</code> is a function 
				that is called once the change&nbsp;completes
			</td>
		</tr>
	</tbody>
</table>

Returns a *jQuery object*.

---

#### `animateToNearestChild`

Animates the Roundabout to the nearest child. This animation will not move the Roundabout if any child is already in focus.

##### Usage

```javascript
.roundabout("animateToNearestChild")
.roundabout("animateToNearestChild", callback)
.roundabout("animateToNearestChild", duration, easing, callback)
```

##### Parameters

<table class="parameters">
	<tbody>
		<tr>
			<td class="type">integer</td>
			<td class="parameter">
				<code>duration</code> is the length
				of time (in milliseconds) that the animation
				will take to&nbsp;complete; uses Roundabout’s
				configured <code>duration</code> if no value
				is set&nbsp;here
			</td>
		</tr>
		<tr>
			<td class="type">string</td>
			<td class="parameter">
				<code>easing</code> is the name of
				the easing function to use for&nbsp;movement;
				uses Roundabout’s configured <code>easing</code>
				if no value is set&nbsp;here
			</td>
		</tr>
		<tr>
			<td class="type">function</td>
			<td class="parameter">
				<code>callback</code> is a function 
				that is called once the change&nbsp;completes
			</td>
		</tr>
	</tbody>
</table>

Returns a *jQuery object*.

---

#### `animateToChild`

Animates the Roundabout to the given `childPosition`, which is a zero-based counter of children based on the order of markup.

##### Usage

```javascript
.roundabout("animateToChild", childPosition)
.roundabout("animateToChild", childPosition, callback)
.roundabout("animateToChild", childPosition, duration, easing)
.roundabout("animateToChild", childPosition, duration, easing, callback)
```

##### Parameters

<table class="parameters">
	<tbody>
		<tr>
			<td class="type">integer</td>
			<td class="parameter">
				<code>childPosition</code> is the
				zero-based child to which Roundabout 
				will&nbsp;animate
			</td>
		</tr>
		<tr>
			<td class="type">integer</td>
			<td class="parameter">
				<code>duration</code> is the length
				of time (in milliseconds) that the animation
				will take to&nbsp;complete; uses Roundabout’s
				configured <code>duration</code> if no value
				is set&nbsp;here
			</td>
		</tr>
		<tr>
			<td class="type">string</td>
			<td class="parameter">
				<code>easing</code> is the name of
				the easing function to use for&nbsp;movement;
				uses Roundabout’s configured <code>easing</code>
				if no value is set&nbsp;here
			</td>
		</tr>
		<tr>
			<td class="type">function</td>
			<td class="parameter">
				<code>callback</code> is a function 
				that is called once the change&nbsp;completes
			</td>
		</tr>
	</tbody>
</table>

Returns a *jQuery object*.

---

#### `animateToNextChild`

Animates the Roundabout to the next child element.

##### Usage

```javascript
.roundabout("animateToNextChild")
.roundabout("animateToNextChild", callback)
.roundabout("animateToNextChild", duration, easing)
.roundabout("animateToNextChild", duration, easing, callback)
```

##### Parameters

<table class="parameters">
	<tbody>
		<tr>
			<td class="type">integer</td>
			<td class="parameter">
				<code>duration</code> is the length
				of time (in milliseconds) that the animation
				will take to&nbsp;complete; uses Roundabout’s
				configured <code>duration</code> if no value
				is set&nbsp;here
			</td>
		</tr>
		<tr>
			<td class="type">string</td>
			<td class="parameter">
				<code>easing</code> is the name of
				the easing function to use for&nbsp;movement;
				uses Roundabout’s configured <code>easing</code>
				if no value is set&nbsp;here
			</td>
		</tr>
		<tr>
			<td class="type">function</td>
			<td class="parameter">
				<code>callback</code> is a function 
				that is called once the change&nbsp;completes
			</td>
		</tr>
	</tbody>
</table>

Returns a *jQuery object*.
Returns a *jQuery object*.

---

#### `animateToPreviousChild`

Animates the Roundabout to the previous child element.

##### Usage

```javascript
.roundabout("animateToPreviousChild")
.roundabout("animateToPreviousChild", callback)
.roundabout("animateToPreviousChild", duration, easing)
.roundabout("animateToPreviousChild", duration, easing, callback)
```

##### Parameters

<table class="parameters">
	<tbody>
		<tr>
			<td class="type">integer</td>
			<td class="parameter">
				<code>duration</code> is the length
				of time (in milliseconds) that the animation
				will take to&nbsp;complete; uses Roundabout’s
				configured <code>duration</code> if no value
				is set&nbsp;here
			</td>
		</tr>
		<tr>
			<td class="type">string</td>
			<td class="parameter">
				<code>easing</code> is the name of
				the easing function to use for&nbsp;movement;
				uses Roundabout’s configured <code>easing</code>
				if no value is set&nbsp;here
			</td>
		</tr>
		<tr>
			<td class="type">function</td>
			<td class="parameter">
				<code>callback</code> is a function 
				that is called once the change&nbsp;completes
			</td>
		</tr>
	</tbody>
</table>

Returns a *jQuery object*.

---

#### `animateToDelta`

Animates the Roundabout to the given amount of degrees away from its current `bearing` (either positive or negative degrees).

##### Usage

```javascript
.roundabout("animateToDelta", degrees)
.roundabout("animateToDelta", degrees, callback)
.roundabout("animateToDelta", degrees, duration, easing)
.roundabout("animateToDelta", degrees, duration, easing, callback)
```

##### Parameters

<table class="parameters">
	<tbody>
		<tr>
			<td class="type">float</td>
			<td class="parameter">
				<code>degrees</code> is the amount
				by which the <code>bearing</code> will change
				(either positive or&nbsp;negative)
			</td>
		</tr>
		<tr>
			<td class="type">integer</td>
			<td class="parameter">
				<code>duration</code> is the length
				of time (in milliseconds) that the animation
				will take to&nbsp;complete; uses Roundabout’s
				configured <code>duration</code> if no value
				is set&nbsp;here
			</td>
		</tr>
		<tr>
			<td class="type">string</td>
			<td class="parameter">
				<code>easing</code> is the name of
				the easing function to use for&nbsp;movement;
				uses Roundabout’s configured <code>easing</code>
				if no value is set&nbsp;here
			</td>
		</tr>
		<tr>
			<td class="type">function</td>
			<td class="parameter">
				<code>callback</code> is a function 
				that is called once the change&nbsp;completes
			</td>
		</tr>
	</tbody>
</table>

Returns a *jQuery object*.

---

#### `animateBearingToFocus`

Animates the Roundabout so that a given `bearing` ends at the configured `focusBearing`.

##### Usage

```javascript
.roundabout("animateBearingToFocus", degrees)
.roundabout("animateBearingToFocus", degrees, callback)
.roundabout("animateBearingToFocus", degrees, duration, easing)
.roundabout("animateBearingToFocus", degrees, duration, easing, callback)
```

##### Parameters

<table class="parameters">
	<tbody>
		<tr>
			<td class="type">float</td>
			<td class="parameter">
				<code>degrees</code> is a value
				between <code>0.0</code> and <code>359.9</code>
			</td>
		</tr>
		<tr>
			<td class="type">integer</td>
			<td class="parameter">
				<code>duration</code> is the length
				of time (in milliseconds) that the animation
				will take to&nbsp;complete; uses Roundabout’s
				configured <code>duration</code> if no value
				is set&nbsp;here
			</td>
		</tr>
		<tr>
			<td class="type">string</td>
			<td class="parameter">
				<code>easing</code> is the name of
				the easing function to use for&nbsp;movement;
				uses Roundabout’s configured <code>easing</code>
				if no value is set&nbsp;here
			</td>
		</tr>
		<tr>
			<td class="type">function</td>
			<td class="parameter">
				<code>callback</code> is a function 
				that is called once the change&nbsp;completes
			</td>
		</tr>
	</tbody>
</table>

Returns a *jQuery object*.

---

#### `startAutoplay`

Starts the Roundabout’s `autoplay` feature.

##### Usage

```javascript
.roundabout("startAutoplay")
.roundabout("startAutoplay", callback)
```

##### Parameters

<table class="parameters">
	<tbody>
		<tr>
			<td class="type">function</td>
			<td class="parameter">
				<code>callback</code> is a function 
				that is called after each autoplay
				animation&nbsp;completes
			</td>
		</tr>
	</tbody>
</table>

Returns a *jQuery object*.

---

#### `stopAutoplay`

Stops the Roundabout’s `autoplay` feature.

##### Usage

```javascript
.roundabout("stopAutoplay")
.roundabout("stopAutoplay", keepAutoplayBindings)
```

##### Parameters

<table class="parameters">
	<tbody>
		<tr>
			<td class="type">boolean</td>
			<td class="parameter">
				<code>keepAutoplayBindings</code> — when <code>true</code> —
				will not destroy any autoplay <code>mouseenter</code> and <code>mouseleave</code>
				event bindings that were set by <code>autoplayPauseOnHover</code>
			</td>
		</tr>
	</tbody>
</table>

Returns a *jQuery object*.

---

#### `toggleAutoplay`

Starts or stops the Roundabout’s `autoplay` feature (based upon its current state).

##### Usage

```javascript
.roundabout("toggleAutoplay")
.roundabout("toggleAutoplay", callback)
```

##### Parameters

<table class="parameters">
	<tbody>
		<tr>
			<td class="type">function</td>
			<td class="parameter">
				<code>callback</code> is a function 
				that is called after each autoplay
				animation&nbsp;completes
			</td>
		</tr>
	</tbody>
</table>

Returns a *jQuery object*.

---

#### `isAutoplaying`

Checks to see if the Roundabout’s `autoplay` feature is currently playing or not.

##### Usage

```javascript
.roundabout("isAutoplaying")
```

##### Parameters

*No parameters.*

Returns a *boolean*.

---

#### `changeAutoplayDuration`

Changes the length of time (in milliseconds) that the Roundabout’s `autoplay` feature waits between attempts to animate to the next child.

##### Usage

```javascript
.roundabout("changeAutoplayDuration", duration)
```

##### Parameters

<table class="parameters">
	<tbody>
		<tr>
			<td class="type">integer</td>
			<td class="parameter">
				<code>duration</code> is a length of
				time (in milliseconds) between attempts to have
				autoplay animate to the next child element
			</td>
		</tr>
	</tbody>
</table>

Returns a *jQuery object*.

---

#### `relayoutChildren`

Repositions child elements based on new contextual information. This is most helpful when the Roundabout element itself changes size and moving child elements within need readjusting.

##### Usage

```javascript
.roundabout("relayoutChildren")
```

##### Parameters

*No parameters.*

Returns a *jQuery object*.

---

#### `getNearestChild`

Gets the nearest child element to the `focusBearing`. This number is a zero-based counter based on order of markup.

##### Usage

```javascript
.roundabout("getNearestChild")
```

##### Parameters

*No parameters.*

Returns a *integer*.

---

#### `getChildInFocus`

Gets the child currently in focus. This number is a zero-based counter based on order of markup.

##### Usage

```javascript
.roundabout("getChildInFocus")
```

##### Parameters

*No parameters.*

Returns a *integer*.


### Hookable Events

Roundabout is equipped to trigger events on both the Roundabout element itself and the moving child elements.

#### `ready`

This event fires on the Roundabout element once it and its child elements have been initialized. It also fires on each child element once it has been initialized.

#### `focus`

This event fires on child elements that land in the `focusBearing` at the end of an animation. Will only fire if `triggerFocusEvents` is set to `true`.

#### `blur`

This event fires on child elements that move away from the `focusBearing` at the start of an animation. Will only fire if `triggerBlurEvents` is set to `true`.

#### `childrenUpdated`

This event fires on the Roundabout element when its child elements have been repositioned and are in place.

#### `reposition`

This event fires on child elements that have been repositioned and are in place.

#### `bearingSet`

This event fires on the Roundabout element when its `bearing` has been set.

#### `moveClockwiseThroughBack`

This event fires on moving child elements when an animation causes them pass through the point that is opposite (or 180°) from the `focusBearing` in a clockwise motion.

#### `moveCounterclockwiseThroughBack`

This event fires on moving child elements when an animation causes them to pass through the point that is opposite (or 180°) from the `focusBearing` in a counterclockwise motion.

#### `animationStart`

This event fires on the Roundabout element at the start of any animation.

#### `animationEnd`

This event fires on the Roundabout element at the end of any animation.

#### `autoplayStart`

This event fires on the Roundabout element when the `autoplay` feature starts.

#### `autoplayStop`

This event fires on the Roundabout element when the `autoplay` feature stops.

================================================
FILE: jquery.roundabout.js
================================================
/**
 * jQuery Roundabout - v2.4.2
 * http://fredhq.com/projects/roundabout
 *
 * Moves list-items of enabled ordered and unordered lists long
 * a chosen path. Includes the default "lazySusan" path, that
 * moves items long a spinning turntable.
 *
 * Terms of Use // jQuery Roundabout
 *
 * Open source under the BSD license
 *
 * Copyright (c) 2011-2012, Fred LeBlanc
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   - Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   - Neither the name of the author nor the names of its contributors
 *     may be used to endorse or promote products derived from this
 *     software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
(function($) {
	"use strict";
	
	var defaults, internalData, methods;

	// add default shape
	$.extend({
		roundaboutShapes: {
			def: "lazySusan",
			lazySusan: function (r, a, t) {
				return {
					x: Math.sin(r + a),
					y: (Math.sin(r + 3 * Math.PI / 2 + a) / 8) * t,
					z: (Math.cos(r + a) + 1) / 2,
					scale: (Math.sin(r + Math.PI / 2 + a) / 2) + 0.5
				};
			}
		}
	});

	defaults = {
		bearing: 0.0,
		tilt: 0.0,
		minZ: 100,
		maxZ: 280,
		minOpacity: 0.4,
		maxOpacity: 1.0,
		minScale: 0.4,
		maxScale: 1.0,
		duration: 600,
		btnNext: null,
		btnNextCallback: function() {},
		btnPrev: null,
		btnPrevCallback: function() {},
		btnToggleAutoplay: null,
		btnStartAutoplay: null,
		btnStopAutoplay: null,
		easing: "swing",
		clickToFocus: true,
		clickToFocusCallback: function() {},
		focusBearing: 0.0,
		shape: "lazySusan",
		debug: false,
		childSelector: "li",
		startingChild: null,
		reflect: false,
		floatComparisonThreshold: 0.001,
		autoplay: false,
		autoplayDuration: 1000,
		autoplayPauseOnHover: false,
		autoplayCallback: function() {},
		autoplayInitialDelay: 0,
		enableDrag: false,
		dropDuration: 600,
		dropEasing: "swing",
		dropAnimateTo: "nearest",
		dropCallback: function() {},
		dragAxis: "x",
		dragFactor: 4,
		triggerFocusEvents: true,
		triggerBlurEvents: true,
		responsive: false
	};

	internalData = {
		autoplayInterval: null,
		autoplayIsRunning: false,
		autoplayStartTimeout: null,
		animating: false,
		childInFocus: -1,
		touchMoveStartPosition: null,
		stopAnimation: false,
		lastAnimationStep: false
	};

	methods = {

		// starters
		// -----------------------------------------------------------------------

		// init
		// starts up roundabout
		init: function(options, callback, relayout) {
			var settings,
			    now = (new Date()).getTime();

			options   = (typeof options === "object") ? options : {};
			callback  = ($.isFunction(callback)) ? callback : function() {};
			callback  = ($.isFunction(options)) ? options : callback;
			settings  = $.extend({}, defaults, options, internalData);

			return this
				.each(function() {
					// make options
					var self = $(this),
					    childCount = self.children(settings.childSelector).length,
					    period = 360.0 / childCount,
					    startingChild = (settings.startingChild && settings.startingChild > (childCount - 1)) ? (childCount - 1) : settings.startingChild,
					    startBearing = (settings.startingChild === null) ? settings.bearing : 360 - (startingChild * period),
					    holderCSSPosition = (self.css("position") !== "static") ? self.css("position") : "relative";

					self
						.css({  // starting styles
							padding:   0,
							position:  holderCSSPosition
						})
						.addClass("roundabout-holder")
						.data(  // starting options
							"roundabout",
							$.extend(
								{},
								settings,
								{
									startingChild: startingChild,
									bearing: startBearing,
									oppositeOfFocusBearing: methods.normalize.apply(null, [settings.focusBearing - 180]),
									dragBearing: startBearing,
									period: period
								}
							)
						);

					// unbind any events that we set if we're relaying out
					if (relayout) {
						self
							.unbind(".roundabout")
							.children(settings.childSelector)
								.unbind(".roundabout");
					} else {
						// bind responsive action
						if (settings.responsive) {
							$(window).bind("resize", function() {
								methods.stopAutoplay.apply(self);
								methods.relayoutChildren.apply(self);
							});
						}
					}

					// bind click-to-focus
					if (settings.clickToFocus) {
						self
							.children(settings.childSelector)
							.each(function(i) {
								$(this)
									.bind("click.roundabout", function() {
										var degrees = methods.getPlacement.apply(self, [i]);

										if (!methods.isInFocus.apply(self, [degrees])) {
											methods.stopAnimation.apply($(this));
											if (!self.data("roundabout").animating) {
												methods.animateBearingToFocus.apply(self, [degrees, self.data("roundabout").clickToFocusCallback]);
											}
											return false;
										}
									});
							});
					}

					// bind next buttons
					if (settings.btnNext) {
						$(settings.btnNext)
							.bind("click.roundabout", function() {
								if (!self.data("roundabout").animating) {
									methods.animateToNextChild.apply(self, [self.data("roundabout").btnNextCallback]);
								}
								return false;
							});
					}

					// bind previous buttons
					if (settings.btnPrev) {
						$(settings.btnPrev)
							.bind("click.roundabout", function() {
								methods.animateToPreviousChild.apply(self, [self.data("roundabout").btnPrevCallback]);
								return false;
							});
					}

					// bind toggle autoplay buttons
					if (settings.btnToggleAutoplay) {
						$(settings.btnToggleAutoplay)
							.bind("click.roundabout", function() {
								methods.toggleAutoplay.apply(self);
								return false;
							});
					}

					// bind start autoplay buttons
					if (settings.btnStartAutoplay) {
						$(settings.btnStartAutoplay)
							.bind("click.roundabout", function() {
								methods.startAutoplay.apply(self);
								return false;
							});
					}

					// bind stop autoplay buttons
					if (settings.btnStopAutoplay) {
						$(settings.btnStopAutoplay)
							.bind("click.roundabout", function() {
								methods.stopAutoplay.apply(self);
								return false;
							});
					}

					// autoplay pause on hover
					if (settings.autoplayPauseOnHover) {
						self
							.bind("mouseenter.roundabout.autoplay", function() {
								methods.stopAutoplay.apply(self, [true]);
							})
							.bind("mouseleave.roundabout.autoplay", function() {
								methods.startAutoplay.apply(self);
							});
					}

					// drag and drop
					if (settings.enableDrag) {
						// on screen
						if (!$.isFunction(self.drag)) {
							if (settings.debug) {
								alert("You do not have the drag plugin loaded.");
							}
						} else if (!$.isFunction(self.drop)) {
							if (settings.debug) {
								alert("You do not have the drop plugin loaded.");
							}
						} else {
							self
								.drag(function(e, properties) {
									var data = self.data("roundabout"),
									    delta = (data.dragAxis.toLowerCase() === "x") ? "deltaX" : "deltaY";
									methods.stopAnimation.apply(self);
									methods.setBearing.apply(self, [data.dragBearing + properties[delta] / data.dragFactor]);
								})
								.drop(function(e) {
									var data = self.data("roundabout"),
									    method = methods.getAnimateToMethod(data.dropAnimateTo);
									methods.allowAnimation.apply(self);
									methods[method].apply(self, [data.dropDuration, data.dropEasing, data.dropCallback]);
									data.dragBearing = data.period * methods.getNearestChild.apply(self);
								});
						}

						// on mobile
						self
							.each(function() {
								var element = $(this).get(0),
								    data = $(this).data("roundabout"),
								    page = (data.dragAxis.toLowerCase() === "x") ? "pageX" : "pageY",
								    method = methods.getAnimateToMethod(data.dropAnimateTo);

								// some versions of IE don't like this
								if (element.addEventListener) {
									element.addEventListener("touchstart", function(e) {
										data.touchMoveStartPosition = e.touches[0][page];
									}, false);

									element.addEventListener("touchmove", function(e) {
										var delta = (e.touches[0][page] - data.touchMoveStartPosition) / data.dragFactor;
										e.preventDefault();
										methods.stopAnimation.apply($(this));
										methods.setBearing.apply($(this), [data.dragBearing + delta]);
									}, false);

									element.addEventListener("touchend", function(e) {
										e.preventDefault();
										methods.allowAnimation.apply($(this));
										method = methods.getAnimateToMethod(data.dropAnimateTo);
										methods[method].apply($(this), [data.dropDuration, data.dropEasing, data.dropCallback]);
										data.dragBearing = data.period * methods.getNearestChild.apply($(this));
									}, false);
								}
							});
					}

					// start children
					methods.initChildren.apply(self, [callback, relayout]);
				});
		},


		// initChildren
		// applys settings to child elements, starts roundabout
		initChildren: function(callback, relayout) {
			var self = $(this),
			    data = self.data("roundabout");

			callback = callback || function() {};
			
			self.children(data.childSelector).each(function(i) {
				var startWidth, startHeight, startFontSize,
				    degrees = methods.getPlacement.apply(self, [i]);

				// on relayout, grab these values from current data
				if (relayout && $(this).data("roundabout")) {
					startWidth = $(this).data("roundabout").startWidth;
					startHeight = $(this).data("roundabout").startHeight;
					startFontSize = $(this).data("roundabout").startFontSize;
				}

				// apply classes and css first
				$(this)
					.addClass("roundabout-moveable-item")
					.css("position", "absolute");

				// now measure
				$(this)
					.data(
						"roundabout",
						{
							startWidth: startWidth || $(this).width(),
							startHeight: startHeight || $(this).height(),
							startFontSize: startFontSize || parseInt($(this).css("font-size"), 10),
							degrees: degrees,
							backDegrees: methods.normalize.apply(null, [degrees - 180]),
							childNumber: i,
							currentScale: 1,
							parent: self
						}
					);
			});

			methods.updateChildren.apply(self);

			// start autoplay if necessary
			if (data.autoplay) {
				data.autoplayStartTimeout = setTimeout(function() {
					methods.startAutoplay.apply(self);
				}, data.autoplayInitialDelay);
			}

			self.trigger('ready');
			callback.apply(self);
			return self;
		},



		// positioning
		// -----------------------------------------------------------------------

		// updateChildren
		// move children elements into their proper locations
		updateChildren: function() {
			return this
				.each(function() {
					var self = $(this),
					    data = self.data("roundabout"),
					    inFocus = -1,
					    info = {
							bearing: data.bearing,
							tilt: data.tilt,
							stage: {
								width: Math.floor($(this).width() * 0.9),
								height: Math.floor($(this).height() * 0.9)
							},
							animating: data.animating,
							inFocus: data.childInFocus,
							focusBearingRadian: methods.degToRad.apply(null, [data.focusBearing]),
							shape: $.roundaboutShapes[data.shape] || $.roundaboutShapes[$.roundaboutShapes.def]
					    };

					// calculations
					info.midStage = {
						width: info.stage.width / 2,
						height: info.stage.height / 2
					};

					info.nudge = {
						width: info.midStage.width + (info.stage.width * 0.05),
						height: info.midStage.height + (info.stage.height * 0.05)
					};

					info.zValues = {
						min: data.minZ,
						max: data.maxZ,
						diff: data.maxZ - data.minZ
					};

					info.opacity = {
						min: data.minOpacity,
						max: data.maxOpacity,
						diff: data.maxOpacity - data.minOpacity
					};

					info.scale = {
						min: data.minScale,
						max: data.maxScale,
						diff: data.maxScale - data.minScale
					};

					// update child positions
					self.children(data.childSelector)
						.each(function(i) {
							if (methods.updateChild.apply(self, [$(this), info, i, function() { $(this).trigger('ready'); }]) && (!info.animating || data.lastAnimationStep)) {
								inFocus = i;
								$(this).addClass("roundabout-in-focus");
							} else {
								$(this).removeClass("roundabout-in-focus");
							}
						});

					if (inFocus !== info.inFocus) {
						// blur old child
						if (data.triggerBlurEvents) {
							self.children(data.childSelector)
								.eq(info.inFocus)
									.trigger("blur");
						}

						data.childInFocus = inFocus;

						if (data.triggerFocusEvents && inFocus !== -1) {
							// focus new child
							self.children(data.childSelector)
								.eq(inFocus)
									.trigger("focus");
						}
					}

					self.trigger("childrenUpdated");
				});
		},


		// updateChild
		// repositions a child element into its new position
		updateChild: function(childElement, info, childPos, callback) {
			var factors,
			    self = this,
			    child = $(childElement),
			    data = child.data("roundabout"),
			    out = [],
			    rad = methods.degToRad.apply(null, [(360.0 - data.degrees) + info.bearing]);

			callback = callback || function() {};

			// adjust radians to be between 0 and Math.PI * 2
			rad = methods.normalizeRad.apply(null, [rad]);

			// get factors from shape
			factors = info.shape(rad, info.focusBearingRadian, info.tilt);

			// correct
			factors.scale = (factors.scale > 1) ? 1 : factors.scale;
			factors.adjustedScale = (info.scale.min + (info.scale.diff * factors.scale)).toFixed(4);
			factors.width = (factors.adjustedScale * data.startWidth).toFixed(4);
			factors.height = (factors.adjustedScale * data.startHeight).toFixed(4);

			// update item
			child
				.css({
					left: ((factors.x * info.midStage.width + info.nudge.width) - factors.width / 2.0).toFixed(0) + "px",
					top: ((factors.y * info.midStage.height + info.nudge.height) - factors.height / 2.0).toFixed(0) + "px",
					width: factors.width + "px",
					height: factors.height + "px",
					opacity: (info.opacity.min + (info.opacity.diff * factors.scale)).toFixed(2),
					zIndex: Math.round(info.zValues.min + (info.zValues.diff * factors.z)),
					fontSize: (factors.adjustedScale * data.startFontSize).toFixed(1) + "px"
				});
			data.currentScale = factors.adjustedScale;

			// for debugging purposes
			if (self.data("roundabout").debug) {
				out.push("<div style=\"font-weight: normal; font-size: 10px; padding: 2px; width: " + child.css("width") + "; background-color: #ffc;\">");
				out.push("<strong style=\"font-size: 12px; white-space: nowrap;\">Child " + childPos + "</strong><br />");
				out.push("<strong>left:</strong> " + child.css("left") + "<br />");
				out.push("<strong>top:</strong> " + child.css("top") + "<br />");
				out.push("<strong>width:</strong> " + child.css("width") + "<br />");
				out.push("<strong>opacity:</strong> " + child.css("opacity") + "<br />");
				out.push("<strong>height:</strong> " + child.css("height") + "<br />");
				out.push("<strong>z-index:</strong> " + child.css("z-index") + "<br />");
				out.push("<strong>font-size:</strong> " + child.css("font-size") + "<br />");
				out.push("<strong>scale:</strong> " + child.data("roundabout").currentScale);
				out.push("</div>");

				child.html(out.join(""));
			}

			// trigger event
			child.trigger("reposition");
			
			// callback
			callback.apply(self);

			return methods.isInFocus.apply(self, [data.degrees]);
		},



		// manipulation
		// -----------------------------------------------------------------------

		// setBearing
		// changes the bearing of the roundabout
		setBearing: function(bearing, callback) {
			callback = callback || function() {};
			bearing = methods.normalize.apply(null, [bearing]);

			this
				.each(function() {
					var diff, lowerValue, higherValue,
					    self = $(this),
					    data = self.data("roundabout"),
					    oldBearing = data.bearing;

					// set bearing
					data.bearing = bearing;
					self.trigger("bearingSet");
					methods.updateChildren.apply(self);

					// not animating? we're done here
					diff = Math.abs(oldBearing - bearing);
					if (!data.animating || diff > 180) {
						return;
					}

					// check to see if any of the children went through the back
					diff = Math.abs(oldBearing - bearing);
					self.children(data.childSelector).each(function(i) {
						var eventType;

						if (methods.isChildBackDegreesBetween.apply($(this), [bearing, oldBearing])) {
							eventType = (oldBearing > bearing) ? "Clockwise" : "Counterclockwise";
							$(this).trigger("move" + eventType + "ThroughBack");
						}
					});
				});

			// call callback if one was given
			callback.apply(this);
			return this;
		},


		// adjustBearing
		// change the bearing of the roundabout by a given degree
		adjustBearing: function(delta, callback) {
			callback = callback || function() {};
			if (delta === 0) {
				return this;
			}

			this
				.each(function() {
					methods.setBearing.apply($(this), [$(this).data("roundabout").bearing + delta]);
				});

			callback.apply(this);
			return this;
		},


		// setTilt
		// changes the tilt of the roundabout
		setTilt: function(tilt, callback) {
			callback = callback || function() {};

			this
				.each(function() {
					$(this).data("roundabout").tilt = tilt;
					methods.updateChildren.apply($(this));
				});

			// call callback if one was given
			callback.apply(this);
			return this;
		},


		// adjustTilt
		// changes the tilt of the roundabout
		adjustTilt: function(delta, callback) {
			callback = callback || function() {};

			this
				.each(function() {
					methods.setTilt.apply($(this), [$(this).data("roundabout").tilt + delta]);
				});

			callback.apply(this);
			return this;
		},



		// animation
		// -----------------------------------------------------------------------

		// animateToBearing
		// animates the roundabout to a given bearing, all animations come through here
		animateToBearing: function(bearing, duration, easing, passedData, callback) {
			var now = (new Date()).getTime();

			callback = callback || function() {};

			// find callback function in arguments
			if ($.isFunction(passedData)) {
				callback = passedData;
				passedData = null;
			} else if ($.isFunction(easing)) {
				callback = easing;
				easing = null;
			} else if ($.isFunction(duration)) {
				callback = duration;
				duration = null;
			}

			this
				.each(function() {
					var timer, easingFn, newBearing,
					    self = $(this),
					    data = self.data("roundabout"),
					    thisDuration = (!duration) ? data.duration : duration,
					    thisEasingType = (easing) ? easing : data.easing || "swing";

					// is this your first time?
					if (!passedData) {
						passedData = {
							timerStart: now,
							start: data.bearing,
							totalTime: thisDuration
						};
					}

					// update the timer
					timer = now - passedData.timerStart;

					if (data.stopAnimation) {
						methods.allowAnimation.apply(self);
						data.animating = false;
						return;
					}

					// we need to animate more
					if (timer < thisDuration) {
						if (!data.animating) {
							self.trigger("animationStart");
						}

						data.animating = true;

						if (typeof $.easing.def === "string") {
							easingFn = $.easing[thisEasingType] || $.easing[$.easing.def];
							newBearing = easingFn(null, timer, passedData.start, bearing - passedData.start, passedData.totalTime);
						} else {
							newBearing = $.easing[thisEasingType]((timer / passedData.totalTime), timer, passedData.start, bearing - passedData.start, passedData.totalTime);
						}

						// fixes issue #24, animation changed as of jQuery 1.7.2
						// also addresses issue #29, using easing breaks "linear"
						if (methods.compareVersions.apply(null, [$().jquery, "1.7.2"]) >= 0 && !($.easing["easeOutBack"])) {
							newBearing = passedData.start + ((bearing - passedData.start) * newBearing);
						}

						newBearing = methods.normalize.apply(null, [newBearing]);
						data.dragBearing = newBearing;

						methods.setBearing.apply(self, [newBearing, function() {
							setTimeout(function() {  // done with a timeout so that each step is displayed
								methods.animateToBearing.apply(self, [bearing, thisDuration, thisEasingType, passedData, callback]);
							}, 0);
						}]);

					// we're done animating
					} else {
						data.lastAnimationStep = true;

						bearing = methods.normalize.apply(null, [bearing]);
						methods.setBearing.apply(self, [bearing, function() {
							self.trigger("animationEnd");
						}]);
						data.animating = false;
						data.lastAnimationStep = false;
						data.dragBearing = bearing;

						callback.apply(self);
					}
				});

			return this;
		},


		// animateToNearbyChild
		// animates roundabout to a nearby child
		animateToNearbyChild: function(passedArgs, which) {
			var duration = passedArgs[0],
			    easing = passedArgs[1],
			    callback = passedArgs[2] || function() {};

			// find callback
			if ($.isFunction(easing)) {
				callback = easing;
				easing = null;
			} else if ($.isFunction(duration)) {
				callback = duration;
				duration = null;
			}

			return this
				.each(function() {
					var j, range,
					    self = $(this),
					    data = self.data("roundabout"),
					    bearing = (!data.reflect) ? data.bearing % 360 : data.bearing,
					    length = self.children(data.childSelector).length;

					if (!data.animating) {
						// reflecting, not moving to previous || not reflecting, moving to next
						if ((data.reflect && which === "previous") || (!data.reflect && which === "next")) {
							// slightly adjust for rounding issues
							bearing = (Math.abs(bearing) < data.floatComparisonThreshold) ? 360 : bearing;

							// clockwise
							for (j = 0; j < length; j += 1) {
								range = {
									lower: (data.period * j),
									upper: (data.period * (j + 1))
								};
								range.upper = (j === length - 1) ? 360 : range.upper;

								if (bearing <= Math.ceil(range.upper) && bearing >= Math.floor(range.lower)) {
									if (length === 2 && bearing === 360) {
										methods.animateToDelta.apply(self, [-180, duration, easing, callback]);
									} else {
										methods.animateBearingToFocus.apply(self, [range.lower, duration, easing, callback]);
									}
									break;
								}
							}
						} else {
							// slightly adjust for rounding issues
							bearing = (Math.abs(bearing) < data.floatComparisonThreshold || 360 - Math.abs(bearing) < data.floatComparisonThreshold) ? 0 : bearing;

							// counterclockwise
							for (j = length - 1; j >= 0; j -= 1) {
								range = {
									lower: data.period * j,
									upper: data.period * (j + 1)
								};
								range.upper = (j === length - 1) ? 360 : range.upper;

								if (bearing >= Math.floor(range.lower) && bearing < Math.ceil(range.upper)) {
									if (length === 2 && bearing === 360) {
										methods.animateToDelta.apply(self, [180, duration, easing, callback]);
									} else {
										methods.animateBearingToFocus.apply(self, [range.upper, duration, easing, callback]);
									}
									break;
								}
							}
						}
					}
				});
		},


		// animateToNearestChild
		// animates roundabout to the nearest child
		animateToNearestChild: function(duration, easing, callback) {
			callback = callback || function() {};

			// find callback
			if ($.isFunction(easing)) {
				callback = easing;
				easing = null;
			} else if ($.isFunction(duration)) {
				callback = duration;
				duration = null;
			}

			return this
				.each(function() {
					var nearest = methods.getNearestChild.apply($(this));
					methods.animateToChild.apply($(this), [nearest, duration, easing, callback]);
				});
		},


		// animateToChild
		// animates roundabout to a given child position
		animateToChild: function(childPosition, duration, easing, callback) {
			callback = callback || function() {};

			// find callback
			if ($.isFunction(easing)) {
				callback = easing;
				easing = null;
			} else if ($.isFunction(duration)) {
				callback = duration;
				duration = null;
			}

			return this
				.each(function() {
					var child,
					    self = $(this),
					    data = self.data("roundabout");

					if (data.childInFocus !== childPosition && !data.animating) {
						child = self.children(data.childSelector).eq(childPosition);
						methods.animateBearingToFocus.apply(self, [child.data("roundabout").degrees, duration, easing, callback]);
					}
				});
		},


		// animateToNextChild
		// animates roundabout to the next child
		animateToNextChild: function(duration, easing, callback) {
			return methods.animateToNearbyChild.apply(this, [arguments, "next"]);
		},


		// animateToPreviousChild
		// animates roundabout to the preious child
		animateToPreviousChild: function(duration, easing, callback) {
			return methods.animateToNearbyChild.apply(this, [arguments, "previous"]);
		},


		// animateToDelta
		// animates roundabout to a given delta (in degrees)
		animateToDelta: function(degrees, duration, easing, callback) {
			callback = callback || function() {};

			// find callback
			if ($.isFunction(easing)) {
				callback = easing;
				easing = null;
			} else if ($.isFunction(duration)) {
				callback = duration;
				duration = null;
			}

			return this
				.each(function() {
					var delta = $(this).data("roundabout").bearing + degrees;
					methods.animateToBearing.apply($(this), [delta, duration, easing, callback]);
				});
		},


		// animateBearingToFocus
		// animates roundabout to bring a given angle into focus
		animateBearingToFocus: function(degrees, duration, easing, callback) {
			callback = callback || function() {};

			// find callback
			if ($.isFunction(easing)) {
				callback = easing;
				easing = null;
			} else if ($.isFunction(duration)) {
				callback = duration;
				duration = null;
			}

			return this
				.each(function() {
					var delta = $(this).data("roundabout").bearing - degrees;
					delta = (Math.abs(360 - delta) < Math.abs(delta)) ? 360 - delta : -delta;
					delta = (delta > 180) ? -(360 - delta) : delta;

					if (delta !== 0) {
						methods.animateToDelta.apply($(this), [delta, duration, easing, callback]);
					}
				});
		},


		// stopAnimation
		// if an animation is currently in progress, stop it
		stopAnimation: function() {
			return this
				.each(function() {
					$(this).data("roundabout").stopAnimation = true;
				});
		},


		// allowAnimation
		// clears the stop-animation hold placed by stopAnimation
		allowAnimation: function() {
			return this
				.each(function() {
					$(this).data("roundabout").stopAnimation = false;
				});
		},



		// autoplay
		// -----------------------------------------------------------------------

		// startAutoplay
		// starts autoplaying this roundabout
		startAutoplay: function(callback) {
			return this
				.each(function() {
					var self = $(this),
					    data = self.data("roundabout");

					callback = callback || data.autoplayCallback || function() {};

					clearInterval(data.autoplayInterval);
					data.autoplayInterval = setInterval(function() {
						methods.animateToNextChild.apply(self, [callback]);
					}, data.autoplayDuration);
					data.autoplayIsRunning = true;
					
					self.trigger("autoplayStart");
				});
		},


		// stopAutoplay
		// stops autoplaying this roundabout
		stopAutoplay: function(keepAutoplayBindings) {
			return this
				.each(function() {
					clearInterval($(this).data("roundabout").autoplayInterval);
					$(this).data("roundabout").autoplayInterval = null;
					$(this).data("roundabout").autoplayIsRunning = false;
					
					// this will prevent autoplayPauseOnHover from restarting autoplay
					if (!keepAutoplayBindings) {
						$(this).unbind(".autoplay");
					}
					
					$(this).trigger("autoplayStop");
				});
		},
		
		
		// toggleAutoplay
		// toggles autoplay pause/resume
		toggleAutoplay: function(callback) {
			return this
				.each(function() {
					var self = $(this),
					    data = self.data("roundabout");

					callback = callback || data.autoplayCallback || function() {};

					if (!methods.isAutoplaying.apply($(this))) {
						methods.startAutoplay.apply($(this), [callback]);
					} else {
						methods.stopAutoplay.apply($(this), [callback]);
					}
				});
		},


		// isAutoplaying
		// is this roundabout currently autoplaying?
		isAutoplaying: function() {
			return (this.data("roundabout").autoplayIsRunning);
		},


		// changeAutoplayDuration
		// stops the autoplay, changes the duration, restarts autoplay
		changeAutoplayDuration: function(duration) {
			return this
				.each(function() {
					var self = $(this),
					    data = self.data("roundabout");

					data.autoplayDuration = duration;

					if (methods.isAutoplaying.apply(self)) {
						methods.stopAutoplay.apply(self);
						setTimeout(function() {
							methods.startAutoplay.apply(self);
						}, 10);
					}
				});
		},



		// helpers
		// -----------------------------------------------------------------------

		// normalize
		// regulates degrees to be >= 0.0 and < 360
		normalize: function(degrees) {
			var inRange = degrees % 360.0;
			return (inRange < 0) ? 360 + inRange : inRange;
		},


		// normalizeRad
		// regulates radians to be >= 0 and < Math.PI * 2
		normalizeRad: function(radians) {
			while (radians < 0) {
				radians += (Math.PI * 2);
			}

			while (radians > (Math.PI * 2)) {
				radians -= (Math.PI * 2);
			}

			return radians;
		},


		// isChildBackDegreesBetween
		// checks that a given child's backDegrees is between two values
		isChildBackDegreesBetween: function(value1, value2) {
			var backDegrees = $(this).data("roundabout").backDegrees;

			if (value1 > value2) {
				return (backDegrees >= value2 && backDegrees < value1);
			} else {
				return (backDegrees < value2 && backDegrees >= value1);
			}
		},


		// getAnimateToMethod
		// takes a user-entered option and maps it to an animation method
		getAnimateToMethod: function(effect) {
			effect = effect.toLowerCase();

			if (effect === "next") {
				return "animateToNextChild";
			} else if (effect === "previous") {
				return "animateToPreviousChild";
			}

			// default selection
			return "animateToNearestChild";
		},
		
		
		// relayoutChildren
		// lays out children again with new contextual information
		relayoutChildren: function() {
			return this
				.each(function() {
					var self = $(this),
					    settings = $.extend({}, self.data("roundabout"));

					settings.startingChild = self.data("roundabout").childInFocus;
					methods.init.apply(self, [settings, null, true]);
				});
		},


		// getNearestChild
		// gets the nearest child from the current bearing
		getNearestChild: function() {
			var self = $(this),
			    data = self.data("roundabout"),
			    length = self.children(data.childSelector).length;

			if (!data.reflect) {
				return ((length) - (Math.round(data.bearing / data.period) % length)) % length;
			} else {
				return (Math.round(data.bearing / data.period) % length);
			}
		},


		// degToRad
		// converts degrees to radians
		degToRad: function(degrees) {
			return methods.normalize.apply(null, [degrees]) * Math.PI / 180.0;
		},


		// getPlacement
		// returns the starting degree for a given child
		getPlacement: function(child) {
			var data = this.data("roundabout");
			return (!data.reflect) ? 360.0 - (data.period * child) : data.period * child;
		},


		// isInFocus
		// is this roundabout currently in focus?
		isInFocus: function(degrees) {
			var diff,
			    self = this,
			    data = self.data("roundabout"),
			    bearing = methods.normalize.apply(null, [data.bearing]);

			degrees = methods.normalize.apply(null, [degrees]);
			diff = Math.abs(bearing - degrees);

			// this calculation gives a bit of room for javascript float rounding
			// errors, it looks on both 0deg and 360deg ends of the spectrum
			return (diff <= data.floatComparisonThreshold || diff >= 360 - data.floatComparisonThreshold);
		},
		
		
		// getChildInFocus
		// returns the current child in focus, or false if none are in focus
		getChildInFocus: function() {
			var data = $(this).data("roundabout");
			
			return (data.childInFocus > -1) ? data.childInFocus : false;
		},


		// compareVersions
		// compares a given version string with another
		compareVersions: function(baseVersion, compareVersion) {
			var i,
			    base = baseVersion.split(/\./i),
			    compare = compareVersion.split(/\./i),
			    maxVersionSegmentLength = (base.length > compare.length) ? base.length : compare.length;

			for (i = 0; i <= maxVersionSegmentLength; i++) {
				if (base[i] && !compare[i] && parseInt(base[i], 10) !== 0) {
					// base is higher
					return 1;
				} else if (compare[i] && !base[i] && parseInt(compare[i], 10) !== 0) {
					// compare is higher
					return -1;
				} else if (base[i] === compare[i]) {
					// these are the same, next
					continue;
				}

				if (base[i] && compare[i]) {
					if (parseInt(base[i], 10) > parseInt(compare[i], 10)) {
						// base is higher
						return 1;
					} else {
						// compare is higher
						return -1;
					}
				}
			}

			// nothing was triggered, versions are the same
			return 0;
		}
	};


	// start the plugin
	$.fn.roundabout = function(method) {
		if (methods[method]) {
			return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
		} else if (typeof method === "object" || $.isFunction(method) || !method) {
			return methods.init.apply(this, arguments);
		} else {
			$.error("Method " + method + " does not exist for jQuery.roundabout.");
		}
	};
})(jQuery);
Download .txt
gitextract_6h2mdl76/

├── README.md
└── jquery.roundabout.js
Condensed preview — 2 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (82K chars).
[
  {
    "path": "README.md",
    "chars": 36525,
    "preview": "# Roundabout\n\n**Note: Roundabout is no longer under active development. I've moved the documentation over here to suppor"
  },
  {
    "path": "jquery.roundabout.js",
    "chars": 34963,
    "preview": "/**\n * jQuery Roundabout - v2.4.2\n * http://fredhq.com/projects/roundabout\n *\n * Moves list-items of enabled ordered and"
  }
]

About this extraction

This page contains the full source code of the fredleblanc/roundabout GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 2 files (69.8 KB), approximately 19.3k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!