我正在寻找一种在Javascript中拖放时实现Adobe Illustrator风格的“智能指南”的方法。我目前正在使用jQuery UI的draggable
:
$('.object').draggable({
containment: 'parent',
snap: '.other-objects',
snapTolerance: 5
})
这可以达到我想要的90% - 我可以在它的父级中拖动.object
,并且当它足够接近时它会将它的边缘捕捉到.other-objects
。
然而,我想要的是某种线(或某种类型的指南)出现,如果符合另一个对象的边缘,那么我可以拍摄东西在没有它们的情况下,它们彼此紧挨着。
有人知道这是否可行,或者我该怎么做呢?
答案 0 :(得分:7)
drag: function(event, ui) {
var inst = $(this).data("draggable"), o = inst.options;
var d = o.tolerance;
$(".objectx").css({"display":"none"});
$(".objecty").css({"display":"none"});
var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height,
xc = (x1 + x2) / 2, yc = (y1 + y2) / 2;
for (var i = inst.elements.length - 1; i >= 0; i--){
var l = inst.elements[i].left, r = l + inst.elements[i].width,
t = inst.elements[i].top, b = t + inst.elements[i].height,
hc = (l + r) / 2, vc = (t + b) / 2;
var ls = Math.abs(l - x2) <= d;
var rs = Math.abs(r - x1) <= d;
var ts = Math.abs(t - y2) <= d;
var bs = Math.abs(b - y1) <= d;
var hs = Math.abs(hc - xc) <= d;
var vs = Math.abs(vc - yc) <= d;
if(ls) {
ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
$(".objectx").css({"left":l-d-4,"display":"block"});
}
if(rs) {
ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
$(".objectx").css({"left":r-d-4,"display":"block"});
}
if(ts) {
ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
$(".objecty").css({"top":t-d-4,"display":"block"});
}
if(bs) {
ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
$(".objecty").css({"top":b-d-4,"display":"block"});
}
if(hs) {
ui.position.left = inst._convertPositionTo("relative", { top: 0, left: hc - inst.helperProportions.width/2 }).left - inst.margins.left;
$(".objectx").css({"left":hc-d-4,"display":"block"});
}
if(vs) {
ui.position.top = inst._convertPositionTo("relative", { top: vc - inst.helperProportions.height/2, left: 0 }).top - inst.margins.top;
$(".objecty").css({"top":vc-d-4,"display":"block"});
}
};
}
这样可以更容易地对齐行/列中的元素。
检查下面的小提琴:
http://jsfiddle.net/elin/A6CpP/
答案 1 :(得分:4)
我开始使用jsFiddle搞砸了。它并不完美,但它应该让你开始。
大部分逻辑都在jQuery UI的drag事件处理程序中:
function (event, ui) {
// You'll want to debounce this function so that it doesn't run every mouse move (e.g. see Ben Alman's site @ http://tinyurl.com/37dyjug)
var debounceTime = 200; // milliseconds
setTimeout(function () {
// Loop through all 'other-object's and see if we're lined up
$(".other-object").each(function (idx, other) {
var $other = $(other);
// Determine whether we're "close enough" to display the line
var padding = 1;
var closeToLeft = Math.abs($other.offset().left - ui.offset.left) < padding;
var closeToTop = Math.abs($other.offset().top - ui.offset.top) < padding;
// You can add closeToRight/closeToBottom, but you may need to do some calculation, e.g. right = left + width
// If we're close, display a line, otherwise remove that same line
// TODO: Find a better way of tagging which 'other-object' this line belongs to, using IDs or something more stable than the index of the jQuery each() function!
var id = 'leftOther' + idx;
if (closeToLeft) {
console.debug(idx, 'left');
$('.parent').not(':has(#' + id + ')').append('<div id="' + id + '" class="line vertical" style="left: ' + $other.offset().left + 'px;"/>');
} else {
$('#' + id).remove();
}
id = 'topOther' + idx;
if (closeToTop) {
console.debug(idx, 'top');
$('.parent').not(':has(#' + id + ')').append('<div id="topOther' + idx + '" class="line horizontal" style="top: ' + $other.offset().top + 'px;"/>');
} else {
$('#' + id).remove();
}
}); // End of 'other-object' loop
}, debounceTime); // End of setTimeout
} // End of drag function
如果我有一段时间后,我会回来再给它一点思考,但是你觉得你很喜欢半答案,所以现在开始你=)
答案 2 :(得分:3)
你可以尝试创建一个这样的插件
$.ui.plugin.add("draggable", "smartguides", {
start: function(event, ui) {
var i = $(this).data("draggable"), o = i.options;
i.elements = [];
$(o.smartguides.constructor != String ? ( o.smartguides.items || ':data(draggable)' ) : o.smartguides).each(function() {
var $t = $(this); var $o = $t.offset();
if(this != i.element[0]) i.elements.push({
item: this,
width: $t.outerWidth(), height: $t.outerHeight(),
top: $o.top, left: $o.left
});
});
},
drag: function(event, ui) {
var inst = $(this).data("draggable"), o = inst.options;
var d = o.tolerance;
$(".objectx").css({"display":"none"});
$(".objecty").css({"display":"none"});
var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
for (var i = inst.elements.length - 1; i >= 0; i--){
var l = inst.elements[i].left, r = l + inst.elements[i].width,
t = inst.elements[i].top, b = t + inst.elements[i].height;
var ls = Math.abs(l - x2) <= d;
var rs = Math.abs(r - x1) <= d;
var ts = Math.abs(t - y2) <= d;
var bs = Math.abs(b - y1) <= d;
if(ls) {
ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
$(".objectx").css({"left":l-d-4,"display":"block"});
}
if(rs) {
ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
$(".objectx").css({"left":r-d-4,"display":"block"});
}
if(ts) {
ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
$(".objecty").css({"top":t-d-4,"display":"block"});
}
if(bs) {
ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
$(".objecty").css({"top":b-d-4,"display":"block"});
}
};
}
});
并像这样使用
$('.other-objects').draggable({
containment: 'parent',
smartguides:".other-objects",
tolerance:5
});
答案 3 :(得分:0)
我从上面分叉了JSFiddle,我通过支持形状的同一侧来改进它。这是JsFiddle:http://jsfiddle.net/yusrilmaulidanraji/A6CpP/120/
HTML:
<div id="parent">
<div class="object1 dropped" style="left:0px;top:300px;background:#a00;"></div>
<div class="object2 dropped"></div>
<div class="object3 dropped" style="left:400px;top:20px;"></div>
<div class="objectx"></div>
<div class="objecty"></div>
</div>
CSS:
#parent{
width:600px;
height:500px;
border:1px solid #000;
position:relative;
}
.object1{
background:#aaa;
width:100px;
height:100px;
display:block;
position:absolute;
left:140px;
top:50px;
}
.object2{
background:#aaa;
width:100px;
height:150px;
display:block;
position:absolute;
left:140px;
top:50px;
}
.object3{
background:#aaa;
width:150px;
height:100px;
display:block;
position:absolute;
left:140px;
top:50px;
}
.objectx{
display:none;
//background:#fff;
width:0px;
height:100%;
position:absolute;
top:0px;
left:10px;
border-left: 1px solid yellow;
}
.objecty{
display:none;
//background:#fff;
width:100%;
height:0px;
position:absolute;
top:10px;
left:0px;
border-bottom: 1px solid yellow;
}
JS:
$.ui.plugin.add("draggable", "smartguides", {
start: function(event, ui) {
var i = $(this).data("draggable"), o = i.options;
i.elements = [];
$(o.smartguides.constructor != String ? ( o.smartguides.items || ':data(draggable)' ) : o.smartguides).each(function() {
var $t = $(this); var $o = $t.offset();
if(this != i.element[0]) i.elements.push({
item: this,
width: $t.outerWidth(), height: $t.outerHeight(),
top: $o.top, left: $o.left
});
});
},
stop: function(event, ui) {
$(".objectx").css({"display":"none"});
$(".objecty").css({"display":"none"});
},
drag: function(event, ui) {
var inst = $(this).data("draggable"), o = inst.options;
var d = o.tolerance;
$(".objectx").css({"display":"none"});
$(".objecty").css({"display":"none"});
var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height,
xc = (x1 + x2) / 2, yc = (y1 + y2) / 2;
for (var i = inst.elements.length - 1; i >= 0; i--){
var l = inst.elements[i].left, r = l + inst.elements[i].width,
t = inst.elements[i].top, b = t + inst.elements[i].height,
hc = (l + r) / 2, vc = (t + b) / 2;
var lss = Math.abs(l - x1) <= d;
var ls = Math.abs(l - x2) <= d;
var rss = Math.abs(r - x2) <= d;
var rs = Math.abs(r - x1) <= d;
var tss = Math.abs(t - y1) <= d;
var ts = Math.abs(t - y2) <= d;
var bss = Math.abs(b - y2) <= d;
var bs = Math.abs(b - y1) <= d;
var hs = Math.abs(hc - xc) <= d;
var vs = Math.abs(vc - yc) <= d;
if(lss) {
ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
$(".objectx").css({"left":ui.position.left,"display":"block"});
}
if(rss) {
ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
$(".objectx").css({"left":ui.position.left + ui.helper.width(),"display":"block"});
}
if(ls) {
ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
$(".objectx").css({"left":ui.position.left + ui.helper.width(),"display":"block"});
}
if(rs) {
ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
$(".objectx").css({"left":ui.position.left,"display":"block"});
}
if(tss) {
ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
$(".objecty").css({"top":ui.position.top,"display":"block"});
}
if(ts) {
ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
$(".objecty").css({"top":ui.position.top + ui.helper.height(),"display":"block"});
}
if(bss) {
ui.position.top = inst._convertPositionTo("relative", { top: b-inst.helperProportions.height, left: 0 }).top - inst.margins.top;
$(".objecty").css({"top":ui.position.top + ui.helper.height(),"display":"block"});
}
if(bs) {
ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
$(".objecty").css({"top":ui.position.top,"display":"block"});
}
if(hs) {
ui.position.left = inst._convertPositionTo("relative", { top: 0, left: hc - inst.helperProportions.width/2 }).left - inst.margins.left;
$(".objectx").css({"left":ui.position.left + (ui.helper.width()/2),"display":"block"});
}
if(vs) {
ui.position.top = inst._convertPositionTo("relative", { top: vc - inst.helperProportions.height/2, left: 0 }).top - inst.margins.top;
$(".objecty").css({"top":ui.position.top + (ui.helper.height()/2),"display":"block"});
}
};
}
});
$('.dropped').draggable({
containment: 'parent',
smartguides:".dropped",
tolerance:5
});
答案 4 :(得分:0)
我为可拖动和可调整大小的插件添加了智能指南功能。
$('.drag')
.draggable({
smartGuides: '.drag:not(".selected")'
})
.resizable({
handles: 'all',
smartGuides: '.drag:not(".selected")'
}
你可以看到它的工作原理:
jsFiddle:https://jsfiddle.net/chukanov/bypr7Lt3/2/
答案 5 :(得分:-1)
我的jsfiddle的问题是什么
访问jsfiddle.net/datakolay/7xzTn/
$.ui.plugin.add("draggable", "smartguides", {
start: function(event, ui) {
var i = $(this).data("draggable"), o = i.options;
i.elements = [];
$(o.smartguides.constructor != String ? ( o.smartguides.items || ':data(draggable)' ) : o.smartguides).each(function() {
var $t = $(this); var $o = $t.offset();
if(this != i.element[0]) i.elements.push({
item: this,
width: $t.outerWidth(), height: $t.outerHeight(),
top: $o.top, left: $o.left
});
});
},
stop: function(event, ui) {
$(".objectx").css({"display":"none"});
$(".objecty").css({"display":"none"});
},
drag: function(event, ui) {
var inst = $(this).data("draggable"), o = inst.options;
var d = o.tolerance;
$(".objectx").css({"display":"none"});
$(".objecty").css({"display":"none"});
var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height,
xc = (x1 + x2) / 2, yc = (y1 + y2) / 2;
for (var i = inst.elements.length - 1; i >= 0; i--){
var l = inst.elements[i].left, r = l + inst.elements[i].width,
t = inst.elements[i].top, b = t + inst.elements[i].height,
hc = (l + r) / 2, vc = (t + b) / 2;
var ls = Math.abs(l - x2) <= d;
var rs = Math.abs(r - x1) <= d;
var ts = Math.abs(t - y2) <= d;
var bs = Math.abs(b - y1) <= d;
var hs = Math.abs(hc - xc) <= d;
var vs = Math.abs(vc - yc) <= d;
if(ls) {
ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
$(".objectx").css({"left":l-d-4,"display":"block"});
}
if(rs) {
ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
$(".objectx").css({"left":r-d-4,"display":"block"});
}
if(ts) {
ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
$(".objecty").css({"top":t-d-4,"display":"block"});
}
if(bs) {
ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
$(".objecty").css({"top":b-d-4,"display":"block"});
}
if(hs) {
ui.position.left = inst._convertPositionTo("relative", { top: 0, left: hc - inst.helperProportions.width/2 }).left - inst.margins.left;
$(".objectx").css({"left":hc-d-4,"display":"block"});
}
if(vs) {
ui.position.top = inst._convertPositionTo("relative", { top: vc - inst.helperProportions.height/2, left: 0 }).top - inst.margins.top;
$(".objecty").css({"top":vc-d-4,"display":"block"});
}
};
}
});
$('.other-objects').draggable({
containment: 'parent',
smartguides:".other-objects",
tolerance:5
});