如何让3D旋转的鼠标悬停更加流畅?

3
如何实现当鼠标进入或离开盒子区域时平稳旋转3D效果?我有下面的代码,但当鼠标从盒子区域移出并从另一侧进入盒子时,元素的动画效果不太流畅。
代码: fiddle
$(document).ready(function () {
var $one = $('#div1'),
    $two = $('#div2'),
    browserPrefix = "",
    usrAg = navigator.userAgent;
if(usrAg.indexOf("Chrome") > -1 || usrAg.indexOf("Safari") > -1) {
    browserPrefix = "-webkit-";
} else if (usrAg.indexOf("Opera") > -1) {
    browserPrefix = "-o";
} else if (usrAg.indexOf("Firefox") > -1) {
    browserPrefix = "-moz-";
} else if (usrAg.indexOf("MSIE") > -1) {
    browserPrefix = "-ms-";
}

$(document).mousemove(function (event) {
    var cx = Math.ceil(window.innerWidth / 2.0),
        cy = Math.ceil(window.innerHeight / 2.0),
        dx = event.pageX - cx,
        dy = event.pageY - cy,
        tiltx = (dy / cy),
        tilty = - (dx / cx),
        radius = Math.sqrt(Math.pow(tiltx, 2) + Math.pow(tilty, 2)),
        degree = (radius * 15);

        shadx = degree*tiltx;   /*horizontal shadow*/
        shady = degree*tilty;   /*vertical shadow*/

    $one.css(browserPrefix + 'transform', 'rotate3d(' + tiltx + ', ' + tilty + ', 0, ' + degree + 'deg)');
    $two.css(browserPrefix + 'transform', 'rotate3d(' + tiltx + ', ' + tilty + ', 0, ' + degree + 'deg)');



    if(dx>cx) /*without that horizontal values are reversed*/
        $('#div1, #div2').css('box-shadow', + (-shady) + 'px ' + (-shadx) +'px 5px #3D352A');
    else $('#div1, #div2').css('box-shadow', + shady + 'px ' + (-shadx) +'px 5px #3D352A');
});});

你的fiddle(在Chrome中)似乎完好无损;我没有看到你描述的问题。由于mousemove已经正确地附加到文档上,所以不应该有任何问题。除非你在测试某些劣质浏览器。 - Ingmars
我在 Chrome 和 Firefox 上进行了测试,它可以正常工作。您能说明一下您想要做什么吗? - Mimouni
我认为OP的意思是,现在如果你慢慢移动鼠标,你会看到翻译/旋转以小跳跃方式更新,但他/她希望它更平滑地进行。 - Timothy Groote
我认为你的限制因素是鼠标移动事件触发的频率和时间。值得研究一下requestAnimationFrame并设置绘制循环,然后使用缓动来平滑动画效果。 - Timothy Groote
就像Timothy说的那样,我的意思是如何在鼠标指针进入框区域时去掉那些微小的跳动旋转,并使其更加平滑。 - Riantori
2个回答

2
如果我理解正确,OP的问题是,如果您将鼠标放在jsfiddle的“result”面板一侧,绕过div并从另一侧重新进入,则旋转会立即跳到新位置,没有任何过渡效果。
您的代码中存在一个错误,html中wrapper的ID应该是id="#wrapper"

编辑:我的第二个解决方案存在一些错误,在某些浏览器中,mousemove事件的触发速度比css转换结束更快,导致元素来回跳动。

仅JS的解决方案 这是我的最终解决方案。

我将mousemove事件限流以降低其触发频率。然后在新旧鼠标位置之间计算了几个步骤,并延迟渲染变换,直到mousemove事件再次触发。

限流事件的方法在这个stackoverflow答案中。


这是我在JS之前做的。过渡似乎非常平滑,但除非出现跳跃问题,否则无法使其快于0.2秒。

第3个解决方案


第1个解决方案

我已将2个div添加到默认的中心位置,并在离开视口时返回该位置。当鼠标位于视口上方时,过渡速度更快,因此即使mousemove事件不是非常连续地触发,旋转也应平滑。

请注意,这里存在一些错误,如果您移动鼠标的速度稍微快一点,它就会在Firefox中来回跳动。

CSS:

#wrapper {
    width: 100%;
    height: 90vh;
}

#wrapper:hover #div1,
#wrapper:hover #div2 {
    transition: transform 0.05s linear, box-shadow 0.05s linear;
}

#div1,
#div2 {
    transform: rotate3d(0,0,0,0deg);
    box-shadow: 0 0 5px #3D352A;
    transition: transform 0.3s linear, box-shadow 0.3s linear;
}

JS:

$(document).mouseleave(function (event) {
    $one.removeAttr('style');
    $two.removeAttr('style');
});

我没有在CSS中包含厂商前缀。同时,请将wrapper的高度修正为你在最终产品中需要的值,90vh是fiddle中更好的值。


如果你不喜欢div回到中心的效果:

使用解决方案2进行操作

CSS:

.mouse-enter #div1,
.mouse-enter #div2 {
    transition: transform 0.2s linear, box-shadow 0.2s linear;
}

JS:

$(document).mouseenter(function (event) {
    $('#wrapper').addClass('mouse-enter');
    setTimeout(function(){ $('#wrapper').removeClass('mouse-enter'); }, 400);
});

在mouseleave之前,您可能希望将最后一个鼠标位置保存为js变量或#wrapper上的数据属性。然后,在mouseenter时,计算旧位置和新位置之间的一些转换步骤,并依次将它们添加到2个div中。这可能是比我的解决方法更好的解决方案,可以减少可能出现的错误。


你好,我喜欢你的解决方案,但是当我尝试解决方案2时,仍然存在一些跳跃和旋转更新时的轻微延迟。 - Riantori
你说得对,我很快会更新我的答案,我想到了一些解决方案。 - ezattilabatyi

0
   <div></div>
      <style>
div {
     width: 200px;
     height: 100px;
     background-color: yellow;
     transition: all 1s;
         }

div:hover{
       -moz-transform: rotate(7deg); 
     -o-transform: rotate(7deg); 
    -webkit-transform: rotate(7deg); 
    transform: rotate(180deg);
         }
    </style>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接