THE PROBLEM
I'm having a minor problem dragging elements onto a scalable div container.
Once the element is actually in the container, the elements drag fine and work the way they are supposed to.
Larger elements that are dragged onto the scalable container don't have too much of an issue.
But when smaller elements are dragged, you can see that the mouse is no longer attached to said element and when it is dropped, it drops a little off where it is supposed to drop.
I'm trying to find a solution that my mouse stays on the element and it drops where it is supposed to drop.
I've solved problems bit by bit and you can see below but this is the last piece of the puzzle that's driving me mad. If anyone has the time to lend a hand, it would be greatly appreciated.
Here is a codepen - click and drag the two blue elements onto the white container to try it out
This wil help making sure that the droppable area works with a scaled container.
$.ui.ddmanager.prepareOffsets = function(t, event) {
var i, j, m = $.ui.ddmanager.droppables[t.options.scope] || [],
type = event ? event.type : null,
list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack();
droppablesLoop: for (i = 0; i < m.length; i++) {
if (m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0], (t.currentItem || t.element)))) {
continue;
}
for (j = 0; j < list.length; j++) {
if (list[j] === m[i].element[0]) {
m[i].proportions().height = 0;
continue droppablesLoop;
}
}
m[i].visible = m[i].element.css("display") !== "none";
if (!m[i].visible) {
continue;
}
if (type === "mousedown") {
m[i]._activate.call(m[i], event);
}
m[i].offset = m[i].element.offset();
m[i].proportions({
width: m[i].element[0].offsetWidth * percent,
height: m[i].element[0].offsetHeight * percent
});
}
};
Enable the element to be resizable on a scaled container
function resizeFix(event, ui) {
var changeWidth = ui.size.width - ui.originalSize.width,
newWidth = ui.originalSize.width + changeWidth / percent,
changeHeight = ui.size.height - ui.originalSize.height,
newHeight = ui.originalSize.height + changeHeight / percent;
ui.size.width = newWidth;
ui.size.height = newHeight;
}
Makes it so drag works on a scaled container
function dragFix(event, ui) {
var containmentArea = $("#documentPage_"+ui.helper.parent().parent().attr('id').replace(/^(w+)_/, "")),
contWidth = containmentArea.width(), contHeight = containmentArea.height();
ui.position.left = Math.max(0, Math.min(ui.position.left / percent , contWidth - ui.helper.width()));
ui.position.top = Math.max(0, Math.min(ui.position.top / percent, contHeight- ui.helper.height()));
}
Creating a draggable element that I can drag onto the box.
.directive('draggableTypes', function() {
return {
restrict:'A',
link: function(scope, element, attrs) {
element.draggable({
zIndex:3000,
appendTo: 'body',
helper: function(e, ui){
var formBox = angular.element($("#formBox"));
percent = formBox.width() / scope.templateData.pdf_width;
if(element.attr('id') == 'textbox_item')
return $('<div class="text" style="text-align:left;font-size:14px;width:200px;height:20px;line-height:20px;">New Text Box.</div>').css({ 'transform': 'scale(' + percent + ')', '-moz-transform': 'scale(' + percent + ')', '-webkit-transform': 'scale(' + percent + ')', '-ms-transform': 'scale(' + percent + ')'});
if(element.attr('id') == 'sm_textbox_item')
return $('<div class="text" style="text-align:left;font-size:14px;width:5px;height:5px;line-height:20px;"></div>').css({ 'transform': 'scale(' + percent + ')', '-moz-transform': 'scale(' + percent + ')', '-webkit-transform': 'scale(' + percent + ')', '-ms-transform': 'scale(' + percent + ')'});
}
});
}
};
})
Create draggable/resizable elements that may already be in the box and applying the drag/resize fix to these
.directive('textboxDraggable', function() {
return {
restrict:'A',
link: function(scope, element, attrs) {
element.draggable({
cursor: "move",
drag: dragFix,
start: function(event, ui) {
var activeId = element.attr('id');
scope.activeElement.id = activeId;
scope.activeElement.name = scope.templateItems[activeId].info.name;
scope.$apply();
}
});
element.resizable({
minWidth: 25,
minHeight: 25,
resize: resizeFix,
stop: function( event, ui ) {
var activeId = element.attr('id');
scope.activeElement.duplicateName = false;
scope.activeElement.id = activeId;
scope.activeElement.name = scope.templateItems[activeId].info.name;
scope.templateItems[activeId]['style']['width'] = element.css('width');
scope.templateItems[activeId]['style']['height'] = element.css('height');
scope.$apply();
}
})
}
};
})
What happens when an item is dropped
.directive('droppable', function($compile) {
return {
restrict: 'A',
link: function(scope,element,attrs){
element.droppable({
drop:function(event,ui) {
var draggable = angular.element(ui.draggable),
draggable_parent = draggable.parent().parent(),
drag_type = draggable.attr('id'),
documentBg = element,
x = ui.offset.left,
y = ui.offset.top,
element_top = (y - documentBg.offset().top - draggable.height() * (percent - 1) / 2) / percent,
element_left = (x - documentBg.offset().left - draggable.width() * (percent - 1) / 2) / percent,
timestamp = new Date().getTime();
//just get the document page of where the mouse is if its a new element
if(draggable_parent.attr('id') == 'template_builder_box_container' || draggable_parent.attr('id') == 'template_builder_container')
var documentPage = documentBg.parent().parent().attr('id').replace(/^(w+)_/, "");
//if you are dragging an element that was already on the page, get parent of draggable and not parent of where mouse is
else var documentPage = draggable_parent.parent().parent().attr('id').replace(/^(w+)_/, "");
if(drag_type == "textbox_item")
{
scope.activeElement.id = scope.templateItems.push({
info: {'page': documentPage,'name': 'textbox_'+timestamp, 'type': 'text'},
style: {'text-align':'left','font-size':'14px','top':element_top+'px','left':element_left+'px', 'width':'200px', 'height':'20px'}
}) - 1;
scope.activeElement.name = 'textbox_'+timestamp;
}
else if(drag_type == "sm_textbox_item")
{
scope.activeElement.id = scope.templateItems.push({
info: {'page': documentPage,'name': '', 'type': 'text'},
style: {'text-align':'left','font-size':'14px','top':element_top+'px','left':element_left+'px', 'width':'5px', 'height':'5px'}
}) - 1;
scope.activeElement.name = 'textbox_'+timestamp;
}
else {
scope.templateItems[scope.activeElement.id]['style']['top'] = draggable.css('top');
scope.templateItems[scope.activeElement.id]['style']['left'] = draggable.css('left');
}
scope.$apply();
}
});
}
};
})
last but not least, my controller
.controller('testing', function($scope, $rootScope, $state, $stateParams) {
$scope.templateItems = [];
$scope.activeElement = { id: undefined, name: undefined };
$scope.templateData = {"id":"12345", "max_pages":1,"pdf_width":385,"pdf_height":800};
$scope.clickElement = function(index) { $scope.activeElement = { id: index, name: $scope.templateItems[index].info.name } }
});
Here is the basis of my html
<div id="formBox" ng-style="formbox(templateData.pdf_width)" zoom>
<div class="trimSpace" ng-style="trimSpace(templateData.pdf_width)" zoom>
<div id="formScale" ng-style="formScale(templateData.pdf_width)" zoom>
<form action="#" id="{{ templateData.id }}_form">
<div ng-repeat="key in [] | range:templateData.max_pages">
<div class="formContainer" id="{{ templateData.id + '_' + (key+1) }}" ng-style="{width: templateData.pdf_width+'px', height: templateData.pdf_height+'px'}">
<div class="formContent">
<div class="formBackground" id="documentPage_{{ (key+1) }}" droppable>
<div ng-hide="preview" ng-repeat="item in templateItems">
<div ng-if="item.info.page == (key+1) && item.info.type == 'text'" id="{{ $index }}" data-type="{{ item.info.type }}" ng-click="clickElement($index)" class="text" ng-style="item.style" textbox-draggable>{{ item.info.name }}</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
question from:
https://stackoverflow.com/questions/39987643/accurate-drop-for-draggable-element-on-scaled-div