【问题标题】:Jquery draggable and droppable with CSS 'zoom' property使用 CSS 'zoom' 属性可拖放的 Jquery
【发布时间】:2014-01-16 16:01:49
【问题描述】:

在我的应用程序中,我有一个可以改变 CSS 缩放的 div。

不幸的是,这与坐标空间混淆了。当超过可缩放区域 1 页 px != 1px 时 :)

当涉及到 droppables 时,它完全破坏了交叉点检测。

我正在寻找关于我应该从哪里开始尝试处理这个问题的提示?

我在这里做了一个演示。

小提琴:

http://jsfiddle.net/crRvp/1/

HTML:

<div id="dse">
    <div id="ds">Drop here!</div>
</div>
<p>
<div id="widget">Drag me!</div>
</p>

CSS:

#dse{
    position:relative;
    width:640px;
    height:360px;
    zoom:0.75;
    -moz-transform: scale(0.75);
    -moz-transform-origin:0 0;
    -o-transform: scale(0.75);
    -o-transform-origin:0 0;
}

#ds{
    position:relative;
    zoom:1;
    width:640px;
    height:360px;
    border: solid 1px black;
    font-size:2em;
}

#widget{
    position:relative;
    width:150px;
    height:50px;
    border: solid 1px black;
}

.droppableActive{
    background-color:red;
}

.droppableHover{
    background-color:green;
}

JS:

$("#widget").draggable({
    opacity     : 0.7,
    scroll      : false,
    revert: function(dropped){
          var wasDropped = dropped && dropped[0].id == "ds";
          if(!wasDropped){$(this).animate({ top: 0, left: 0 }, 'slow');}
          return !wasDropped;
    }
    ,
    stop: function(evt, ui) {

        var canvasLeft = $('#ds').offset().left;
        var canvasTop = $('#ds').offset().top;

        alert('ui.position.left: ' + (ui.position.left) + ' canvasLeft: ' + canvasLeft);
        alert('ui.position.top: ' + (ui.position.top) + ' canvasTop: ' + canvasTop);
    }
});

$("#ds").droppable({
    activeClass: 'droppableActive',
    hoverClass: 'droppableHover',
    accept: "#widget",
    drop: function(evt, ui){
        id = ui.draggable.attr('id');
        alert('id: ' + id);
    }
});

【问题讨论】:

    标签: jquery css zooming draggable droppable


    【解决方案1】:

    我遇到了同样的问题,但仅在我的情况下:可放置和可拖动的项目都在缩放容器中(带有zoom css 属性!)。

    可拖动可以通过“dragFix”修复轻松修复:

    var zoomScale = parseFloat($('.container').css('zoom'));
    
    $('.drag__item').draggable({            
            drag: function (event, ui) {
                var changeLeft = ui.position.left - ui.originalPosition.left;
                var newLeft = ui.originalPosition.left + changeLeft / zoomScale;
                var changeTop = ui.position.top - ui.originalPosition.top;
                var newTop = ui.originalPosition.top + changeTop / zoomScale;
    
                ui.position.left = newLeft;
                ui.position.top = newTop;
            }
    });
    

    要修复 droppable,我们需要编辑 jquery-ui 代码。考虑到编辑库源代码不是一个好主意,让我们重写intersect 方法。 问题是x1y1 坐标(顶部,可拖动项目的左侧)在先前的“dragFix”修复后被破坏,因此,交叉点检测无法按预期工作。 所以我们需要对x1y1坐标进行归一化处理。

    var intersect = $.ui.intersect = (function () {
        function isOverAxis(x, reference, size) {
            return (x >= reference) && (x < (reference + size));
        }
    
        return function (draggable, droppable, toleranceMode, event) {
            if (!droppable.offset) {
                return false;
            }
    
            var x1 = draggable.offset.left + draggable.position.left - draggable.originalPosition.left + draggable.margins.left,//here is the fix for scaled container
                y1 = draggable.offset.top + draggable.position.top - draggable.originalPosition.top + draggable.margins.top,//here is the fix for scaled container
                x2 = x1 + draggable.helperProportions.width,
                y2 = y1 + draggable.helperProportions.height,
                l = droppable.offset.left,
                t = droppable.offset.top,
                r = l + droppable.proportions().width,
                b = t + droppable.proportions().height;
    
            switch (toleranceMode) {
                case 'fit':
                    return (l <= x1 && x2 <= r && t <= y1 && y2 <= b);
                case 'intersect':
                    return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half
                        x2 - (draggable.helperProportions.width / 2) < r && // Left Half
                        t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half
                        y2 - (draggable.helperProportions.height / 2) < b); // Top Half
                case 'pointer':
                    return isOverAxis(event.pageY, t, droppable.proportions().height) &&
                        isOverAxis(event.pageX, l, droppable.proportions().width);
                case 'touch':
                    return (
                        (y1 >= t && y1 <= b) || // Top edge touching
                        (y2 >= t && y2 <= b) || // Bottom edge touching
                        (y1 < t && y2 > b) // Surrounded vertically
                    ) && (
                        (x1 >= l && x1 <= r) || // Left edge touching
                        (x2 >= l && x2 <= r) || // Right edge touching
                        (x1 < l && x2 > r) // Surrounded horizontally
                    );
                default:
                    return false;
            }
        };
    })();
    

    从 jquery 1.12 开始,$.ui.intersect 函数是作用域的,因此以后不能直接修改它。它在$.ui.ddmanager 中作为局部变量调用,所以即使修改$.ui.intersect 也不会被使用。自定义它有点复杂。你可以这样做,基本上你重新定义 intersect 的范围,然后重新定义 $.ui.ddmanager 上的拖放方法,以便它调用修改后的 intersect:

    from this answer

    $.ui.ddmanager.drag = function (draggable, event) {
        // If you have a highly dynamic page, you might try this option. It renders positions
        // every time you move the mouse.
        if (draggable.options.refreshPositions) {
            $.ui.ddmanager.prepareOffsets(draggable, event);
        }
    
        // Run through all droppables and check their positions based on specific tolerance options
        $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function () {
    
            if (this.options.disabled || this.greedyChild || !this.visible) {
                return;
            }
    
            var parentInstance, scope, parent,
                intersects = intersect(draggable, this, this.options.tolerance, event),
                c = !intersects && this.isover ?
                    'isout' :
                    (intersects && !this.isover ? 'isover' : null);
            if (!c) {
                return;
            }
    
            if (this.options.greedy) {
    
                // find droppable parents with same scope
                scope = this.options.scope;
                parent = this.element.parents(':data(ui-droppable)').filter(function () {
                    return $(this).droppable('instance').options.scope === scope;
                });
    
                if (parent.length) {
                    parentInstance = $(parent[0]).droppable('instance');
                    parentInstance.greedyChild = (c === 'isover');
                }
            }
    
            // We just moved into a greedy child
            if (parentInstance && c === 'isover') {
                parentInstance.isover = false;
                parentInstance.isout = true;
                parentInstance._out.call(parentInstance, event);
            }
    
            this[c] = true;
            this[c === 'isout' ? 'isover' : 'isout'] = false;
            this[c === 'isover' ? '_over' : '_out'].call(this, event);
    
            // We just moved out of a greedy child
            if (parentInstance && c === 'isout') {
                parentInstance.isout = false;
                parentInstance.isover = true;
                parentInstance._over.call(parentInstance, event);
            }
        });
    
    }
    
    $.ui.ddmanager.drop = function (draggable, event) {
        var dropped = false;
    
        // Create a copy of the droppables in case the list changes during the drop (#9116)
        $.each(($.ui.ddmanager.droppables[draggable.options.scope] || []).slice(), function () {
    
            if (!this.options) {
                return;
            }
            if (!this.options.disabled && this.visible &&
                intersect(draggable, this, this.options.tolerance, event)) {
                dropped = this._drop.call(this, event) || dropped;
            }
    
            if (!this.options.disabled && this.visible && this.accept.call(this.element[0],
                (draggable.currentItem || draggable.element))) {
                this.isout = true;
                this.isover = false;
                this._deactivate.call(this, event);
            }
    
        });
        return dropped;
    }
    

    JSFiddle example

    【讨论】:

      猜你喜欢
      • 2018-12-13
      • 1970-01-01
      • 2017-10-31
      • 2017-10-19
      • 2020-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多