introductory fun with force layouts
check repo and DL for example with the image files... having issues getting github to serve the png's
xxxxxxxxxx
<meta charset="utf-8">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<style>
.control-bar {
padding-top:150px;
}
.svgs {
}
.svgs :hover {
}
.link {
stroke: #999;
stroke-opacity: .6;
}
.nodegroup {
fill-opacity:0.75;
overflow:;
}
.nodegroup :hover {
fill-opacity:0.95;
}
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.innerText {
font-size:12px;
}
.foreign{
opacity:0;
overflow:hidden;
}
.foreign body {
height:106px;
background-color:rgba(255,255,255,0);
border-color:white;
border-style: solid;
border-width:2px;
border-radius:10px;
padding:10px;
overflow:hidden;
}
</style>
<body>
<div class="container">
<div class="row">
<div class="col-xs-10 col-sm-10 col-md-10 col-lg-10 vis"></div>
<div class="col-xs-2 col-sm-2 col-md-2 col-lg-2 control-bar">
<p>
<label for="charge"
style="display: inline-block; width: 240px; text-align: right">
Charge = <span id="charge-value">-404</span>
</label>
<input type="range" min="-999" max="999" step="1" value="-404" id="charge">
</p>
<p>
<label for="gravity"
style="display: inline-block; width: 240px; text-align: right">
Gravity = <span id="gravity-value">0.04</span>
</label>
<input type="range" min="0" max="1" step="0.01" value="0.04" id="gravity">
</p>
<button class ="btn btn-default" onclick="getNewNodes()">New Nodes</button>
</div>
</div>
</div>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script>
var WIDTH = 800;
var HEIGHT = 600;
var c10 = d3.scale.category10();
//var data = genNodes();
var data = [{id: 01,
name: "herb",
amount:"220",
imgURL:"./data/face00.png"},
{id: 02,
name: "derp",
amount:"330",
imgURL:"./data/face01.png"},
{id: 03,
name: "foo",
amount:"490",
imgURL:"./data/face02.png"},
{id: 04,
name: "bar",
amount:"290",
imgURL:"./data/face03.png"},
{id: 05,
name: "blip",
amount:"490",
imgURL:"./data/face04.png"},
{id: 06,
name: "asdflk",
amount:"390",
imgURL:"./data/face05.png"}];
var force = d3.layout.force()
.nodes(data)
.size([WIDTH, HEIGHT])
.charge(-300)
.gravity(0.1)
.alpha(0.1)
.on("tick", tick)
.start();
var vis = d3.select('.vis').append('g');
vis.attr('class','svggroup');
var svgs = vis.append('svg')
.attr('class','svgs')
.attr('height', HEIGHT)
.attr('width', WIDTH);
var groups = svgs.selectAll("g")
.data(force.nodes())
.enter()
.append("g")
.attr("class","nodegroup");
//enter
var node = groups
.append("circle")
.style("fill", function(d,i) { return c10(i);})
.attr("r", function(d) { return Math.sqrt(d.amount)})
.attr("class", "node")
.call(force.drag);
node
.on("mouseover", function(selected) {
//force.stop();
d3.select(this).transition()
.duration(500)
.attr("r", 75);
//bring node to front
d3.selectAll('.nodegroup')
.sort(function(a, b) {
if (a.id === selected.id) {
return 1;
} else {
if (b.id === selected.id) {
return -1;
} else {
return 0;
}
}
});
//force.resume();
//append text to parent group, not the circle
//d3.select(this.parentNode).append("text")
// .attr("class", "innerText")
// .attr("text-anchor", "middle")
// .attr("fill", "black")
// .text(function(d) {
// return d.name;
// })
// .attr("pointer-events","none") // this eliminates the loss of :hover when directly over the text
// .attr("transform", function(d) {
// return 'translate(' + [d.x, d.y] + ')';
// });
//append foreign html to group
d3.select(this.parentNode).append("foreignObject")
.attr("width", 150/Math.sqrt(2))
.attr("height", 150/Math.sqrt(2))
.attr("class","foreign")
.attr("pointer-events","none")
.attr("transform", function(d) {
return 'translate(' + [(d.x-75/Math.sqrt(2)), (d.y-75/Math.sqrt(2))] + ')';
})
.append("xhtml:body")
.style("font", "8px 'Helvetica Neue'")
.html(function(d,i) {
return "<img src="+d.imgURL+" style='width:48px;height:48px;float:right;padding-bottom:5px'> "+"<bold>Name:</bold> " + d.name +"<br><bold>Description:</bold>In imperdiet rutrum porttitor. In nec risus eu leo sodales lobortis."
});
d3.select(".foreign").transition()
.delay(300)
.duration(1000)
.style("opacity",1);
})
.on("mouseout", function(){
d3.select(this).transition()
.duration(500)
.attr("r", function(d) { return Math.sqrt(d.amount)});
//remove text console.log(this.getBBox());
//d3.select(this.parentNode).select("text").remove();
d3.select(".foreign").remove();
});
//setup inputs
d3.selectAll("input").on("input", function() {
update(this.id, this.value);
});
function update(property, value) {
d3.select("#"+property+"-value").text(value);
//force.stop(); //is this neccessary?
if(property == "charge") {
force.charge(value);
force.start();
console.log("changing force.charge(" +value+")");
}
else if (property == "gravity") {
force.gravity(value);
force.start();
console.log("changing force.gravity(" +value+")");
}
}
//tick
function tick () {
//here be the magic
node.attr("cx", function(d) {return d.x})
.attr("cy", function(d) {return d.y});
//d3.selectAll('text').attr("transform", function(d) {
// return 'translate(' + [d.x, d.y] + ')';
// })
d3.selectAll('.foreign').attr("transform", function(d) {
return 'translate(' + [(d.x-75/Math.sqrt(2)), (d.y-75/Math.sqrt(2))] + ')';
})
}
function charge(d) {
return d.amount * d.amount * -0.25;
}
//generate random nodes
function genNode() {
var maxAmt = 400;
var amt = Math.floor(Math.random()*maxAmt+1);
return {amount:amt};
}
function genNodes() {
var newNodes = [];
var maxNodes = 10;
var n = Math.floor(Math.random()*maxNodes+4);
for (var i =0; i< n; i++) {
newNodes.push(genNode());
}
return newNodes;
}
function getNewNodes() { location.reload();}
</script>
https://d3js.org/d3.v3.min.js
https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js
https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js