HTML5 Drag and Drop: Sorting Photos Into Albums
Join the DZone community and get the full member experience.
Join For FreeAs first, I suggest you download the source files and keep the demo opened in a tab for better understanding.
Live Demo
download 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.
css/main.css
/* 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 Demo
download 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!
Published at DZone with permission of Andrey Prikaznov, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments