1

我已经为此寻找答案但找不到它......所以希望有人可以帮助我。我正在尝试创建一个包含在圆形(而不是正方形)中的可拖动 div(使用 jquery ui)。现在,我已经将包含设置链接到它的父 div,但无论我尝试什么......它仍然允许可拖动元素进入父方形 div 的角落。我已经尝试设置父 div 的边框半径,使其为圆形而不是方形(但这可能只是一个 css 的东西,并且不会影响实际的 div 形状)。有谁知道如何将可拖动的 div 约束到一个圆圈?谢谢,安迪

var containment_radius = 50;

$(this.dragobject).draggable({ 
    drag: function() {
        var position = $(this.dragobject).position();
        var result = limit(position.left, position.top, containment_radius, containment_radius);
        if (!result.limit) {
            $(this.dragobject).x = result.x + "px";
            $(this.dragobject).y = result.y + "px";
        }
        console.log(result);
    } 
});

function limit(x, y, x1, y1) {
    var dist = distance([x, y], [x1, y1]);
    if (dist <= containment_radius) {
        return {x: x, y: y};
    } else {
        return {limit: true};
    }
}

function distance(dot1, dot2) {
    var x1 = dot1[0],
    y1 = dot1[1],
    x2 = dot2[0],
    y2 = dot2[1];
    return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
}
4

3 回答 3

1

此解决方案遵循 Luke H 更新 ui.position 的建议。实现起来很简单(无需扩展现有的可拖动小部件),但我不喜欢它,因为半径必须从可拖动的外部访问,而不是从容器本身获取。

var radius = 128;
$('.color-picker-map-selector').draggable({
    containment: '.map',
    drag: function( event, ui ) {
        var x = ui.position.left - radius,
            y = radius - ui.position.top,
            h = Math.sqrt(x*x + y*y);
        if (Math.floor(h) > radius) {
            ui.position.top = radius - Math.round(radius * y / h);
            ui.position.left = Math.round(radius * x / h) + radius;
        }
    }
});

不需要像许多示例使用的那样复杂的数学函数,例如正弦和余弦。

我首选的解决方案是通过添加形状选项(“矩形、圆形”)来扩展小部件并覆盖内部 _generatePosition 函数。它使用容器的宽度和高度来找到中心,如果容器不是正方形,它会将可拖动对象限制为椭圆。

// add shape option to stock draggable
$.widget( "ui.draggable", $.ui.draggable, {
    options: {
        shape: 'rectangular'
    },
    _generatePosition( event, constrainPosition ) {
        var position = this._super( event, constrainPosition );
        if (this.options.shape != 'circular') return position;
        if ( constrainPosition ) {
            if ( this.containment ) {
                if ( this.relativeContainer ) {
                    co = this.relativeContainer.offset();
                    containment = [
                        this.containment[ 0 ] + co.left,
                        this.containment[ 1 ] + co.top,
                        this.containment[ 2 ] + co.left,
                        this.containment[ 3 ] + co.top
                    ];
                } else {
                    containment = this.containment;
                }
                var xRadius = Math.floor((containment[ 2 ] - containment[ 0 ]) / 2),
                    yRadius = Math.floor((containment[ 3 ] - containment[ 1 ]) / 2),
                    x = position.left - xRadius,
                    y = yRadius - position.top,
                    h = Math.sqrt(x*x + y*y);
                if (Math.floor(h) > Math.min(xRadius, yRadius)) {
                    var ye = Math.round(yRadius * y / h),
                    xe = Math.round(xRadius * x / h);
                    if ((Math.abs(y) > Math.abs(ye)) || (Math.abs(x) > Math.abs(xe))) {
                        position.left = xe + xRadius;
                        position.top = yRadius - ye;
                    }
                }
            }
        }
        return position;
    }
});

如果 jQuery UI 人员更改 _generatePosition 的名称和用法,会有一些小问题,但如果他们要更改函数的内部结构会很好,因此它会调用一些辅助函数,比如 _constrain(),这将显着简化此代码.

另请注意,此解决方案不适用于网格对齐,但可以通过一些额外的代码来完成。

干杯!

于 2016-09-13T20:43:47.920 回答
0

请参阅此答案,该答案显示了如何使用drag事件进行约束。这是通过更新事件处理程序中的ui.position变量来完成的。drag

于 2013-04-21T16:11:39.197 回答
0

Duopixel 回答了这个确切的问题,其中包含一个圆圈的示例,而不是 andyopayne 在此处建议的波浪。

如何限制圆区域内的运动

这是示例 http://jsfiddle.net/7Asn6/

诀窍是计算与初始和当前拖动位置坐标的距离,使用

Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));

然后计算新的 x 和 y 坐标

x: Math.cos(radians) * canvas.radius + canvas.center[0], y: Math.sin(radians) * canvas.radius + canvas.center[1]

在拖动回调中:

于 2014-01-23T10:44:58.707 回答