通过前导点拖动 div(就像水中的船)

Posted

技术标签:

【中文标题】通过前导点拖动 div(就像水中的船)【英文标题】:Drag div by leading point (like a boat in water) 【发布时间】:2013-06-18 20:41:11 【问题描述】:

我正在尝试让 div 像船一样在水中拖动,但在正确旋转时遇到了一些问题。

这是我目前所拥有的:jsFiddle

JS

var start, stop;
$('#canoe').draggable(
    containment: '#board',
    cursor: 'none',
    cursorAt: 
        top: 5
    ,
    drag: function (event, ui) 
        start = ui.position.left;
        setTimeout(function () 
            stop = ui.position.left;
        , 150);
        $('#canoe').css(
            'transform': 'rotate(' + (start - stop) + 'deg)'
        );
    
);

CSS

#board 
    height:100%;
    width:100%;
    background:blue;

#canoe 
    background: #fff;
    border-radius:100% 100% 100% 100%;
    height:60px;
    width:10px;
    position:absolute;
    left:50%;
    bottom:0;
    transform-origin:top center;
    transition: transform .2s;

html

<div id="board">
    <div id="canoe">A</div>
</div>

有没有更好的方法来设置旋转,使船的前部始终领先,即使是 360 度旋转?

其他背景:我正在处理 Basic Game

赏金更新: 我需要“船”能够以一个连续的动作绕一圈拖动,而无需翻转/切换旋转方向。

【问题讨论】:

您可能需要在setTimeout - jsfiddle.net/unuCD/9 内设置旋转 @Vega 似乎没有做到这一点jsfiddle.net/apaul34208/unuCD/10 ...除非我还缺少更多内容? 【参考方案1】:

你需要:

每次更改时存储position 在变化时,计算所述位置之间的线的角度 最后保存position

http://jsfiddle.net/AstDerek/799Tp/

运动看起来并不柔和,但更接近你想要的。

如果要模拟水阻力,则需要将角度变化减少一些因素,然后在拖动结束后使用一些时间间隔或类似的时间继续移动,直到船的角度与应有的角度匹配有,或者新的拖动事件开始。

【讨论】:

这似乎有点疯狂。有什么办法可以降低灵敏度? 将角度乘以某个值 在this example 我设法减少了一点点波动 一个建议:不要存储最后一个位置,而是存储最后 x 个位置(尝试使用 2、3、4...),然后取这些 + 当前位置的平均值 嗯...有点抑制了小故障,但并不完美jsfiddle.net/799Tp/2【参考方案2】:

这有点复杂,但我会这样做:

var save = false, timer;

$('#canoe').draggable(
    containment: '#board',
    cursor: 'none',
    cursorAt: 
        top: 5
    ,
    drag: function (event, ui) 
        if ( !save ) save = ui.offset;
        var canoe    = $('#canoe'),
            center_x = save.left + 5,
            center_y = save.top + 30,
            radians  = Math.atan2(event.pageX - center_x, event.pageY - center_y),
            degree   = (radians * (180 / Math.PI) * -1) + 180,
            time     = Math.abs(ui.offset.top-save.top) + Math.abs(ui.offset.left-save.left);

        canoe.css(
            '-moz-transform'    : 'rotate('+degree+'deg)',
            '-webkit-transform' : 'rotate('+degree+'deg)',
            '-o-transform'      : 'rotate('+degree+'deg)',
            '-ms-transform'     : 'rotate('+degree+'deg)'
        );

        timer = setTimeout(function() 
            clearTimeout(timer);
            save = ui.offset;
        , Math.abs( time-300 ) + 400 );
    
);

FIDDLE

它将当前鼠标位置与给定时间之前独木舟中心的位置进行比较。 时间是根据鼠标移动的速度来设置的,因为较慢的移动需要更长的超时时间等。

清除超时也是一个好主意,这样它们就不会累积,即使在我测试它时它并不是真正的问题,并且使用 Math.abs 确保它始终是一个正整数。

我在 CSS 中添加了更多浏览器前缀。

【讨论】:

这似乎更接近我所追求的,但执行圆周运动似乎仍然存在问题。 @apaul34208 - 你在使用 Firefox 吗? 试试 Chrome 或 IE,好像 Firefox 有问题!试图弄清楚 FF 中的问题是什么,但它不会按照我说的那样做。 我解决了这个问题,我在#canoe 上设置了transition: transform .2s;,这使FF 中的工作变得混乱。不幸的是,没有它似乎有点抽搐。你知道有什么其他的方法可以解决问题吗? 稍微增加超时可能会使其更顺畅,但同时会“变慢”一点,看看这是否有帮助 -> jsfiddle.net/unuCD/26

以上是关于通过前导点拖动 div(就像水中的船)的主要内容,如果未能解决你的问题,请参考以下文章

jquery如何通过拖动边框改变该div的大小

如何检测 HTML 页面上的文件拖动

人死了,就像水消失在水中(博尔赫斯的经典诗句)

如何在拖放时克隆 div 而不是在拖动开始时克隆

在 Javascript FireFox 中不允许通过拖动来调整 div 的大小

JavaScript 如何通过单击和拖动动态移动 div