cartodb/lib/assets/javascripts/utils/draggable.js
2020-06-15 10:58:47 +08:00

205 lines
5.5 KiB
JavaScript

$.fn.draggableOverlay = function(opt) {
var self = this;
var $rule = null;
var $ruleH = null;
var $elements = this;
if (opt === "disable" || opt.container == undefined) {
this.addClass("disabled");
this.css('cursor', '')
return;
}
opt = $.extend({ horizontal_guides: [], vertical_guides: [], padding: 0, stickiness: 7, cursor: "move" }, opt);
var $container = opt.container;
// Guide offsets
var horizontal_guides = opt.horizontal_guides;
var vertical_guides = opt.vertical_guides;
var vertical_limits, horizontal_limits, verticals, horizontals = [];
$(".rule").remove();
$rule = $("<div class='rule' />");
$container.append($rule)
$rule.offset({ top: 0 }).css( { left: 0 });
$ruleH = $("<div class='rule horizontal' />");
$container.append($ruleH);
$ruleH.offset({ top: 0 }).css( { left: 0 });
for (var i = 0; i < horizontal_guides.length; i++) {
var position = horizontal_guides[i];
var $el = $("<div class='guide horizontal' />");
$container.append($el)
$el.offset( { top: position }).css( { left: 0 });
}
for (var i = 0; i < vertical_guides.length; i++) {
var position = vertical_guides[i];
var $el = $("<div class='guide vertical' />");
$container.append($el)
$el.offset( { left: position }).css( { top: 0 });
}
var onMouseDown = function(e) {
if (self.hasClass("disabled")) {
e.stopPropagation();
return;
}
e.stopPropagation();
var $drag = $(this).addClass('draggable');
$(this).css({ bottom: "auto", right: "auto", left: $(this).position().left, top: $(this).position().top })
var
//z_idx = $drag.css('z-index'),
drg_h = $drag.outerHeight(),
drg_w = $drag.outerWidth(),
pos_y = $drag.offset().top + drg_h - e.pageY,
pos_x = $drag.offset().left + drg_w - e.pageX,
container_x = $container.offset().left,
container_y = $container.offset().top,
container_w = $container.width(),
container_h = $container.height();
verticals = [];
horizontals = [];
vertical_limits = [];
horizontal_limits = [];
var device = $(this).hasClass("desktop") ? "desktop" : "mobile";
if ($(this).hasClass("snap")) {
$elements.each(function(i, e) {
if (!$(e).hasClass("draggable") && $(e).hasClass(device) && !$(e).hasClass("disabled") && $(e).hasClass("snap")) {
var t = $(e).offset().top;
horizontal_limits.push(t);
horizontal_limits.push(t + $(e).height());
var l = $(e).offset().left;
vertical_limits.push(l);
vertical_limits.push(l + $(e).width());
}
});
verticals = verticals.concat(vertical_limits, vertical_guides);
horizontals = horizontals.concat(horizontal_limits, horizontal_guides);
}
var onMouseMove = function(e) {
var top = e.pageY + pos_y - drg_h;
var left = e.pageX + pos_x - drg_w;
var otop = top;
var oleft = left;
var container_right = container_x + container_w;
var container_bottom = container_y + container_h;
// CHECK GUIDES
for (var i = 0; i < horizontals.length; i++) {
var target_l = horizontals[i];
if ( ( top >= target_l - opt.stickiness - opt.padding ) && ( top <= target_l + opt.stickiness + opt.padding) ) {
top = target_l;
$ruleH.offset( { top: top }).css({ left: 0, opacity: 1 })
break;
} else if ( ( top + drg_h <= target_l + opt.stickiness + opt.padding ) && ( top + drg_h >= target_l - opt.stickiness - opt.padding ) ) {
top = target_l - drg_h ;
$ruleH.offset( { top: top + drg_h }).css({ left: 0, opacity: 1 })
break;
}
}
for (var i = 0; i < verticals.length; i++) {
var target_l = verticals[i];
if ( ( left >= target_l - opt.stickiness - opt.padding) && ( left <= target_l + opt.stickiness + opt.padding ) ) {
left = target_l;
$rule.offset( { left: left }).css({ top: 0, opacity: 1 })
break;
} else if ( ( left + drg_w <= target_l + opt.stickiness + opt.padding ) && ( left + drg_w >= target_l - opt.stickiness - opt.padding) ) {
left = target_l - drg_w ;
$rule.offset( { left: left + drg_w }).css({ top: 0, opacity: 1 })
break;
}
}
// LEFT
if (left - opt.stickiness < container_x) {
left = container_x;
} else if (left + drg_w + opt.stickiness > container_right ) {
left = container_right - drg_w;
}
// TOP
if (top - opt.stickiness < container_y) {
top = container_y;
} else if (top + drg_h + opt.stickiness > container_bottom ) {
top = container_bottom - drg_h;
}
if (top == otop && left == oleft) {
$(this).find(".draggable").removeClass("sticky");
$(".rule").css({ opacity: 0 });
} else {
$(this).find(".draggable").addClass("sticky");
}
var offset = { top: top, left: left };
$('.draggable').offset(offset);
var updateLayout = _.throttle(function(e) {
opt.drag && opt.drag();
}, 100);
updateLayout();
}
$drag.parents().on("mousemove", onMouseMove);
};
var onExit = function() {
$(".draggable").parents().off("mousemove");
$(".rule").css({ opacity: 0 });
$(".draggable").removeClass('sticky');
$(".draggable").removeClass('draggable');
};
$("body").on("mouseup", onExit);
return this.on("mousedown", onMouseDown).on("mouseup", onExit);
}