I am using the interact.js library for drag/drop functionality. I'm using raw images instead of divs as my draggable objects and this seems to work fine:
<img id="drag4" src="images/SVG/ksTire.svg" class="draggable js-drag" style="width:85px">
I cannot figure out how to return an image back to its original starting point before the drag began. I need to store the original coords in a js variable, and depending on certain events, return the image back to its exact original starting location. I experimented with various x/y coordinates on the event, and tried getElementById also, with no luck. Whenever I try to return the image back to its original location, some approaches will bring it back the first time, but then when I begin to drag it again, it's way off in a strange place, not under the mouse pointer anymore.
Could someone please provide a bit of sample code showing how to constantly snap a draggable object back to its initial location? I already figured out the places in code where to call this, all I need is how to get images back to the right place, and then to continue to behave properly after that occurs.
Note: interact.js isn't built on jquery, so I'd prefer a non-jquery solution in this particular case.
Here is the full contents of my dropzone.js, which is where most of the pertinent stuff happens related to this issue:
(function(interact) {
'use strict';
var transformProp;
var startPos = null;
var startX = 0;
var startY = 0;
var validDrop = false;
interact.maxInteractions(Infinity);
// setup draggable elements.
/* block below was copied from https://github.com/taye/interact.js/issues/79 -- try to get this working */
// setup drop areas.
setupDropzone('#drop1', '#drag1, #drag2, #drag4');
setupDropzone('#drop2', '#drag4');
setupDropzone('#drop4', '#drag4');
setupDropzone('#drop5', '#drag1, #drag2, #drag4');
setupDropzone('#drop6', '#drag3');
setupDropzone('#drop7', '#drag1');
/* SNAP code was copied from http://kundprojekt.soonce.com/lintex/zonbuilder/ and https://github.com/taye/interact.js/issues/79 -- try to get this working */
// dropzone #1 accepts draggable #1
//setupDropzone('#drop1', '#drag1');
// dropzone #2 accepts draggable #1 and #2
//setupDropzone('#drop2', '#drag1, #drag2');
// every dropzone accepts draggable #3
//setupDropzone('.js-drop', '#drag3');
/**
* Setup a given element as a dropzone.
*
* @param {HTMLElement|String} el
* @param {String} accept
*/
function setupDropzone(el, accept) {
interact(el)
.dropzone({
accept: accept,
ondropactivate: function(event) {
addClass(event.relatedTarget, '-drop-possible');
},
ondropdeactivate: function(event) {
removeClass(event.relatedTarget, '-drop-possible');
}
})
.snap({
mode: 'anchor',
anchors: [],
range: Infinity,
elementOrigin: {
x: 0.5,
y: 0.5
},
endOnly: true
})
.on('dropactivate', function(event) {
var active = event.target.getAttribute('active') | 0;
// change style if it was previously not active
if (active === 0) {
addClass(event.target, '-drop-possible');
//event.target.textContent = 'Drop me here!';
}
event.target.setAttribute('active', active + 1);
})
.on('dropdeactivate', function(event) { // this fires after each drop, whether a drop into a valid drop zone occurs or not
var active = event.target.getAttribute('active') | 0;
// change style if it was previously active
// but will no longer be active
if (active === 1) {
removeClass(event.target, '-drop-possible');
//event.target.textContent = 'Dropzone';
}
event.target.setAttribute('active', active - 1);
if (!validDrop) {
//document.getElementById("drag4").style.position = 'absolute';
//document.getElementById("drag4").style.left = startX + "px";
//document.getElementById("drag4").style.top = startY + "px";
}
})
.on('dragstart', function(event) {
// snap to the start position
if (!startPos) {
var rect = interact.getElementRect(event.target);
// record center point when starting the very first a drag
startPos = {
x: rect.left + rect.width / 2,
y: rect.top + rect.height / 2
}
}
event.interactable.snap({
anchors: [startPos]
});
})
.on('dragenter', function(event) {
addClass(event.target, '-drop-over');
var dropRect = interact.getElementRect(event.target),
dropCenter = {
x: dropRect.left + dropRect.width / 2,
y: dropRect.top + dropRect.height / 2
};
event.draggable.snap({
anchors: [dropCenter]
});
//event.relatedTarget.textContent = 'I\'m in';
})
.on('dragleave', function(event) {
removeClass(event.target, '-drop-over');
event.draggable.snap(false);
// when leaving a dropzone, snap to the start position
event.draggable.snap({
anchors: [startPos]
});
var svgFilename = getSVGFilename(event.relatedTarget.src);
if (document.getElementById("message").innerHTML) {
document.getElementById("message").innerHTML = document.getElementById("message").innerHTML.replace(svgFilename + "<br>", "");
}
//event.relatedTarget.textContent = 'Drag me…';
})
.on('drop', function(event) { // this only fires when an object is dropped into a valid drop zone for that object
validDrop = true;
removeClass(event.target, '-drop-over');
var svgFilename = getSVGFilename(event.relatedTarget.src);
document.getElementById("message").innerHTML += svgFilename + "<br>";
//event.relatedTarget.textContent = 'Dropped';
});
}
function getAbsolutePosition(el) {
var el2 = el;
var curtop = 0;
var curleft = 0;
if (document.getElementById || document.all) {
do {
curleft += el.offsetLeft - el.scrollLeft;
curtop += el.offsetTop - el.scrollTop;
el = el.offsetParent;
el2 = el2.parentNode;
while (el2 != el) {
curleft -= el2.scrollLeft;
curtop -= el2.scrollTop;
el2 = el2.parentNode;
}
} while (el.offsetParent);
} else if (document.layers) {
curtop += el.y;
curleft += el.x;
}
return [curleft, curtop];
};
function getSVGFilename(url) {
if (url.indexOf("/") > -1)
return url.substr(url.lastIndexOf('/') + 1);
else
return "";
}
function addClass(element, className) {
if (element.classList) {
return element.classList.add(className);
} else {
element.className += ' ' + className;
}
}
function removeClass(element, className) {
if (element.classList) {
return element.classList.remove(className);
} else {
element.className = element.className.replace(new RegExp(className + ' *', 'g'), '');
}
}
interact('.js-drag')
.draggable({
max: Infinity
})
.on('dragstart', function(event) {
validDrop = false;
event.interaction.x = parseInt(event.target.getAttribute('data-x'), 10) || 0;
event.interaction.y = parseInt(event.target.getAttribute('data-y'), 10) || 0;
var absolutePosition = getAbsolutePosition(event.target);
startX = absolutePosition[0];
startY = absolutePosition[1];
})
.on('dragmove', function(event) {
event.interaction.x += event.dx;
event.interaction.y += event.dy;
if (transformProp) {
event.target.style[transformProp] =
'translate(' + event.interaction.x + 'px, ' + event.interaction.y + 'px)';
} else {
event.target.style.left = event.interaction.x + 'px';
event.target.style.top = event.interaction.y + 'px';
}
})
.on('dragend', function(event) {
event.target.setAttribute('data-x', event.interaction.x);
event.target.setAttribute('data-y', event.interaction.y);
});
interact(document).on('ready', function() {
transformProp = 'transform' in document.body.style ? 'transform' : 'webkitTransform' in document.body.style ? 'webkitTransform' : 'mozTransform' in document.body.style ? 'mozTransform' : 'oTransform' in document.body.style ? 'oTransform' : 'msTransform' in document.body.style ? 'msTransform' : null;
});
}(window.interact));
And here is my base html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>WorkScreen Prototype #1</title>
<script src="js/interact.js"></script>
<script src="js/dropzones.js"></script>
<link rel="stylesheet" href="css/dropzones.css">
</head>
<body style="background-color: #CCC; height: 852px">
<a href="ShowSVGs.aspx" target="_blank">View All SVGs</a>
<div style="margin-top:55px">
<div style="float: left; vertical-align: top">
<img id="drag1" src="images/SVG/ksBatteryBox.svg" class="draggable js-drag" style="width:80px"><br />
<img id="drag2" src="images/SVG/ksBumper6308700.svg" class="draggable js-drag" style="width:85px"><br />
<img id="drag3" src="images/SVG/ksHood8090130.svg" class="draggable js-drag" style="width:165px"><br />
<img id="drag4" src="images/SVG/ksTire.svg" class="draggable js-drag" style="width:85px"><br />
</div>
<div style="float: left;vertical-align:top;margin-left:-72px">
<div style ="margin-left:100px;">
<div id="drop1" class="dropzone js-drop" style="margin-left:186px;"></div>
<div id="drop2" class="dropzone js-drop" style="margin-left:90px"></div>
<div style="">
<div id="drop6" class="dropzone js-drop" style="clear: both; margin-left: 0px; margin-top: 37px"></div>
<div style="float:left"><img src="images/BaseTruck.png" /></div>
<div id="drop7" class="dropzone js-drop" style="float: left; margin-left: 251px; margin-top: 153px; position: absolute;"></div>
<div id="drop3" class="dropzone js-drop" style="float:left; margin-left:10px;margin-top:37px"></div>
</div>
<div id="drop5" class="dropzone js-drop" style="clear: both; margin-left: 186px;"></div>
<div id="drop4" class="dropzone js-drop" style="margin-left: 90px;"></div>
<br /><br />
<div id="message" style="clear: both; margin-left: 0px; margin-top: 44px; width: 245px; display: inherit; border: 2px solid gray; padding: 7px;"></div>
</div>
</div>
</div>
</body>
</html>
Here's the solution in case it helps others. No need to figure out exact location relative to window in order to return elements to their load-time position. Just do this:
And call resetCoords like this:
In the
.on('drop...)event you set validDrop to true, else it will be false.