|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<title>D3 Drag Drop Example</title> |
|
<script src="http://d3js.org/d3.v3.min.js"></script> |
|
<script src="http://codeorigin.jquery.com/jquery-1.10.2.min.js"></script> |
|
<script src="http://codeorigin.jquery.com/ui/1.10.3/jquery-ui.min.js"></script> |
|
|
|
<style> |
|
body { |
|
height: 100%; |
|
text-align: center; |
|
padding: 1rem; |
|
} |
|
.col { |
|
display: inline-block; |
|
width: 200px; |
|
vertical-align: top; |
|
} |
|
ul { |
|
margin: 0; padding: 0; |
|
} |
|
li { |
|
margin: 0 0 .3rem 0; |
|
padding: .3rem; |
|
list-style: none; |
|
background-color: #fff; |
|
background-color: rgba(255,255,255,.8); |
|
font: .8rem/1 arial, helvetica, sans-serif; |
|
border: 1px #7f7f7f solid; |
|
} |
|
li.ui-draggable { |
|
cursor: move; |
|
} |
|
li.ui-state-disabled { |
|
cursor: not-allowed; |
|
opacity: .5; |
|
} |
|
rect { |
|
stroke: #7f7f7f; |
|
stroke-width: 1 |
|
} |
|
text { |
|
font-family: arial, helvetica, sans-serif; |
|
font-size: 20px; |
|
fill: #fff; |
|
} |
|
.color1 { fill: #1f77b4; } |
|
.color2 { fill: #2ca02c; } |
|
.color3 { fill: #9467bd; } |
|
</style> |
|
</head> |
|
<body> |
|
|
|
<div class="col droptargets"></div> |
|
<div class="col draggables"></div> |
|
|
|
<script> |
|
// -- |
|
// Setup: Creating the dataset and placing the data in the document. |
|
// -- |
|
|
|
// Establish our dataset |
|
var dwarfSet = { |
|
Fairytale : ["Blick","Flick","Glick","Quee"], |
|
Tolkien : ["Thorin","Gloin","Fili","Kili"], |
|
Pratchett : ["Carrot","Goodmountain","Littlebottom"] |
|
} |
|
|
|
var types = d3.keys(dwarfSet); |
|
var dwarves = d3.shuffle(d3.merge(d3.values(dwarfSet))); |
|
|
|
// Droppable items on the right |
|
var draggables = d3.select(".draggables").append("ul"); |
|
draggables.selectAll("li").data(dwarves).enter() |
|
.append("li") |
|
.text(function(d) { return d }) |
|
|
|
// Drop targets on the left |
|
var canvas = d3.select(".droptargets").append("svg") |
|
.attr("width",200) |
|
.attr("height",400) |
|
.attr("class","YlGn"); |
|
|
|
var dropTargets = canvas.selectAll("rect").data(types).enter().append("g") |
|
|
|
dropTargets.append("rect") |
|
.attr({ |
|
width: 180, |
|
height: 100, |
|
x: 10.5, |
|
y: function(d,i) { return (i * 110) + .5}, |
|
rx: 20, |
|
ry: 20, |
|
class: function(d,i) { return "color" + (i+1) } |
|
}) |
|
|
|
dropTargets.append("text") |
|
.text(function (d) { return d }) |
|
.attr({ |
|
x: 25.5, |
|
dy: 30, |
|
y: function(d,i) { return (i * 110) + .5} |
|
}); |
|
|
|
// --- |
|
// Handle dragging from HTML to dropping on SVG |
|
// --- |
|
var DragDropManager = { |
|
dragged: null, |
|
droppable: null, |
|
draggedMatchesTarget: function() { |
|
if (!this.droppable) return false; |
|
return (dwarfSet[this.droppable].indexOf(this.dragged) >= 0); |
|
} |
|
} |
|
|
|
var body = d3.select("body"); |
|
|
|
// Register the associated element as a potential target on mouseOver |
|
// D3 events call listeners with the current datum |
|
// and index, so this is straightforward. |
|
dropTargets.on('mouseover',function(d,i){ |
|
DragDropManager.droppable = d; |
|
}); |
|
|
|
// Clear the target from the DragDropManager on mouseOut. |
|
dropTargets.on('mouseOut',function(e){ |
|
DragDropManager.droppable = null; |
|
}); |
|
|
|
// Set up jqueryUI's draggable on the list items |
|
// |
|
// Note that we have to move helper out of the way of the cursor |
|
// using the "cursorAt" property; otherwise the cursor will be |
|
// located over the helper and the SVG element's mouseover/mouseout |
|
// events will not fire. |
|
|
|
$(".draggables li").draggable({ |
|
revert: true, |
|
revertDuration: 200, |
|
cursorAt: { left: -2, top: -2 }, |
|
|
|
// Register what we're dragging with the drop manager |
|
start: function (e) { |
|
// Getting the datum from the standard event target requires more work. |
|
DragDropManager.dragged = d3.select(e.target).datum(); |
|
}, |
|
// Set cursors based on matches, prepare for a drop |
|
drag: function (e) { |
|
matches = DragDropManager.draggedMatchesTarget(); |
|
body.style("cursor",function() { |
|
return (matches) ? "copy" : "move"; |
|
}); |
|
// Eliminate the animation on revert for matches. |
|
// We have to set the revert duration here instead of "stop" |
|
// in order to have the change take effect. |
|
$(e.target).draggable("option","revertDuration",(matches) ? 0 : 200) |
|
}, |
|
// Handle the end state. For this example, disable correct drops |
|
// then reset the standard cursor. |
|
stop: function (e,ui) { |
|
// Dropped on a non-matching target. |
|
if (!DragDropManager.draggedMatchesTarget()) return; |
|
$(e.target).draggable("disable"); |
|
$("body").css("cursor",""); |
|
} |
|
}); |
|
|
|
</script> |
|
</body> |
|
</html> |