'use strict';
angular.module('dndWithD3App', ['ng-sortable','dndLists','ngAnimate','ngRoute', 'ui.bootstrap', 'restangular','ngAnimate']).config(function($routeProvider) {
$routeProvider.when('/', {
templateUrl: 'lc-drag_drop_d3.html',
controller: 'MainCtrl'
}).otherwise({
redirectTo: '/'
});
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>AngularJS prototype with HTML5 Drag and Drop, integrated with D3.JS</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="style.css" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
<script src="http://cdn.jsdelivr.net/restangular/latest/restangular.min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
<script src="https://code.angularjs.org/1.4.7/angular-route.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.6.0/ui-bootstrap-tpls.min.js"></script>
<script src="https://code.angularjs.org/1.4.7/angular-sanitize.min.js"></script>
<script src="https://code.angularjs.org/1.4.7/angular-animate.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="app.js"></script>
<script src="lc-main-controller.js"></script>
<script src="lc-drag-directive.js"></script>
<script src="lc-drop-directive.js"></script>
<script src="lc-d3-service.js"></script>
<script src="angular-drag-and-drop-lists.min.js"></script>
<script src="http://rubaxa.github.io/Sortable/Sortable.js"></script>
<!-- ng-sortable.js -->
<script src="http://rubaxa.github.io/Sortable/ng-sortable.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui/0.4.0/angular-ui.min.js"></script>
</head>
<body ng-app="dndWithD3App">
<div class="col-md-10" data-ng-view="">
</div>
</body>
</html>
/* Space out content a bit */
body {
padding-top: 20px;
padding-bottom: 20px;
}
#items{
float:right;
padding-right:20px;
}
#container{
float:left;
padding-left:20px;
width:700px;
height:100px;
}
/* Customize container */
@media (min-width: 768px) {
.container {
max-width: 730px;
}
}
/* Responsive: Portrait tablets and up */
@media screen and (min-width: 768px) {
/* Remove the padding we set earlier */
.header,
.marketing,
.footer {
padding-left: 0;
padding-right: 0;
}
/* Space out the masthead */
.header {
margin-bottom: 30px;
}
/* Remove the bottom border on the jumbotron for visual effect */
.jumbotron {
border-bottom: 0;
}
}
.fixed-panel {
min-height: 10;
max-height: 10;
overflow-y: scroll;
}
.over-drop-area {
border: dashed 1px red;
}
[draggable] {
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
user-select: none;
/* Required to make elements draggable in old WebKit */
-khtml-user-drag: element;
-webkit-user-drag: element;
}
.cbp-spmenu {
background: #47a3da;
position: fixed;
height:300px;
}
.cbp-spmenu h3 {
color: #afdefa;
font-size: 1.9em;
padding: 20px;
margin: 0;
font-weight: 300;
background: #0d77b6;
}
.cbp-spmenu a {
display: block;
color: #fff;
font-size: 1.1em;
font-weight: 300;
}
.cbp-spmenu a:hover {
background: #258ecd;
}
ul
{
list-style-type: none;
}
.cbp-spmenu-vertical {
width: 240px;
height: 100%;
top: 0;
z-index: 1000;
}
.cbp-spmenu-vertical a {
border-bottom: 1px solid #258ecd;
padding: 1em;
}
.cbp-spmenu-right {
right: -240px;
}
.cbp-spmenu-right.cbp-spmenu-open {
right: 0px;
}
/* The starting CSS styles for the enter animation */
.fade.ng-enter {
transform: translateX(-240px) 4s ease-in;
opacity:0;
/*transform: translate3d(0px, -240px, 0px);
//transition: transform .2s ease-in-out;*/
}
/* The finishing CSS styles for the enter animation */
.fade.ng-enter.ng-enter-active {
opacity:1;
/*transform: translate3d(0px, 0px, 0px);
transition: transform .2s ease-in-out;*/
}
.fade.ng-leave {
transition:translateX(240px) 1s ease-out;
opacity:1;
}
.fade.ng-leave.ng-leave-active {
opacity:0;
}
.cbp-spmenu,
.cbp-spmenu-push {
transition: translate(-240px,0px) 5s ease-in-out;
}
/**
* For the correct positioning of the placeholder element, the dnd-list and
* it's children must have position: relative
*/
.simpleDemo ul[dnd-list],
.simpleDemo ul[dnd-list] > li {
position: relative;
}
/**
* The dnd-list should always have a min-height,
* otherwise you can't drop to it once it's empty
*/
.simpleDemo ul[dnd-list] {
min-height: 42px;
padding-left: 0px;
}
/**
* The dndDraggingSource class will be applied to
* the source element of a drag operation. It makes
* sense to hide it to give the user the feeling
* that he's actually moving it.
*/
.simpleDemo ul[dnd-list] .dndDraggingSource {
display: none;
}
/**
* An element with .dndPlaceholder class will be
* added to the dnd-list while the user is dragging
* over it.
*/
.simpleDemo ul[dnd-list] .dndPlaceholder {
display: block;
background-color: #ddd;
min-height: 42px;
}
/**
* The dnd-lists's child elements currently MUST have
* position: relative. Otherwise we can not determine
* whether the mouse pointer is in the upper or lower
* half of the element we are dragging over. In other
* browsers we can use event.offsetY for this.
*/
.simpleDemo ul[dnd-list] li {
background-color: #fff;
border: 1px solid #ddd;
border-top-right-radius: 4px;
border-top-left-radius: 4px;
display: block;
padding: 10px 15px;
margin-bottom: -1px;
}
/**
* Show selected elements in green
*/
.simpleDemo ul[dnd-list] li.selected {
background-color: #dff0d8;
color: #3c763d;
}
<div class="row">
<h1>Questionaire</h1>
<div id="items" class="span12 " >
<nav class="cbp-spmenu cbp-spmenu-verticals" id="cbp-spmenu-s2">
<h3>Below items are draggable:</h3>
<ul dnd-list="draggedQuestion">
<li
dnd-draggable="item"
dnd-moved="draggedQuestion.push()"
dnd-effect-allowed="copy"
ng-repeat="item in dragItems" id="{{item.itemId}}"><a>{{ item.title }}</a></li>
</ul>
</nav>
</div>
<br/><br/>
<div class="span8" id="container">
<div class="panel panel-primary">
<div class="panel-heading">Drop items here</div>
<div class="panel-body fixed-panel">
<table>
<tbody dnd-list="draggedQuestion" >
<tr ng-repeat="question in draggedQuestion"
dnd-draggable="question"
dnd-moved="draggedQuestion.splice($index, 1)"
dnd-effect-allowed="move"
class="background-{{draggedQuestion.itemId}}">
<td class="list-group-item">
<div ng-if="question.itemId == '1'" class="panel panel-warning">
<div class="panel-heading" ng-bind="question.title">
</div>
<div class="panel-body">
<div align="right">
<button type="button" class="btn btn-danger" ng-click="remove($index)" >
<span class="glyphicon glyphicon-remove " aria-hidden="true"></span>
</button>
</div>
<br/>
<input type="text" class="form-control" placeholder="Enter question here" ng-model="ques" /><br>
<input type="radio"/>Yes<br/>
<input type="radio"/>No<br/>
</div>
</div>
<div ng-if="question.itemId == '2'" class="panel panel-success">
<div class="panel-heading" ng-bind="question.title"></div>
<div class="panel-body">
<div align="right">
<button type="button" class="btn btn-danger" ng-click="remove($index)" >
<span class="glyphicon glyphicon-remove " aria-hidden="true"></span>
</button>
</div>
<br/>
<div ng-bind="question.itemId" droppable="true"></div>
</div>
</div>
<div ng-if="question.itemId == '3'" class="panel panel-info">
<div class="panel-heading" ng-bind="question.title"></div>
<div class="panel-body">
<div align="right">
<button type="button" class="btn btn-danger" ng-click="remove($index)" >
<span class="glyphicon glyphicon-remove " aria-hidden="true"></span>
</button>
</div>
<br/>
<input type="text" placeholder="Enter Comments here" class="form-control" ng-model="comm" /><br>
</div>
</div>
</td>
</tr>
</tbody>
</table>
'use strict';
var app=angular.module('dndWithD3App');
app.controller('MainCtrl', ['$scope','filterFilter', 'Restangular',
function($scope, filterFilter, Restangular, storage) {
var randomData, t, sampleData, init;
randomData = function() {
return Math.round(Math.random() * 25);
};
$scope.remove = function($index) {
$scope.draggedQuestion.splice($index, 1);
}
$scope.dragItems = [{
title: "Questions",
itemId: 1
}, {
title: "Sections",
itemId: 2
}, {
title: "Comments",
itemId: 3
}];
$scope.handleDragStart = function(e) {
this.style.opacity = '0.4';
e.dataTransfer.setData('text', this.id);
};
$scope.handleDragEnd = function(e) {
this.style.opacity = '1';
};
$scope.handleDragEnter = function(e) {
this.classList.add('over-drop-area');
};
$scope.handleDragLeave = function(e) {
this.classList.remove('over-drop-area');
};
$scope.handleDrop = function(e) {
if (e.preventDefault) {
e.preventDefault();
}
if (e.stopPropogation) {
e.stopPropogation();
}
console.log(this);
var dataText = e.dataTransfer.getData("text");
$scope.draggedItem = [];
$scope.draggedItem = filterFilter($scope.dragItems, dataText);
$scope.$apply(function() {
$scope.showTemplate();
});
return false;
};
$scope.handleDragOver = function(e) {
if (e.preventDefault) {
e.preventDefault();
}
e.dataTransfer.dropEffect = 'copy';
return false;
};
$scope.showTemplate = function() {
if ($scope.draggedQuestion == null) {
$scope.draggedQuestion = [];
}
$scope.draggedQuestion.push({
title: $scope.draggedItem[0].title,
itemId: $scope.draggedItem[0].itemId
});
}
}
]);
'use strict';
angular.module('dndWithD3App').directive('draggable', function() {
return {
restrict : "A",
link : function(scope, element, attrs) {
element[0].addEventListener("dragstart", scope.handleDragStart, false);
element[0].addEventListener("dragend", scope.handleDragEnd, false);
element[0].addEventListener("dragenter", scope.handleDragEnter, false);
element[0].addEventListener("dragleave", scope.handleDragLeave, false);
}
}
});
'use strict';
angular.module('dndWithD3App').directive('droppable', function() {
return {
restrict : "A",
link : function(scope, element, attrs) {
element[0].addEventListener("drop", scope.handleDrop, false);
element[0].addEventListener("dragover", scope.handleDragOver, false);
}
}
});
angular.module("dndLists",[]).directive("dndDraggable",["$parse","$timeout","dndDropEffectWorkaround","dndDragTypeWorkaround",function(e,n,r,t){return function(a,o,d){o.attr("draggable","true"),d.dndDisableIf&&a.$watch(d.dndDisableIf,function(e){o.attr("draggable",!e)}),o.on("dragstart",function(i){i=i.originalEvent||i,i.dataTransfer.setData("Text",angular.toJson(a.$eval(d.dndDraggable))),i.dataTransfer.effectAllowed=d.dndEffectAllowed||"move",o.addClass("dndDragging"),n(function(){o.addClass("dndDraggingSource")},0),r.dropEffect="none",t.isDragging=!0,t.dragType=d.dndType?a.$eval(d.dndType):void 0,e(d.dndDragstart)(a,{event:i}),i.stopPropagation()}),o.on("dragend",function(i){i=i.originalEvent||i;var f=r.dropEffect;a.$apply(function(){switch(f){case"move":e(d.dndMoved)(a,{event:i});break;case"copy":e(d.dndCopied)(a,{event:i});break;case"none":e(d.dndCanceled)(a,{event:i})}e(d.dndDragend)(a,{event:i,dropEffect:f})}),o.removeClass("dndDragging"),n(function(){o.removeClass("dndDraggingSource")},0),t.isDragging=!1,i.stopPropagation()}),o.on("click",function(n){d.dndSelected&&(n=n.originalEvent||n,a.$apply(function(){e(d.dndSelected)(a,{event:n})}),n.stopPropagation())}),o.on("selectstart",function(){this.dragDrop&&this.dragDrop()})}}]).directive("dndList",["$parse","$timeout","dndDropEffectWorkaround","dndDragTypeWorkaround",function(e,n,r,t){return function(a,o,d){function i(e,n,r){var t=y?e.offsetX||e.layerX:e.offsetY||e.layerY,a=y?n.offsetWidth:n.offsetHeight,o=y?n.offsetLeft:n.offsetTop;return o=r?o:0,o+a/2>t}function f(){var e;return angular.forEach(o.children(),function(n){var r=angular.element(n);r.hasClass("dndPlaceholder")&&(e=r)}),e||angular.element("<li class='dndPlaceholder'></li>")}function l(){return Array.prototype.indexOf.call(D.children,v)}function g(e){if(!t.isDragging&&!E)return!1;if(!c(e.dataTransfer.types))return!1;if(d.dndAllowedTypes&&t.isDragging){var n=a.$eval(d.dndAllowedTypes);if(angular.isArray(n)&&-1===n.indexOf(t.dragType))return!1}return d.dndDisableIf&&a.$eval(d.dndDisableIf)?!1:!0}function s(){return p.remove(),o.removeClass("dndDragover"),!0}function u(n,r,o,d){return e(n)(a,{event:r,index:o,item:d||void 0,external:!t.isDragging,type:t.isDragging?t.dragType:void 0})}function c(e){if(!e)return!0;for(var n=0;n<e.length;n++)if("Text"===e[n]||"text/plain"===e[n])return!0;return!1}var p=f(),v=p[0],D=o[0];p.remove();var y=d.dndHorizontalList&&a.$eval(d.dndHorizontalList),E=d.dndExternalSources&&a.$eval(d.dndExternalSources);o.on("dragover",function(e){if(e=e.originalEvent||e,!g(e))return!0;if(v.parentNode!=D&&o.append(p),e.target!==D){for(var n=e.target;n.parentNode!==D&&n.parentNode;)n=n.parentNode;n.parentNode===D&&n!==v&&(i(e,n)?D.insertBefore(v,n):D.insertBefore(v,n.nextSibling))}else if(i(e,v,!0))for(;v.previousElementSibling&&(i(e,v.previousElementSibling,!0)||0===v.previousElementSibling.offsetHeight);)D.insertBefore(v,v.previousElementSibling);else for(;v.nextElementSibling&&!i(e,v.nextElementSibling,!0);)D.insertBefore(v,v.nextElementSibling.nextElementSibling);return d.dndDragover&&!u(d.dndDragover,e,l())?s():(o.addClass("dndDragover"),e.preventDefault(),e.stopPropagation(),!1)}),o.on("drop",function(e){if(e=e.originalEvent||e,!g(e))return!0;e.preventDefault();var n,t=e.dataTransfer.getData("Text")||e.dataTransfer.getData("text/plain");try{n=JSON.parse(t)}catch(o){return s()}var i=l();if(d.dndDrop&&(n=u(d.dndDrop,e,i,n),!n))return s();var f=a.$eval(d.dndList);return a.$apply(function(){f.splice(i,0,n)}),u(d.dndInserted,e,i,n),r.dropEffect="none"===e.dataTransfer.dropEffect?"copy"===e.dataTransfer.effectAllowed||"move"===e.dataTransfer.effectAllowed?e.dataTransfer.effectAllowed:e.ctrlKey?"copy":"move":e.dataTransfer.dropEffect,s(),e.stopPropagation(),!1}),o.on("dragleave",function(e){e=e.originalEvent||e,o.removeClass("dndDragover"),n(function(){o.hasClass("dndDragover")||p.remove()},100)})}}]).directive("dndNodrag",function(){return function(e,n){n.attr("draggable","true"),n.on("dragstart",function(e){e=e.originalEvent||e,e.dataTransfer.types&&e.dataTransfer.types.length||e.preventDefault(),e.stopPropagation()}),n.on("dragend",function(e){e=e.originalEvent||e,e.stopPropagation()})}}).factory("dndDragTypeWorkaround",function(){return{}}).factory("dndDropEffectWorkaround",function(){return{}});