Skip to content

Instantly share code, notes, and snippets.

@vladimir-ivanov
Created January 27, 2015 20:36
Show Gist options
  • Save vladimir-ivanov/df45ef30db82da69d7db to your computer and use it in GitHub Desktop.
Save vladimir-ivanov/df45ef30db82da69d7db to your computer and use it in GitHub Desktop.
force layout with lasso js
<html>
<head>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.js?2.4.6"></script>
<link href='http://mbostock.github.com/d3/ex/force.css' rel='stylesheet' type='text/css'/>
<script src='http://mbostock.github.com/d3/d3.layout.js?2.4.6' type='text/javascript'></script>
<script src='http://mbostock.github.com/d3/d3.geom.js?2.4.6' type='text/javascript'></script>
<script src="http://axc.net/code_libraries/lasso/lasso.min.js"></script>
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.dot {
stroke: #000;
}
.lasso path {
stroke: rgb(80, 80, 80);
stroke-width: 2px;
}
.lasso .drawn {
fill-opacity: .05;
}
.lasso .loop_close {
fill: none;
stroke-dasharray: 4, 4;
}
.lasso .origin {
fill: #3399FF;
fill-opacity: .5;
}
.not_possible {
fill: rgb(200, 200, 200);
}
.possible {
fill: #EC888C;
}
</style>
</head>
<body>
<div id="chart"></div>
</body>
<script>
var w = 500,
h = 500,
fill = d3.scale.category20();
var zoomBehaviour = d3.behavior.zoom().on("zoom", redraw);
var vis = d3.select("#chart")
.append("svg:svg")
.attr("width", w)
.attr("height", h)
.attr("pointer-events", "all")
.append('svg:g')
.call(zoomBehaviour)
.append('svg:g');
vis.append('svg:rect')
.attr('width', w)
.attr('height', h)
.attr('fill', 'white');
// Create the area where the lasso event can be triggered
var lasso_area = vis.append("rect")
.attr("width", w)
.attr("height", h)
.style("opacity", 0);
// Define the lasso
var lasso = d3.lasso()
.closePathDistance(75) // max distance for the lasso loop to be closed
.closePathSelect(true) // can items be selected by closing the path?
.hoverSelect(true) // can items by selected by hovering over them?
.area(lasso_area) // area where the lasso can be started
.on("start", lasso_start) // lasso start function
.on("draw", lasso_draw) // lasso draw function
.on("end", lasso_end); // lasso end function
function redraw() {
vis.attr("transform",
"translate(" + d3.event.translate + ")"
+ " scale(" + d3.event.scale + ")");
}
var draw = function (json) {
var force = d3.layout.force()
.charge(-120)
.linkDistance(30)
.nodes(json.nodes)
.links(json.links)
.size([w, h])
.start();
var link = vis.selectAll("line.link")
.data(json.links)
.enter().append("svg:line")
.attr("class", "link")
.style("stroke-width", function (d) {
return Math.sqrt(d.value);
})
.attr("x1", function (d) {
return d.source.x;
})
.attr("y1", function (d) {
return d.source.y;
})
.attr("x2", function (d) {
return d.target.x;
})
.attr("y2", function (d) {
return d.target.y;
});
var node = vis.selectAll("circle.node")
.data(json.nodes)
.enter().append("svg:circle")
.attr("class", "node")
.attr("cx", function (d) {
return d.x;
})
.attr("cy", function (d) {
return d.y;
})
.attr("r", 5)
.style("fill", function (d) {
return fill(d.group);
})
.call(force.drag);
node.append("svg:title")
.text(function (d) {
return d.name;
});
vis.style("opacity", 1e-6)
.transition()
.duration(1000)
.style("opacity", 1);
force.on("tick", function () {
link.attr("x1", function (d) {
return d.source.x;
})
.attr("y1", function (d) {
return d.source.y;
})
.attr("x2", function (d) {
return d.target.x;
})
.attr("y2", function (d) {
return d.target.y;
});
node.attr("cx", function (d) {
return d.x;
})
.attr("cy", function (d) {
return d.y;
});
});
lasso.items(d3.selectAll(".node"));
};
var data = {"nodes": [
{"name": "Myriel", "group": 1},
{"name": "Napoleon", "group": 1},
{"name": "Mlle.Baptistine", "group": 1},
{"name": "Mme.Magloire", "group": 1},
{"name": "CountessdeLo", "group": 1},
{"name": "Geborand", "group": 1},
{"name": "Champtercier", "group": 1},
{"name": "Cravatte", "group": 1},
{"name": "Count", "group": 1},
{"name": "OldMan", "group": 1},
{"name": "Labarre", "group": 2},
{"name": "Valjean", "group": 2},
{"name": "Marguerite", "group": 3},
{"name": "Mme.deR", "group": 2},
{"name": "Isabeau", "group": 2},
{"name": "Gervais", "group": 2},
{"name": "Tholomyes", "group": 3},
{"name": "Listolier", "group": 3},
{"name": "Fameuil", "group": 3},
{"name": "Blacheville", "group": 3},
{"name": "Favourite", "group": 3},
{"name": "Dahlia", "group": 3},
{"name": "Zephine", "group": 3},
{"name": "Fantine", "group": 3},
{"name": "Mme.Thenardier", "group": 4},
{"name": "Thenardier", "group": 4},
{"name": "Cosette", "group": 5},
{"name": "Javert", "group": 4},
{"name": "Fauchelevent", "group": 0},
{"name": "Bamatabois", "group": 2},
{"name": "Perpetue", "group": 3},
{"name": "Simplice", "group": 2},
{"name": "Scaufflaire", "group": 2},
{"name": "Woman1", "group": 2},
{"name": "Judge", "group": 2},
{"name": "Champmathieu", "group": 2},
{"name": "Brevet", "group": 2},
{"name": "Chenildieu", "group": 2},
{"name": "Cochepaille", "group": 2},
{"name": "Pontmercy", "group": 4},
{"name": "Boulatruelle", "group": 6},
{"name": "Eponine", "group": 4},
{"name": "Anzelma", "group": 4},
{"name": "Woman2", "group": 5},
{"name": "MotherInnocent", "group": 0},
{"name": "Gribier", "group": 0},
{"name": "Jondrette", "group": 7},
{"name": "Mme.Burgon", "group": 7},
{"name": "Gavroche", "group": 8},
{"name": "Gillenormand", "group": 5},
{"name": "Magnon", "group": 5},
{"name": "Mlle.Gillenormand", "group": 5},
{"name": "Mme.Pontmercy", "group": 5},
{"name": "Mlle.Vaubois", "group": 5},
{"name": "Lt.Gillenormand", "group": 5},
{"name": "Marius", "group": 8},
{"name": "BaronessT", "group": 5},
{"name": "Mabeuf", "group": 8},
{"name": "Enjolras", "group": 8},
{"name": "Combeferre", "group": 8},
{"name": "Prouvaire", "group": 8},
{"name": "Feuilly", "group": 8},
{"name": "Courfeyrac", "group": 8},
{"name": "Bahorel", "group": 8},
{"name": "Bossuet", "group": 8},
{"name": "Joly", "group": 8},
{"name": "Grantaire", "group": 8},
{"name": "MotherPlutarch", "group": 9},
{"name": "Gueulemer", "group": 4},
{"name": "Babet", "group": 4},
{"name": "Claquesous", "group": 4},
{"name": "Montparnasse", "group": 4},
{"name": "Toussaint", "group": 5},
{"name": "Child1", "group": 10},
{"name": "Child2", "group": 10},
{"name": "Brujon", "group": 4},
{"name": "Mme.Hucheloup", "group": 8}
], "links": [
{"source": 1, "target": 0, "value": 1},
{"source": 2, "target": 0, "value": 8},
{"source": 3, "target": 0, "value": 10},
{"source": 3, "target": 2, "value": 6},
{"source": 4, "target": 0, "value": 1},
{"source": 5, "target": 0, "value": 1},
{"source": 6, "target": 0, "value": 1},
{"source": 7, "target": 0, "value": 1},
{"source": 8, "target": 0, "value": 2},
{"source": 9, "target": 0, "value": 1},
{"source": 11, "target": 10, "value": 1},
{"source": 11, "target": 3, "value": 3},
{"source": 11, "target": 2, "value": 3},
{"source": 11, "target": 0, "value": 5},
{"source": 12, "target": 11, "value": 1},
{"source": 13, "target": 11, "value": 1},
{"source": 14, "target": 11, "value": 1},
{"source": 15, "target": 11, "value": 1},
{"source": 17, "target": 16, "value": 4},
{"source": 18, "target": 16, "value": 4},
{"source": 18, "target": 17, "value": 4},
{"source": 19, "target": 16, "value": 4},
{"source": 19, "target": 17, "value": 4},
{"source": 19, "target": 18, "value": 4},
{"source": 20, "target": 16, "value": 3},
{"source": 20, "target": 17, "value": 3},
{"source": 20, "target": 18, "value": 3},
{"source": 20, "target": 19, "value": 4},
{"source": 21, "target": 16, "value": 3},
{"source": 21, "target": 17, "value": 3},
{"source": 21, "target": 18, "value": 3},
{"source": 21, "target": 19, "value": 3},
{"source": 21, "target": 20, "value": 5},
{"source": 22, "target": 16, "value": 3},
{"source": 22, "target": 17, "value": 3},
{"source": 22, "target": 18, "value": 3},
{"source": 22, "target": 19, "value": 3},
{"source": 22, "target": 20, "value": 4},
{"source": 22, "target": 21, "value": 4},
{"source": 23, "target": 16, "value": 3},
{"source": 23, "target": 17, "value": 3},
{"source": 23, "target": 18, "value": 3},
{"source": 23, "target": 19, "value": 3},
{"source": 23, "target": 20, "value": 4},
{"source": 23, "target": 21, "value": 4},
{"source": 23, "target": 22, "value": 4},
{"source": 23, "target": 12, "value": 2},
{"source": 23, "target": 11, "value": 9},
{"source": 24, "target": 23, "value": 2},
{"source": 24, "target": 11, "value": 7},
{"source": 25, "target": 24, "value": 13},
{"source": 25, "target": 23, "value": 1},
{"source": 25, "target": 11, "value": 12},
{"source": 26, "target": 24, "value": 4},
{"source": 26, "target": 11, "value": 31},
{"source": 26, "target": 16, "value": 1},
{"source": 26, "target": 25, "value": 1},
{"source": 27, "target": 11, "value": 17},
{"source": 27, "target": 23, "value": 5},
{"source": 27, "target": 25, "value": 5},
{"source": 27, "target": 24, "value": 1},
{"source": 27, "target": 26, "value": 1},
{"source": 28, "target": 11, "value": 8},
{"source": 28, "target": 27, "value": 1},
{"source": 29, "target": 23, "value": 1},
{"source": 29, "target": 27, "value": 1},
{"source": 29, "target": 11, "value": 2},
{"source": 30, "target": 23, "value": 1},
{"source": 31, "target": 30, "value": 2},
{"source": 31, "target": 11, "value": 3},
{"source": 31, "target": 23, "value": 2},
{"source": 31, "target": 27, "value": 1},
{"source": 32, "target": 11, "value": 1},
{"source": 33, "target": 11, "value": 2},
{"source": 33, "target": 27, "value": 1},
{"source": 34, "target": 11, "value": 3},
{"source": 34, "target": 29, "value": 2},
{"source": 35, "target": 11, "value": 3},
{"source": 35, "target": 34, "value": 3},
{"source": 35, "target": 29, "value": 2},
{"source": 36, "target": 34, "value": 2},
{"source": 36, "target": 35, "value": 2},
{"source": 36, "target": 11, "value": 2},
{"source": 36, "target": 29, "value": 1},
{"source": 37, "target": 34, "value": 2},
{"source": 37, "target": 35, "value": 2},
{"source": 37, "target": 36, "value": 2},
{"source": 37, "target": 11, "value": 2},
{"source": 37, "target": 29, "value": 1},
{"source": 38, "target": 34, "value": 2},
{"source": 38, "target": 35, "value": 2},
{"source": 38, "target": 36, "value": 2},
{"source": 38, "target": 37, "value": 2},
{"source": 38, "target": 11, "value": 2},
{"source": 38, "target": 29, "value": 1},
{"source": 39, "target": 25, "value": 1},
{"source": 40, "target": 25, "value": 1},
{"source": 41, "target": 24, "value": 2},
{"source": 41, "target": 25, "value": 3},
{"source": 42, "target": 41, "value": 2},
{"source": 42, "target": 25, "value": 2},
{"source": 42, "target": 24, "value": 1},
{"source": 43, "target": 11, "value": 3},
{"source": 43, "target": 26, "value": 1},
{"source": 43, "target": 27, "value": 1},
{"source": 44, "target": 28, "value": 3},
{"source": 44, "target": 11, "value": 1},
{"source": 45, "target": 28, "value": 2},
{"source": 47, "target": 46, "value": 1},
{"source": 48, "target": 47, "value": 2},
{"source": 48, "target": 25, "value": 1},
{"source": 48, "target": 27, "value": 1},
{"source": 48, "target": 11, "value": 1},
{"source": 49, "target": 26, "value": 3},
{"source": 49, "target": 11, "value": 2},
{"source": 50, "target": 49, "value": 1},
{"source": 50, "target": 24, "value": 1},
{"source": 51, "target": 49, "value": 9},
{"source": 51, "target": 26, "value": 2},
{"source": 51, "target": 11, "value": 2},
{"source": 52, "target": 51, "value": 1},
{"source": 52, "target": 39, "value": 1},
{"source": 53, "target": 51, "value": 1},
{"source": 54, "target": 51, "value": 2},
{"source": 54, "target": 49, "value": 1},
{"source": 54, "target": 26, "value": 1},
{"source": 55, "target": 51, "value": 6},
{"source": 55, "target": 49, "value": 12},
{"source": 55, "target": 39, "value": 1},
{"source": 55, "target": 54, "value": 1},
{"source": 55, "target": 26, "value": 21},
{"source": 55, "target": 11, "value": 19},
{"source": 55, "target": 16, "value": 1},
{"source": 55, "target": 25, "value": 2},
{"source": 55, "target": 41, "value": 5},
{"source": 55, "target": 48, "value": 4},
{"source": 56, "target": 49, "value": 1},
{"source": 56, "target": 55, "value": 1},
{"source": 57, "target": 55, "value": 1},
{"source": 57, "target": 41, "value": 1},
{"source": 57, "target": 48, "value": 1},
{"source": 58, "target": 55, "value": 7},
{"source": 58, "target": 48, "value": 7},
{"source": 58, "target": 27, "value": 6},
{"source": 58, "target": 57, "value": 1},
{"source": 58, "target": 11, "value": 4},
{"source": 59, "target": 58, "value": 15},
{"source": 59, "target": 55, "value": 5},
{"source": 59, "target": 48, "value": 6},
{"source": 59, "target": 57, "value": 2},
{"source": 60, "target": 48, "value": 1},
{"source": 60, "target": 58, "value": 4},
{"source": 60, "target": 59, "value": 2},
{"source": 61, "target": 48, "value": 2},
{"source": 61, "target": 58, "value": 6},
{"source": 61, "target": 60, "value": 2},
{"source": 61, "target": 59, "value": 5},
{"source": 61, "target": 57, "value": 1},
{"source": 61, "target": 55, "value": 1},
{"source": 62, "target": 55, "value": 9},
{"source": 62, "target": 58, "value": 17},
{"source": 62, "target": 59, "value": 13},
{"source": 62, "target": 48, "value": 7},
{"source": 62, "target": 57, "value": 2},
{"source": 62, "target": 41, "value": 1},
{"source": 62, "target": 61, "value": 6},
{"source": 62, "target": 60, "value": 3},
{"source": 63, "target": 59, "value": 5},
{"source": 63, "target": 48, "value": 5},
{"source": 63, "target": 62, "value": 6},
{"source": 63, "target": 57, "value": 2},
{"source": 63, "target": 58, "value": 4},
{"source": 63, "target": 61, "value": 3},
{"source": 63, "target": 60, "value": 2},
{"source": 63, "target": 55, "value": 1},
{"source": 64, "target": 55, "value": 5},
{"source": 64, "target": 62, "value": 12},
{"source": 64, "target": 48, "value": 5},
{"source": 64, "target": 63, "value": 4},
{"source": 64, "target": 58, "value": 10},
{"source": 64, "target": 61, "value": 6},
{"source": 64, "target": 60, "value": 2},
{"source": 64, "target": 59, "value": 9},
{"source": 64, "target": 57, "value": 1},
{"source": 64, "target": 11, "value": 1},
{"source": 65, "target": 63, "value": 5},
{"source": 65, "target": 64, "value": 7},
{"source": 65, "target": 48, "value": 3},
{"source": 65, "target": 62, "value": 5},
{"source": 65, "target": 58, "value": 5},
{"source": 65, "target": 61, "value": 5},
{"source": 65, "target": 60, "value": 2},
{"source": 65, "target": 59, "value": 5},
{"source": 65, "target": 57, "value": 1},
{"source": 65, "target": 55, "value": 2},
{"source": 66, "target": 64, "value": 3},
{"source": 66, "target": 58, "value": 3},
{"source": 66, "target": 59, "value": 1},
{"source": 66, "target": 62, "value": 2},
{"source": 66, "target": 65, "value": 2},
{"source": 66, "target": 48, "value": 1},
{"source": 66, "target": 63, "value": 1},
{"source": 66, "target": 61, "value": 1},
{"source": 66, "target": 60, "value": 1},
{"source": 67, "target": 57, "value": 3},
{"source": 68, "target": 25, "value": 5},
{"source": 68, "target": 11, "value": 1},
{"source": 68, "target": 24, "value": 1},
{"source": 68, "target": 27, "value": 1},
{"source": 68, "target": 48, "value": 1},
{"source": 68, "target": 41, "value": 1},
{"source": 69, "target": 25, "value": 6},
{"source": 69, "target": 68, "value": 6},
{"source": 69, "target": 11, "value": 1},
{"source": 69, "target": 24, "value": 1},
{"source": 69, "target": 27, "value": 2},
{"source": 69, "target": 48, "value": 1},
{"source": 69, "target": 41, "value": 1},
{"source": 70, "target": 25, "value": 4},
{"source": 70, "target": 69, "value": 4},
{"source": 70, "target": 68, "value": 4},
{"source": 70, "target": 11, "value": 1},
{"source": 70, "target": 24, "value": 1},
{"source": 70, "target": 27, "value": 1},
{"source": 70, "target": 41, "value": 1},
{"source": 70, "target": 58, "value": 1},
{"source": 71, "target": 27, "value": 1},
{"source": 71, "target": 69, "value": 2},
{"source": 71, "target": 68, "value": 2},
{"source": 71, "target": 70, "value": 2},
{"source": 71, "target": 11, "value": 1},
{"source": 71, "target": 48, "value": 1},
{"source": 71, "target": 41, "value": 1},
{"source": 71, "target": 25, "value": 1},
{"source": 72, "target": 26, "value": 2},
{"source": 72, "target": 27, "value": 1},
{"source": 72, "target": 11, "value": 1},
{"source": 73, "target": 48, "value": 2},
{"source": 74, "target": 48, "value": 2},
{"source": 74, "target": 73, "value": 3},
{"source": 75, "target": 69, "value": 3},
{"source": 75, "target": 68, "value": 3},
{"source": 75, "target": 25, "value": 3},
{"source": 75, "target": 48, "value": 1},
{"source": 75, "target": 41, "value": 1},
{"source": 75, "target": 70, "value": 1},
{"source": 75, "target": 71, "value": 1},
{"source": 76, "target": 64, "value": 1},
{"source": 76, "target": 65, "value": 1},
{"source": 76, "target": 66, "value": 1},
{"source": 76, "target": 63, "value": 1},
{"source": 76, "target": 62, "value": 1},
{"source": 76, "target": 48, "value": 1},
{"source": 76, "target": 58, "value": 1}
]}
draw(data);
// Init the lasso on the svg:g that contains the dots
vis.call(lasso);
// Lasso functions to execute while lassoing
function lasso_start() {
lasso.items()
.attr("r", 3.5) // reset size
.classed({"not_possible": true, "selected": false}); // style as not possible
}
function lasso_draw() {
// Style the possible dots
lasso.items().filter(function (d) {
return d.possible === true
})
.classed({"not_possible": false, "possible": true});
// Style the not possible dot
lasso.items().filter(function (d) {
return d.possible === false
})
.classed({"not_possible": true, "possible": false});
}
function lasso_end() {
// Style the selected dots
lasso.items().filter(function (d) {
return d.selected === true
})
.classed({"not_possible": false, "possible": false})
.attr("r", 7);
// Reset the style of the not selected dots
lasso.items().filter(function (d) {
return d.selected === false
})
.classed({"not_possible": false, "possible": false})
.attr("r", 3.5);
}
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment