HTML5 Drag and Drop: Sorting Photos Into Albums
As first, I suggest you download the source files and keep the demo opened in a tab for better understanding.
Live Demodownload result
So, let's start!
Step 1. HTML
index.html<div class="albums">
<div class="album" id="drop_1" droppable="true"><h2>Album 1</h2></div>
<div class="album" id="drop_2" droppable="true"><h2>Album 1</h2></div>
<div class="album" id="drop_3" droppable="true"><h2>Album 3</h2></div>
</div>
<div style="clear:both"></div>
<div class="gallery">
<a id="1" draggable="true"><img src="images/1.jpg"></a>
<a id="2" draggable="true"><img src="images/2.jpg"></a>
<a id="3" draggable="true"><img src="images/3.jpg"></a>
<a id="4" draggable="true"><img src="images/4.jpg"></a>
<a id="5" draggable="true"><img src="images/5.jpg"></a>
<a id="6" draggable="true"><img src="images/6.jpg"></a>
<a id="7" draggable="true"><img src="images/7.jpg"></a>
<a id="8" draggable="true"><img src="images/8.jpg"></a>
<a id="9" draggable="true"><img src="images/9.jpg"></a>
<a id="10" draggable="true"><img src="images/10.jpg"></a>
<a id="11" draggable="true"><img src="images/11.jpg"></a>
<a id="12" draggable="true"><img src="images/12.jpg"></a>
</div>
<script src="js/main.js"></script>
You can see here three droppable objects (our virtual albums) and twelve images. I have marked the droppable albums with attribute ‘droppable’, and draggable objects with the attribute ‘draggable’.
Step 2. CSS
Now,
it's time to style our example. It is possible that you have noticed that the
styles of our today’s lesson looks like the styles of our previous
demonstration (where I described how to create a pure css3 gallery). I
updated those styles for today’s lesson.
/* Photo Gallery styles */
.gallery {
margin: 50px auto 0;
width: 840px;
}
.gallery a {
display: inline-block;
height: 135px;
margin: 10px;
opacity: 1;
position: relative;
width: 180px;
-khtml-user-drag: element;
/* CSS3 Prevent selections */
-moz-user-select: none;
-webkit-user-select: none;
-khtml-user-select: none;
user-select: none;
/* CSS3 transition rules */
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
}
.gallery a img {
border: 8px solid #fff;
border-bottom: 20px solid #fff;
cursor: pointer;
display: block;
height: 100%;
left: 0px;
position: absolute;
top: 0px;
width: 100%;
z-index: 1;
/* CSS3 Box sizing property */
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
-o-box-sizing: border-box;
box-sizing: border-box;
/* CSS3 transition rules */
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
/* CSS3 Box Shadow */
-moz-box-shadow: 2px 2px 4px #444;
-webkit-box-shadow: 2px 2px 4px #444;
-o-box-shadow: 2px 2px 4px #444;
box-shadow: 2px 2px 4px #444;
}
/* Custom CSS3 rotate transformation */
.gallery a:nth-child(1) img {
-moz-transform: rotate(-25deg);
-webkit-transform: rotate(-25deg);
transform: rotate(-25deg);
}
.gallery a:nth-child(2) img {
-moz-transform: rotate(-20deg);
-webkit-transform: rotate(-20deg);
transform: rotate(-20deg);
}
.gallery a:nth-child(3) img {
-moz-transform: rotate(-15deg);
-webkit-transform: rotate(-15deg);
transform: rotate(-15deg);
}
.gallery a:nth-child(4) img {
-moz-transform: rotate(-10deg);
-webkit-transform: rotate(-10deg);
transform: rotate(-10deg);
}
.gallery a:nth-child(5) img {
-moz-transform: rotate(-5deg);
-webkit-transform: rotate(-5deg);
transform: rotate(-5deg);
}
.gallery a:nth-child(6) img {
-moz-transform: rotate(0deg);
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
.gallery a:nth-child(7) img {
-moz-transform: rotate(5deg);
-webkit-transform: rotate(5deg);
transform: rotate(5deg);
}
.gallery a:nth-child(8) img {
-moz-transform: rotate(10deg);
-webkit-transform: rotate(10deg);
transform: rotate(10deg);
}
.gallery a:nth-child(9) img {
-moz-transform: rotate(15deg);
-webkit-transform: rotate(15deg);
transform: rotate(15deg);
}
.gallery a:nth-child(10) img {
-moz-transform: rotate(20deg);
-webkit-transform: rotate(20deg);
transform: rotate(20deg);
}
.gallery a:nth-child(11) img {
-moz-transform: rotate(25deg);
-webkit-transform: rotate(25deg);
transform: rotate(25deg);
}
.gallery a:nth-child(12) img {
-moz-transform: rotate(30deg);
-webkit-transform: rotate(30deg);
transform: rotate(30deg);
}
.gallery a:hover img {
z-index: 5;
/* CSS3 transition rules */
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
/* CSS3 transform rules */
-moz-transform: rotate(0deg);
-webkit-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
.gallery a.hidden {
height: 0;
margin: 0;
opacity: 0;
width: 0;
}
.albums {
margin: 40px auto 0;
overflow: hidden;
width: 840px;
}
.album {
border: 3px dashed #ccc;
float: left;
margin: 10px;
min-height: 100px;
padding: 10px;
width: 220px;
/* CSS3 transition rules */
-webkit-transition: all 1.0s ease;
-moz-transition: all 1.0s ease;
-o-transition: all 1.0s ease;
transition: all 1.0s ease;
}
.album a {
display: inline-block;
height: 56px;
margin: 15px;
opacity: 1;
position: relative;
width: 75px;
-khtml-user-drag: element;
-webkit-user-drag: element;
-khtml-user-select: none;
-webkit-user-select: none;
/* CSS3 Prevent selections */
-moz-user-select: none;
-webkit-user-select: none;
-khtml-user-select: none;
user-select: none;
/* CSS3 transition rules */
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
}
.album a img {
border: 4px solid #fff;
border-bottom: 10px solid #fff;
cursor: pointer;
display: block;
height: 100%;
left: 0px;
position: absolute;
top: 0px;
width: 100%;
z-index: 1;
/* CSS3 Box sizing property */
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
-o-box-sizing: border-box;
box-sizing: border-box;
/* CSS3 transition rules */
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
/* CSS3 Box Shadow */
-moz-box-shadow: 2px 2px 4px #444;
-webkit-box-shadow: 2px 2px 4px #444;
-o-box-shadow: 2px 2px 4px #444;
box-shadow: 2px 2px 4px #444;
}
Step 3. JS
js/main.js// add event handler
var addEvent = (function () {
if (document.addEventListener) {
return function (el, type, fn) {
if (el && el.nodeName || el === window) {
el.addEventListener(type, fn, false);
} else if (el && el.length) {
for (var i = 0; i < el.length; i++) {
addEvent(el[i], type, fn);
}
}
};
} else {
return function (el, type, fn) {
if (el && el.nodeName || el === window) {
el.attachEvent('on' + type, function () { return fn.call(el, window.event); });
} else if (el && el.length) {
for (var i = 0; i < el.length; i++) {
addEvent(el[i], type, fn);
}
}
};
}
})();
// inner variables
var dragItems;
updateDataTransfer();
var dropAreas = document.querySelectorAll('[droppable=true]');
// preventDefault (stops the browser from redirecting off to the text)
function cancel(e) {
if (e.preventDefault) {
e.preventDefault();
}
return false;
}
// update event handlers
function updateDataTransfer() {
dragItems = document.querySelectorAll('[draggable=true]');
for (var i = 0; i < dragItems.length; i++) {
addEvent(dragItems[i], 'dragstart', function (event) {
event.dataTransfer.setData('obj_id', this.id);
return false;
});
}
}
// dragover event handler
addEvent(dropAreas, 'dragover', function (event) {
if (event.preventDefault) event.preventDefault();
// little customization
this.style.borderColor = "#000";
return false;
});
// dragleave event handler
addEvent(dropAreas, 'dragleave', function (event) {
if (event.preventDefault) event.preventDefault();
// little customization
this.style.borderColor = "#ccc";
return false;
});
// dragenter event handler
addEvent(dropAreas, 'dragenter', cancel);
// drop event handler
addEvent(dropAreas, 'drop', function (event) {
if (event.preventDefault) event.preventDefault();
// get dropped object
var iObj = event.dataTransfer.getData('obj_id');
var oldObj = document.getElementById(iObj);
// get its image src
var oldSrc = oldObj.childNodes[0].src;
oldObj.className += 'hidden';
var oldThis = this;
setTimeout(function() {
oldObj.parentNode.removeChild(oldObj); // remove object from DOM
// add similar object in another place
oldThis.innerHTML += '<a id="'+iObj+'" draggable="true"><img src="'+oldSrc+'" /></a>';
// and update event handlers
updateDataTransfer();
// little customization
oldThis.style.borderColor = "#ccc";
}, 500);
return false;
});
As you can see – the code is not very difficult. In the beginning, the script selects all draggable and droppable elements. And, I bind the ‘dragstart’ event to all draggable elements in order to setData to dataTransfer object. And, to all droppable areas I bind these events: ‘dragover’, ‘dragleave’ and ‘drop’. In the case of the first two events, the scripts performs a small css customization to the active drop area. When we drop the draggable object, our script duplicates that draggable object and puts it inside active droppable area (album) and remove that dropped object and, finally, we update the event handlers again (for new draggable objects).
Live Demodownload result
Conclusion
Thats all, today we have implemented native Drag and Drop functionality, which could a very practical task. Hope that our tutorial has helped you. Feel free to share our tutorials with your friends. Good luck!
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)





