Created
November 25, 2012 21:15
-
-
Save endocrimes/4145390 to your computer and use it in GitHub Desktop.
Clustered Force Layout + Custom Gravity with Pan & Zoom, importing a Json file & Canvas boundaries
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "Products", | |
"children": [ | |
{ | |
"name": "Cluster1", | |
"children": [ | |
{ | |
"name": "Supplier: OHG", | |
"children": [ | |
{ | |
"name": "Palma Hotel", | |
"size": 26 | |
}, | |
{ | |
"name": "Pineta Hotel", | |
"size": 26 | |
}, | |
{ | |
"name": "Histria Hotel", | |
"size": 26 | |
}, | |
{ | |
"name": "Medulin Hotel", | |
"size": 26 | |
}, | |
{ | |
"name": "Valdaliso Hotel", | |
"size": 26 | |
}, | |
{ | |
"name": "Grand Hotel Orebic", | |
"size": 26 | |
}, | |
{ | |
"name": "Villa Erna", | |
"size": 26 | |
}, | |
{ | |
"name": "Villa Amfora Dubrovnik", | |
"size": 26 | |
}, | |
{ | |
"name": "Villa Katarina", | |
"size": 26 | |
}, | |
{ | |
"name": "Apartments Marina", | |
"size": 26 | |
}, | |
{ | |
"name": "Hotel As", | |
"size": 26 | |
}, | |
{ | |
"name": "Apartments Ana", | |
"size": 26 | |
} | |
] | |
}, | |
{ | |
"name": "Supplier: Cosmos", | |
"children": [] | |
}, | |
{ | |
"name": "Supplier: Adriatica", | |
"children": [ | |
{ | |
"name": "Hotel Nimfa", | |
"size": 26 | |
}, | |
{ | |
"name": "Bluesun Hotel Bonaca", | |
"size": 26 | |
}, | |
{ | |
"name": "H. Valamar Dubrovnik President", | |
"size": 26 | |
}, | |
{ | |
"name": "Valamar Club Dubrovnik", | |
"size": 26 | |
}, | |
{ | |
"name": "Hotel Tirena", | |
"size": 26 | |
}, | |
{ | |
"name": "Hotel Valamar Club Tamaris", | |
"size": 26 | |
}, | |
{ | |
"name": "Hotel Mediteran", | |
"size": 26 | |
}, | |
{ | |
"name": "Hotel Zorna", | |
"size": 26 | |
}, | |
{ | |
"name": "Hotel Laguna Albatros", | |
"size": 26 | |
}, | |
{ | |
"name": "Hotel Park ", | |
"size": 26 | |
}, | |
{ | |
"name": "Bluesun Hotel Neptun", | |
"size": 26 | |
}, | |
{ | |
"name": "Hotel Meteor", | |
"size": 26 | |
}, | |
{ | |
"name": "Hotel Punta", | |
"size": 26 | |
}, | |
{ | |
"name": "Hotel Argosy", | |
"size": 26 | |
} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "Cluster 2", | |
"children": [ | |
{ | |
"name": "Supplier: OHG", | |
"children": [ | |
{ | |
"name": "Family Apartments NOVI", | |
"size": 10 | |
}, | |
{ | |
"name": "Belvedere Resort", | |
"size": 10 | |
}, | |
{ | |
"name": "Plat Hotels & Villas", | |
"size": 10 | |
}, | |
{ | |
"name": "Petalon Resort", | |
"size": 10 | |
}, | |
{ | |
"name": "Bluesun Apartments Alan", | |
"size": 10 | |
}, | |
{ | |
"name": "Medena Apartments", | |
"size": 10 | |
}, | |
{ | |
"name": "Vranjica Belvedere Apartments", | |
"size": 10 | |
}, | |
{ | |
"name": "The Residence Hotel", | |
"size": 10 | |
}, | |
{ | |
"name": "Imperial Hotel", | |
"size": 10 | |
}, | |
{ | |
"name": "Miran Hotel", | |
"size": 10 | |
} | |
] | |
}, | |
{ | |
"name": "Supplier: Cosmos", | |
"children": [] | |
}, | |
{ | |
"name": "Supplier: Adriatica", | |
"children": [] | |
} | |
] | |
}, | |
{ | |
"name": "Cluster 3", | |
"children": [ | |
{ | |
"name": "Supplier: OHG", | |
"children": [ | |
{ | |
"name": "Feral Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Marco Polo Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Korcula Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Hedera Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Narcis Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Conte Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Pinija Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Vis Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Liburna Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Park Hotel Rovinj", | |
"size": 72 | |
}, | |
{ | |
"name": "Mimosa Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Biokovo Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Astarea 2 Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Dubrovnik Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Zagreb Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Adriatic Hotel Biograd n/m", | |
"size": 72 | |
}, | |
{ | |
"name": "Kornati Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Tragos Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Lafodia Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Medena Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Solaris Hotel Ivan", | |
"size": 72 | |
}, | |
{ | |
"name": "Solaris Hotel Jure", | |
"size": 72 | |
}, | |
{ | |
"name": "Solaris Hotel Niko", | |
"size": 72 | |
}, | |
{ | |
"name": "Bluesun Hotel Borak", | |
"size": 72 | |
}, | |
{ | |
"name": "Sagitta Holiday Village", | |
"size": 72 | |
}, | |
{ | |
"name": "Croatia Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Iberostar Albatros Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Iberostar Epidaurus Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Astarea 1 Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Sumratin Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Ariston Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Dubrovnik Palace Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "More Hotel Dubrovnik", | |
"size": 72 | |
}, | |
{ | |
"name": "Rixos Libertas Dubrovnik", | |
"size": 72 | |
}, | |
{ | |
"name": "Lero Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Splendid Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Uvala Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Berkeley Hotel Dubrovnik", | |
"size": 72 | |
}, | |
{ | |
"name": "Komodor Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Kompas Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Admiral Grand Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Bellevue Hotel Orebic", | |
"size": 72 | |
}, | |
{ | |
"name": "Podgorka Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Bella Vista Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Zora Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Solaris Hotel Andrija", | |
"size": 72 | |
}, | |
{ | |
"name": "Solaris Hotel Jakov", | |
"size": 72 | |
}, | |
{ | |
"name": "Olympia Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Bluesun Hotel Elaphusa", | |
"size": 72 | |
}, | |
{ | |
"name": "Bluesun Hotel Bonaca", | |
"size": 72 | |
}, | |
{ | |
"name": "Diadem Aparthotel", | |
"size": 72 | |
}, | |
{ | |
"name": "The View Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Aurora Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Ambasador Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Admiral Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Kristal Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Cavtat Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Adriatic Hotel Dubrovnik", | |
"size": 72 | |
}, | |
{ | |
"name": "Neptun Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Eden Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Istra Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Maestral Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Laguna Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Dalmacija Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Minerva Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Punta Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Punta Complex - Villa Arausa Arausana Antonina", | |
"size": 72 | |
}, | |
{ | |
"name": "Bluesun Hotel Alan", | |
"size": 72 | |
}, | |
{ | |
"name": "Ilirija Hotel", | |
"size": 72 | |
}, | |
{ | |
"name": "Adriatiq Hotel Hvar", | |
"size": 72 | |
}, | |
{ | |
"name": "Waterman Svpetrvs Resort", | |
"size": 72 | |
}, | |
{ | |
"name": "Meteor Hotel", | |
"size": 72 | |
} | |
] | |
}, | |
{ | |
"name": "Supplier: Cosmos", | |
"children": [] | |
}, | |
{ | |
"name": "Supplier: Adriatica", | |
"children": [] | |
} | |
] | |
}, | |
{ | |
"name": "Cluster 4", | |
"children": [ | |
{ | |
"name": "Supplier: OHG", | |
"children": [ | |
{ | |
"name": "Marina Hotel", | |
"size": 27 | |
} | |
] | |
}, | |
{ | |
"name": "Supplier: Cosmos", | |
"children": [] | |
}, | |
{ | |
"name": "Supplier: Adriatica", | |
"children": [ | |
{ | |
"name": "Hotel Vis", | |
"size": 27 | |
}, | |
{ | |
"name": "Bluesun Hotel Marina", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Jure", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Niko", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Ivan", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Istra", | |
"size": 27 | |
}, | |
{ | |
"name": "Bluesun Hotel Elaphusa", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Neptun", | |
"size": 27 | |
}, | |
{ | |
"name": "GH Park", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Adriatica", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Medulin", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Plavi", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Laguna Molindrio", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Pical", | |
"size": 27 | |
}, | |
{ | |
"name": "Valamar Pinia", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Park Plaza Verudela", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Amfora", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Sol Garden Istra", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Podgorka", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Lero", | |
"size": 27 | |
}, | |
{ | |
"name": "Bluesun Hotel Alga", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotelsko naselje Waterman ", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Aurora", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Opatija", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Minerva", | |
"size": 27 | |
}, | |
{ | |
"name": "Hotel Ariston ", | |
"size": 27 | |
} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "Cluster 5", | |
"children": [ | |
{ | |
"name": "Supplier: OHG", | |
"children": [ | |
{ | |
"name": "Valamar Lacroma Dubrovnik", | |
"size": 6 | |
}, | |
{ | |
"name": "The Pucic Palace", | |
"size": 6 | |
}, | |
{ | |
"name": "Hotel Luxe", | |
"size": 6 | |
}, | |
{ | |
"name": "Jupiter Luxury Hotel", | |
"size": 6 | |
}, | |
{ | |
"name": "Hotel Lapad", | |
"size": 6 | |
} | |
] | |
}, | |
{ | |
"name": "Supplier: Cosmos", | |
"children": [ | |
{ | |
"name": "Hotel Uvala", | |
"size": 6 | |
} | |
] | |
}, | |
{ | |
"name": "Supplier: Adriatica", | |
"children": [] | |
} | |
] | |
}, | |
{ | |
"name": "Cluster 6", | |
"children": [ | |
{ | |
"name": "Supplier: OHG", | |
"children": [ | |
{ | |
"name": "Grand Villa Argentina", | |
"size": 6 | |
}, | |
{ | |
"name": "Hotel Bellevue Dubrovnik", | |
"size": 6 | |
} | |
] | |
}, | |
{ | |
"name": "Supplier: Cosmos", | |
"children": [ | |
{ | |
"name": "Grand Hotel Park", | |
"size": 6 | |
}, | |
{ | |
"name": "Hilton Imperial Dubrovnik", | |
"size": 6 | |
}, | |
{ | |
"name": "Hotel Dubrovnik Palace", | |
"size": 6 | |
} | |
] | |
}, | |
{ | |
"name": "Supplier: Adriatica", | |
"children": [ | |
{ | |
"name": "Hotel Excelsior", | |
"size": 6 | |
} | |
] | |
} | |
] | |
}, | |
{ | |
"name": "Cluster 7", | |
"children": [ | |
{ | |
"name": "Supplier: OHG", | |
"children": [ | |
{ | |
"name": "Hilton Imperial Dubrovnik", | |
"size": 4 | |
}, | |
{ | |
"name": "Grand Hotel Park", | |
"size": 4 | |
} | |
] | |
}, | |
{ | |
"name": "Supplier: Cosmos", | |
"children": [] | |
}, | |
{ | |
"name": "Supplier: Adriatica", | |
"children": [ | |
{ | |
"name": "Hotel Excelsior", | |
"size": 4 | |
}, | |
{ | |
"name": "Hotel Dubrovnik Palace", | |
"size": 4 | |
} | |
] | |
} | |
] | |
} | |
] | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE HTML> | |
<html lang="en"> | |
<head> | |
<title>Data-Driven Documents</title> | |
<link rel="stylesheet" href="main.css"> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
</head> | |
<body> | |
<script> | |
// drawing the graph | |
var drawthegraphthing = function(data, numclusters) { | |
// basics | |
var margin = {top: 0, right: 0, bottom: 0, left: 0}, | |
width = 1352 - margin.left - margin.right, | |
height = 630 - margin.top - margin.bottom; | |
var n = data.length, | |
m = numclusters, | |
padding = 12, | |
radius = d3.scale.sqrt().range([0, 6]), | |
color = d3.scale.category10().domain(d3.range(m)); | |
// cluster coloring | |
var clusterColours = []; | |
var getClusterColour = function(clusterName) { | |
for (var cluster = 0; cluster < clusterColours.length; ++cluster) { | |
if (clusterColours[cluster].name == clusterName) { | |
return clusterColours[cluster].colour; | |
} | |
} | |
var colour = { | |
name: clusterName, | |
colour: color(clusterColours.length) | |
}; | |
clusterColours.push(colour); | |
return colour.colour; | |
}; | |
// nodes & svg's | |
var nodes = d3.range(n).map(function(a, b, c, d, e) { | |
var node = data[a]; | |
return { | |
data: node, | |
color: getClusterColour(node.cluster), | |
radius: radius(node.size) | |
}; | |
}); | |
function svg() { | |
this.style("left", function(d) { return d.x + "px"; }) | |
} | |
// defining the position | |
function position() { | |
this.style("left", function(d) { return d.x + "px"; }) | |
.style("top", function(d) { return d.y + "px"; }) | |
.style("width", function(d) { return Math.max(0, d.dx - 1) + "px"; }) | |
.style("height", function(d) { return Math.max(0, d.dy - 1) + "px"; }); | |
} | |
// forced layout | |
var force = d3.layout.force() | |
.nodes(nodes) | |
.size([width, height]) | |
.gravity(0) | |
.charge(0) | |
.linkDistance(20) | |
.on("tick", tick) | |
.start(); | |
// declaring | |
var svg = d3.select("body").append("svg","div") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
var body = d3.selectAll("body") | |
.call(d3.behavior.zoom().scaleExtent([1, 168]).on("zoom", zoom)) | |
.append("g"); | |
// forming force | |
var circle = svg.selectAll("circle") | |
.data(nodes) | |
.enter().append("circle") | |
.attr("r", function(d) { return d.radius; }) | |
.style("fill", function(d) { return d.color; }) | |
.text(function(d) { return d.data.name; }) | |
.call(force.drag); | |
function tick(e) { | |
circle | |
.each(cluster(10 * e.alpha * e.alpha)) | |
.each(collide(.5)) | |
.attr("cx", function(d) { return d.x; }) | |
.attr("cy", function(d) { return d.y; }); | |
} | |
// Move d to be adjacent to the cluster node. | |
function cluster(alpha) { | |
var max = {}; | |
// locating the largest node in each cluster set | |
nodes.forEach(function(d) { | |
if (!(d.color in max) || (d.radius > max[d.color].radius)) { | |
max[d.color] = d; | |
} | |
}); | |
return function(d) { | |
var node = max[d.color], | |
l, | |
r, | |
x, | |
y, | |
i = -1; | |
if (node == d) return; | |
x = d.x - node.x; | |
y = d.y - node.y; | |
l = Math.sqrt(x * x + y * y); | |
r = d.radius + node.radius; | |
if (l != r) { | |
l = (l - r) / l * alpha; | |
d.x -= x *= l; | |
d.y -= y *= l; | |
node.x += x; | |
node.y += y; | |
} | |
}; | |
} | |
// resolving collisions | |
function collide(alpha) { | |
var quadtree = d3.geom.quadtree(nodes); | |
return function(d) { | |
var r = d.radius + radius.domain()[1] + padding, | |
nx1 = d.x - r, | |
nx2 = d.x + r, | |
ny1 = d.y - r, | |
ny2 = d.y + r; | |
quadtree.visit(function(quad, x1, y1, x2, y2) { | |
if (quad.point && (quad.point !== d)) { | |
var x = d.x - quad.point.x, | |
y = d.y - quad.point.y, | |
l = Math.sqrt(x * x + y * y), | |
r = d.radius + quad.point.radius + (d.color !== quad.point.color) * padding; | |
if (l < r) { | |
l = (l - r) / l * alpha; | |
d.x -= x *= l; | |
d.y -= y *= l; | |
quad.point.x += x; | |
quad.point.y += y; | |
} | |
} | |
return x1 > nx2 | |
|| x2 < nx1 | |
|| y1 > ny2 | |
|| y2 < ny1; | |
}); | |
}; | |
} | |
// zoom & pan | |
var x = d3.scale.linear() | |
.domain([-width / 2, width / 2]) | |
.range([0, width]); | |
var y = d3.scale.linear() | |
.domain([-height / 2, height / 2]) | |
.range([height, 0]); | |
svg.append("div") | |
.attr("width", width) | |
.attr("height", height); | |
function zoom() { | |
svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); | |
} | |
} | |
// building the graph | |
d3.json('flare.json', function(err, data, root, error, div) { | |
var nodeData = []; | |
var clusters = data.children; | |
for (var cluster = 0; cluster < clusters.length; ++cluster) { | |
var suppliers = clusters[cluster].children; | |
for (var supplier = 0; supplier < suppliers.length; ++supplier) { | |
var products = suppliers[supplier].children; | |
for (var product = 0; product < products.length; ++product) { | |
var node = { | |
cluster: clusters[cluster].name, | |
supplier: suppliers[supplier].name, | |
name: products[product].name, | |
size: suppliers.length | |
}; | |
nodeData.push(node); | |
} | |
} | |
} | |
drawthegraphthing(nodeData, clusters.length); | |
//console.log(nodeData); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment