我发现这个问题很有趣,因为前段时间我从事过一个类似的项目,所以这是我的意见。首先,我建议您在动画中使用 Julian Shapiro 的 velocity 插件,这将为您带来以下优势:
- 代码更少、更简洁,没有杂乱(适用于 css 和 javascript)
- Javascript 动画(有争议)比 CSS3 动画快。阅读this了解更多信息
- 您不必来回切换 css 类来实现动画(并且您不必手动预设和计算在 css 规则内旋转的度数)
借助速度,可以像这样简单地转动车轮:
$(".wheel").velocity({
rotateZ : "-" + {degree} + "deg" // "-" minus to spin counterclockwise, remove otherwise
});
velocity 插件有一套完整的 API 选项,您可以探索here。当然,您需要一种算法来计算每个click 上的degree 变量的新值。
现在,如果我理解正确,您有两个问题:
- 如何计算旋转到轮子的度数以及在下一个想要的位置停止。
- 无论是预设的还是随机选择的,如何确定选择的片段(在轮子顶部)是什么,然后启动相应的fancybox。
我将使用以下算法开始回答第二个问题:
_target = (_deg - (360 * parseInt(_deg / 360))) / 45;
其中_target 是所选段的javascript index,_deg 是我们将轮子从先前位置旋转到当前位置的度数。
它是如何工作的:
按照上面的示例,您的轮子的初始状态是第 1 段(商业意识),从那里您需要移动到第 3 段(团队合作),所以这意味着旋转轮子 3 次(1080 度) ) + 2 个 45 度的分段(90 度)= 1170 degrees 旋转。
所以,将该值应用于算法:
_target = (1170 - (360 * parseInt(1170 / 360))) / 45;
_target = (1170 - (360 * parseInt(3.25))) / 45;
_target = (1170 - (360 * 3)) / 45;
_target = (1170 - (1080)) / 45;
_target = (90) / 45;
_target = 2;
如果您认为在 javascript 中,组的第一个元素有index=0,第二个是index=1,第三个是index=2,等等。_target = 2 实际上指向第三个段(团队工作)。无论您转动了多少度,此算法都有效。
然后触发fancybox就很简单了:
$(".fancybox").eq(_target).trigger("click");
上面的代码假设你已经在脚本中的某个地方初始化了fancybox,比如
$(".fancybox").fancybox({ // API options });
现在,对于 first 问题,我看到了 3 种可能的算法,您可以在单独的函数中设置它们以在按钮 click 之后调用:
顺序:
返回一个模式顺序(每个 click 前进 3 个段),如 1,4,7,2,5,8,3,6 ... 然后循环。每个片段在循环之前至少显示一次:
function ordSequential() {
// order : 1,4,7,2,5,8,3,6 ... then loops
return _deg = _deg + (45*3) + 1080;
};
它假定初始值为_deg = 0。请注意,您始终可以更改因子 3 来改变模式。
所以有了旋转轮子的度数,我们可以使用 velocity 来:
- 将所有段的不透明度重置为
1
- 转动轮子
- 将选定段的不透明度设置为
0.4
- 触发所选片段对应的fancybox
完整代码
// sequential order
// advances 3 segments each click
var _target, _deg = 0;
function ordSequential() {
// order : 1,4,7,2,5,8,3,6 ... then loops
return _deg = _deg + (45*3) + 1080;
};
jQuery(document).ready(function ($) {
$(".skills-wheel .btn").on("click", function (e) {
// select algorithm sequential, random or preset :
ordSequential();
_target = (_deg - (360 * parseInt(_deg / 360))) / 45;
// start animation
// reset opacity of all segments to 1
$(".fancybox").parent("li").velocity({
opacity: 1
}, {
duration: 100,
complete: function () {
$(".wheel").velocity({
rotateZ: "-" + _deg + "deg"
}, {
duration: 3000,
complete: function (elements) {
// after spinning animation is completed, set opacity of target segment's parent
$(".fancybox").parent("li").eq(_target).velocity({
opacity: 0.4
}, {
duration: 100,
// after opacity is completed, fire targeted segment in fancybox
complete: function () {
$(".fancybox").eq(_target).trigger("click");
} // third animation completed
}); // nested velocity 2
} // second animation completed
}); // nested velocity 1
} // first animation completed
}); // velocity
return false;
}); // click
// initialize fancybox
$(".fancybox").fancybox({
maxWidth: "85%"
});
}); // ready
见JSFIDDLE
注意在其 complete 回调中使用嵌套*速度函数
* 编辑:如果您使用 Velocity 的 UI 包,您可以使用函数 .RunSequence() 使嵌套动画序列更易于管理。查看使用此方法更新的 JSFIDDLE。确保使用最新版本的 Velocity.js 和 UI 包(v1.1.0,截至今天 [2014 年 10 月 8 日])http://cdnjs.com/libraries/velocity
预设:
如上例所示返回预设顺序
第三 > 第六 > 第一 > 第八 > 第二 > 第五 > 第七 > 第四
代码基本相同,但算法稍微复杂一些。首先,我们需要在数组中预设顺序以及其他支持变量:
var presetPos = [3, 6, 1, 8, 2, 5, 7, 4],
presetInit = true,
spin_count = 0;
注意 presetPos 数组包含实际的段号,而不是 javascript index。还要注意标志 presetInit 的使用,它告诉车轮是否处于初始状态(我们将在第一次旋转后将其切换为 false)
preset 算法的秘诀是计算数组中current 和next 段之间的差异(以度为单位),这样我们就可以知道轮子需要多少度旋转:
function ordPreset() {
// initial state?
if (presetInit) {
presetInit = false;
return _deg = _deg + ((presetPos[spin_count] - 1) * 45) + 1080;
} else {
var _current = presetPos[spin_count];
var _next = presetPos[spin_count > 6 ? 0 : spin_count + 1];
var _diff = _next - _current;
spin_count = spin_count > 6 ? 0 : ++spin_count;
return _deg = _deg + (_diff * 45) + 1080;
};
};
见JSFIDDLE
随机:
返回 0-7 范围内的随机顺序。
随机算法非常简单。参考this。
function ordRandom() {
return _deg = _deg + ((Math.floor(Math.random() * (8 - 1 + 1)) + 0) * 45) + 1080;
};
但是click 方法内部的逻辑有点复杂。在您的理想世界中,选择的片段应该是完全随机的,但永远不要选择以前使用过的片段。一旦选择了所有8,这将是结束(按钮将停止旋转轮子)。
有几个因素需要考虑:首先,我们需要一个数组来说明哪些段从未被使用过。
var _index = [0,1,2,3,4,5,6,7];
注意这个数组是关于每个段的index。
此外,我们需要一个标志,让我们循环(使用while)随机选择,直到找到一个从未使用过的index。
var _repeatRandom = true;
然后,重要的是使用.splice() 方法从数组中删除随机选择的index,以确保我们不会再次使用它。
点击事件的代码:
$(".skills-wheel .btn").on("click", function (e) {
// select algorithm sequential, random or preset :
// if random order, don't repeat the same
_repeatRandom = _index.length == 0 ? false : true;
// loop until find one that has never been used
while (_repeatRandom) {
ordRandom();
_target = (_deg - (360 * parseInt(_deg / 360))) / 45;
var _inArray = $.inArray(_target, _index);
if (_inArray > -1) {
// target is in the array
_repeatRandom = false; // break while loop
_index.splice(_inArray, 1); // remove segment from array so it won't be repeated
// start animation
// reset opacity of all segments to 1
$(".fancybox").parent("li").velocity({
opacity : 1
}, {
duration : 100,
complete : function () {
$(".wheel").velocity({
rotateZ : "-" + _deg + "deg"
}, {
// addtional settings and callback
duration : 3000,
complete : function (elements) {
// after spinning animation is completed, set opacity of target segment's parent
$(".fancybox").parent("li").eq(_target).velocity({
opacity : 0.4
}, {
duration : 100,
// after opacity is completed, fire targeted segment in fancybox
complete : function () {
$(".fancybox").eq(_target).trigger("click");
} // third animation completed
}); // nested velocity 2
} // second animation completed
}); // nested velocity 1
} // first animation completed
}); // velocity
}; // if
}; // while
return false;
}); // click
见JSFIDDLE
最后的笔记:
- 我删除了不必要的 css 选择器和
transform 效果(.wheel.spin-1、.wheel.spin-2、.wheel.spin-3 等)
- 有许多设置(如动画的
duration 等),您可能需要根据自己的喜好和需求进行调整。