Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
(function($){
/*
* jMerrygoround jQuery Plugin version 1.0
* http://lab.hisasann.com/jmerrygoround/
*
* Copyright (c) 2009 hisasann http://hisasann.com/
* Dual licensed under the MIT and GPL licenses.
*/
var
// 画像ロケーション情報
offset = [],
// オプション
options = {
radiusX: 200, // Radius X point
radiusY: 30, // Radius Y point
centerX: 250, // Position adjustment left
centerY: 100, // Position adjustment top
width: 140, // Image height
height: 100, // Image width
action: "click", // Animation action
motion: "normal", // Click action motion
duration: 800, // Easing speed
easing: "swing", // Animation type
nextId: "#next", // Next button element id
prevId: "#prev", // Prev button element id
targetElem: "img", // Merrygoround target element
reflection: false // Reflection flag
},
// Merrygoroundさせたいエレメント
$imgs,
// Merrygoround対象のエレメントを持つ親オブジェクト
$this;
$.jMerrygoround = function(targetId, opts){
$.extend(options, opts);
$imgs = $(targetId).find(options.targetElem);
$this = $(targetId);
setup();
}
$.fn.jMerrygoround = function(opts){
$.extend(options, opts);
$imgs = $(this).find(options.targetElem);
$this = $(this);
setup();
}
// Setup!!
function setup() {
// リフレクション画像の表示枠
if(options.reflection)
$this.append("<div id='reflection'></div>");
// フラッシュ
(options.targetElem == "img" ?
$($imgs).fadeIn(500) :
$($imgs).find("img").fadeIn(500));
$($imgs).each(function(index){
// id指定
$(this).attr("id", "img" + index);
// 画像のポジションを計算します
slider(index, $(this), true, false);
// リフレクション画像の作成
createReflector(options.targetElem == "img" ?
$(this)[0] :
$(this).find("img")[0], $(this).attr("id"), offset[index]);
});
// actionに合わせたイベント指定
$.fn.jMerrygoround[options.action]();
}
var speed = 0;
function slider(index, elem, isBuff, isSpeedup){
var numSlots = $($imgs).size(),
_a, _t, _l, _s, _h, _w, zindex, opacity;
_a = index * ((Math.PI * 2) / numSlots);
if(isSpeedup)
_a += speed;
_t = Math.sin(_a) * options.radiusY + options.centerY;
_l = Math.cos(_a) * options.radiusX + options.centerX;
_s = (_t / ((options.centerY) + options.radiusY));
_w = elem.width() * (options.width / elem.width());
_h = elem.height() * (options.height / elem.height());
zindex = 2000 + Math.floor(_w * _s);
opacity = (Math.floor((_w * _s) / 10) / 10) - 0.2;
// 画像ロケーション情報の保存
// actionをclickにした場合に使用
if(isBuff)
offset[index] = {
top: _t - 70, left: _l,
width: _w * _s, height: _h * _s,
zIndex: zindex, opacity: opacity
}
elem.css({
position: "absolute", top: _t - 70, left: _l,
width: (_w * _s) + "px", height: (_h * _s) + "px",
zIndex: zindex,
opacity: opacity
});
}
// リフレクションしたcanvasを取得
// via http://lab.hisasann.com/reflector/
var _opacity = 0.5, _height = 0.5;
function createReflector(elem, id, offset){
if(!options.reflection)
return;
var reflector;
var refHeight = Math.floor(elem.height * _height);
var refWidth = elem.width;
var canvas = document.createElement("canvas")
if(canvas.getContext){ // not IE
canvas.id = id + "can";
canvas.style.position = "absolute";
canvas.style.top = offset.top + offset.height - 1 + "px";
canvas.style.left = offset.left + "px";
canvas.style.height = refHeight + "px";
canvas.style.width = refWidth + "px";
canvas.height = refHeight;
canvas.width = refWidth;
var ctx = canvas.getContext("2d")
with(ctx){
save();
translate(0, elem.height);
scale(1,-1);
drawImage(elem, 0, 0, elem.width, elem.height);
restore();
var gradient = createLinearGradient(0, 0, 0, refHeight);
gradient.addColorStop(1, "rgba(0, 0, 0, 1)");
gradient.addColorStop(0, "rgba(0, 0, 0, " + _opacity + ")");
globalCompositeOperation = "destination-out";
fillStyle = gradient;
fillRect(0, 0, refWidth, refHeight);
fill();
}
reflector = canvas;
}else{ // IE
var reflection = document.createElement("img");
reflection.id = id + "can";
with(reflection){
src = elem.src;
style.position = "absolute";
style.top = offset.top + offset.height - 1 + "px";
style.left = offset.left + "px";
style.width = refWidth + "px";
style.height = elem.height + "px";
style.display = "block";
style.marginBottom = "-"+(elem.height - refHeight)+"px";
style.filter = 'flipv progid:DXImageTransform.Microsoft.Alpha(opacity='+(_opacity*100)+', style=1, finishOpacity=0, startx=0, starty=0, finishx=0, finishy='+(_height*100)+')';
}
reflector = reflection;
}
$(reflector).appendTo("#reflection");
}
// auto animation
$.fn.jMerrygoround.auto = function() {
var interval,
width = $this.width() / 2,
offsetX = $this.offset().left;
interval = setInterval(function(){
$($imgs).each(function(index){
slider(index, $(this), true, true);
reflectCSS($(this), offset[index]);
});
speed += 0.05;
}, 10);
}
// mouseover animation
$.fn.jMerrygoround.mouseover = function() {
var interval,
width = $this.width() / 2,
offsetX = $this.offset().left;
$this.mouseover(function(e){
interval = setInterval(function(){
$($imgs).each(function(index){
slider(index, $(this), true, true);
reflectCSS($(this), offset[index]);
});
speed += ((e.pageX - offsetX) - width) / 1500;
}, 10);
});
$this.mouseout(function(e){
clearInterval(interval);
interval = null;
});
}
// mousedown animation
$.fn.jMerrygoround.mousedown = function() {
var interval = null;
// next
$(options.nextId).mousedown(function(e){
interval = setInterval(function(){
speed += 0.1;
$($imgs).each(function(index){
slider(index, $(this), true, true);
reflectCSS($(this), offset[index]);
});
}, 10);
}).mouseup(function(e){
clearInterval(interval);
interval = null;
}).mouseout(function(e){
clearInterval(interval);
interval = null;
});
// prev
$(options.prevId).mousedown(function(e){
interval = setInterval(function(){
speed -= 0.1;
$($imgs).each(function(index){
slider(index, $(this), true, true);
reflectCSS($(this), offset[index]);
});
}, 10);
}).mouseup(function(e){
clearInterval(interval);
interval = null;
}).mouseout(function(e){
clearInterval(interval);
interval = null;
});
}
// click animation
var nowIndex = 0;
$.fn.jMerrygoround.click = function(){
// next
$(options.nextId).mousedown(function(){
// 一周したら元のインデックスに戻る
if(nowIndex >= $($imgs).size())
nowIndex = 1;
else
nowIndex++;
$($imgs).each(function(index) {
$.fn.jMerrygoround.click[options.motion]($(this), offset[calcIndex(nowIndex + index)], index);
reflectAnime($(this), offset[calcIndex(nowIndex + index)]);
});
});
// prev
$(options.prevId).click(function(){
// 一周したら元のインデックスに戻る
if(nowIndex <= -$($imgs).size())
nowIndex = -1;
else
nowIndex--;
$($imgs).each(function(index) {
$.fn.jMerrygoround.click[options.motion]($(this), offset[calcIndex(nowIndex + index)], index);
reflectAnime($(this), offset[calcIndex(nowIndex + index)]);
});
});
}
// click animation - normal
$.fn.jMerrygoround.click.normal = function(elem, offset, index){
elem.css({
zIndex: offset.zIndex,
opacity: offset.opacity
}).animate(
{
left: offset.left + 'px',
top: offset.top + 'px',
width: offset.width + 'px',
height: offset.height + 'px'
},
{queue: true, duration: options.duration, easing: options.easing, complete: function(){}}
);
};
// click animation - spiral
$.fn.jMerrygoround.click.spiral = function(elem, offset, index){
elem.animate(
{
top: index * offset.height / 4 - options.centerY + 'px'
},
{queue: true, duration: options.duration, easing: options.easing, complete: function(){
setTimeout(function() {
elem.css({
zIndex: offset.zIndex,
opacity: offset.opacity
}).animate(
{
left: offset.left + 'px',
top: offset.top + 'px',
width: offset.width + 'px',
height: offset.height + 'px'
},
{queue: true, duration: options.duration, easing: options.easing, complete: function(){}}
);
}, Math.random() * options.duration);
}}
);
}
// click animation - shake
$.fn.jMerrygoround.click.shake = function(elem, offset, index){
setTimeout(function() {
elem.animate(
{
left: Math.sin(index) * options.radiusX + options.centerX + 'px',
top: Math.cos(index) * options.radiusY + options.centerY + 'px',
opacity: 0.6
},
{queue: true, duration: options.duration, easing: options.easing, complete: function(){
elem.css({
zIndex: offset.zIndex,
opacity: offset.opacity
}).animate(
{
left: offset.left + 'px',
top: offset.top + 'px',
width: offset.width + 'px',
height: offset.height + 'px'
},
{queue: true, duration: options.duration, easing: options.easing, complete: function(){}}
);
}}
);
}, Math.random() * options.duration);
}
// click animation - grow
$.fn.jMerrygoround.click.grow = function(elem, offset, index){
elem.animate(
{
width: Math.random() * options.width + 'px',
height: Math.random() * options.height + 'px'
},
{queue: true, duration: options.duration, easing: options.easing, complete: function(){
elem.css({
zIndex: offset.zIndex,
opacity: offset.opacity
}).animate(
{
left: offset.left + 'px',
top: offset.top + 'px',
width: offset.width + 'px',
height: offset.height + 'px'
},
{queue: true, duration: options.duration, easing: options.easing, complete: function(){}}
);
}}
);
}
// click animation - delay
$.fn.jMerrygoround.click.delay = function(elem, offset, index){
setTimeout(function() {
elem.animate(
{
left: offset.left + 'px',
top: offset.top + 'px',
width: offset.width + 'px',
height: offset.height + 'px'
},
{queue: true, duration: options.duration, easing: options.easing, complete: function(){
$(this).css({
zIndex: offset.zIndex,
opacity: offset.opacity
});
}}
);
}, Math.random() * options.duration);
}
// リフレクション用CSS設定
function reflectCSS(elem, offset) {
if(!options.reflection)
return;
$("#" + elem.attr("id") + "can").css({
left: offset.left + 'px',
top: offset.top + offset.height - 1 + 'px',
width: offset.width + 'px',
height: $.browser.msie ? offset.height : Math.floor(offset.height * _height) + 'px'
});
}
// リフレクション用アニメーション
function reflectAnime(elem, offset) {
if(!options.reflection)
return;
$("#" + elem.attr("id") + "can").animate({
left: offset.left + 'px',
top: offset.top + offset.height - 1 + 'px',
width: offset.width + 'px',
height: $.browser.msie ? offset.height : Math.floor(offset.height * _height) + 'px'
}, options.duration, options.easing);
}
function calcIndex(x){
var ret = 0;
if(x < 0)
ret = x + offset.length;
else if(x >= offset.length)
ret = x - offset.length;
else
ret = x;
return ret;
}
// Thank you enjoy!!
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment