【问题标题】:Rotating div onClick - cycle through various degrees (wheel of fortune)旋转 div onClick - 不同程度的循环(命运之轮)
【发布时间】:2014-10-09 01:49:54
【问题描述】:

我想要达到的效果是在单击一个按钮时,一个由 8 个三角形组成的圆圈旋转。当它停止时,圆顶部的三角形被选中。然后打开一个相对于所选段的花式框覆盖(最后一部分还没有工作)。选择段的顺序对用户来说是随机的,但可以像我在 CSS 中所做的那样预设(当前:3rd > 6th > 1st > 8th > 2nd > 5th > 7th > 4th)。

我创建了一个 codepen 来显示我目前在这方面的进展,您可以通过访问下面的链接来查看它,因为它很难解释。

http://codepen.io/moy/pen/DrbAL

点击“旋转”按钮后,圆圈会旋转 3 次(1080 度)+ 额外的 270 度,因此第三个列表项位于 div 的顶部 - 这很好用。

我的第一个问题是:在第二次单击按钮时,圆圈需要再次旋转 3 次,然后再旋转一点以将下一个选定的列表项/段 (6) 定位在 div 的顶部,等等为每个剩余的项目打开。有没有办法做到这一点,而不必将 1080 添加到圆圈已经旋转的数量上?因此,该值始终为1080deg + 圆需要旋转以将相关段定位在 div 顶部的额外量。否则最后一项的值将是 10000 度!如果必须这样做,我想我将不得不忍受它并戴上我的数学帽子。

第二个问题是:一旦圆完成旋转,如何显示相关的fancybox叠加? ID 目前是每个叠加层的标题,但可以很容易地为叠加层 1、叠加层 2 等,以匹配每次旋转后在纺车上设置的旋转 1、旋转 2 的类别。

谢谢,希望有人能帮忙!

【问题讨论】:

  • 您是否遵循一种模式?还是轮子应该随机旋转?
  • 它应该“出现”随机。我猜在一个理想的世界里,这将是完全随机的,但永远不会选择以前使用过的片段。一旦选择了所有8个,这将是结束。但实际上,没有人会真正再次/不止一次这样做,所以有一个固定的顺序,所以无论何时有人使用它都是一样的。

标签: jquery html css fancybox css-transitions


【解决方案1】:

我发现这个问题很有趣,因为前段时间我从事过一个类似的项目,所以这是我的意见。首先,我建议您在动画中使用 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 算法的秘诀是计算数组中currentnext 段之间的差异(以度为单位),这样我们就可以知道轮子需要多少度旋转:

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 等),您可能需要根据自己的喜好和需求进行调整。

【讨论】:

  • 这真是太棒了,非常感谢。这么详细!我遇到的唯一问题是当我改变旋转时,轮子顺时针旋转(通过删除“-”)而不是正确的段没有被选择。但我认为我可以通过调整代码的return _deg = _deg + (45*3) + 1080; 部分来对此进行排序。再次感谢您的帮助!
  • @user1406440 :作为改进,如果您使用 Velocity 的 UI 包,您可以使用函数 .RunSequence() 使嵌套动画序列更易于管理。请参阅使用此方法更新的我的答案的顺序选项:JSFIDDLE。确保使用最新版本的 Velocity.js 和 UI 包(今天为 v1.1.0)cdnjs.com/libraries/velocity
猜你喜欢
  • 2016-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多