Skip to content

Instantly share code, notes, and snippets.

@nachocab
Created May 19, 2013 12:49
Show Gist options
  • Save nachocab/5607549 to your computer and use it in GitHub Desktop.
Save nachocab/5607549 to your computer and use it in GitHub Desktop.
saveable graph layout
{"description":"saveable graph layout","endpoint":"","display":"svg","public":true,"require":[],"fileconfigs":{"inlet.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"graph.json":{"default":true,"vim":false,"emacs":false,"fontSize":12},"config.json":{"default":true,"vim":false,"emacs":false,"fontSize":12},"_.md":{"default":true,"vim":false,"emacs":false,"fontSize":12},"style.css":{"default":true,"vim":false,"emacs":false,"fontSize":12}},"play":false,"loop":false,"restart":false,"autoinit":true,"pause":true,"loop_type":"period","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01,"fullscreen":false}
{"nodes":[{"x":206,"y":343},{"x":140,"y":392},{"x":240,"y":346},{"x":233,"y":324},{"x":144,"y":337},{"x":133,"y":315},{"x":121,"y":344},{"x":126,"y":370},{"x":162,"y":398},{"x":150,"y":366},{"x":286,"y":364},{"x":332,"y":311},{"x":314,"y":227},{"x":264,"y":355},{"x":273,"y":381},{"x":275,"y":333},{"x":364,"y":200},{"x":372,"y":158},{"x":354,"y":159},{"x":337,"y":157},{"x":369,"y":141},{"x":353,"y":136},{"x":336,"y":141},{"x":351,"y":217},{"x":382,"y":273},{"x":383,"y":298},{"x":351,"y":302},{"x":582,"y":170},{"x":310,"y":256},{"x":294,"y":264},{"x":310,"y":182},{"x":337,"y":242},{"x":259,"y":318},{"x":338,"y":264},{"x":266,"y":269},{"x":256,"y":254},{"x":244,"y":267},{"x":267,"y":287},{"x":248,"y":284},{"x":352,"y":374},{"x":455,"y":254},{"x":419,"y":326},{"x":429,"y":273},{"x":314,"y":295},{"x":280,"y":241},{"x":235,"y":193},{"x":558,"y":328},{"x":493,"y":340},{"x":404,"y":356},{"x":338,"y":337},{"x":367,"y":255},{"x":321,"y":357},{"x":306,"y":424},{"x":267,"y":433},{"x":341,"y":357},{"x":381,"y":350},{"x":336,"y":397},{"x":426,"y":374},{"x":389,"y":372},{"x":405,"y":395},{"x":426,"y":482},{"x":427,"y":395},{"x":415,"y":385},{"x":412,"y":472},{"x":384,"y":389},{"x":395,"y":472},{"x":409,"y":491},{"x":480,"y":430},{"x":398,"y":308},{"x":402,"y":295},{"x":379,"y":317},{"x":393,"y":322},{"x":328,"y":281},{"x":475,"y":390},{"x":478,"y":366},{"x":428,"y":309},{"x":389,"y":489}],"links":[{"target":0,"source":1},{"target":0,"source":2},{"target":0,"source":3},{"target":2,"source":3},{"target":0,"source":4},{"target":0,"source":5},{"target":0,"source":6},{"target":0,"source":7},{"target":0,"source":8},{"target":0,"source":9},{"target":10,"source":11},{"target":3,"source":11},{"target":2,"source":11},{"target":0,"source":11},{"target":11,"source":12},{"target":11,"source":13},{"target":11,"source":14},{"target":11,"source":15},{"target":16,"source":17},{"target":16,"source":18},{"target":17,"source":18},{"target":16,"source":19},{"target":17,"source":19},{"target":18,"source":19},{"target":16,"source":20},{"target":17,"source":20},{"target":18,"source":20},{"target":19,"source":20},{"target":16,"source":21},{"target":17,"source":21},{"target":18,"source":21},{"target":19,"source":21},{"target":20,"source":21},{"target":16,"source":22},{"target":17,"source":22},{"target":18,"source":22},{"target":19,"source":22},{"target":20,"source":22},{"target":21,"source":22},{"target":16,"source":23},{"target":17,"source":23},{"target":18,"source":23},{"target":19,"source":23},{"target":20,"source":23},{"target":21,"source":23},{"target":22,"source":23},{"target":12,"source":23},{"target":11,"source":23},{"target":23,"source":24},{"target":11,"source":24},{"target":24,"source":25},{"target":23,"source":25},{"target":11,"source":25},{"target":24,"source":26},{"target":11,"source":26},{"target":16,"source":26},{"target":25,"source":26},{"target":11,"source":27},{"target":23,"source":27},{"target":25,"source":27},{"target":24,"source":27},{"target":26,"source":27},{"target":11,"source":28},{"target":27,"source":28},{"target":23,"source":29},{"target":27,"source":29},{"target":11,"source":29},{"target":23,"source":30},{"target":30,"source":31},{"target":11,"source":31},{"target":23,"source":31},{"target":27,"source":31},{"target":11,"source":32},{"target":11,"source":33},{"target":27,"source":33},{"target":11,"source":34},{"target":29,"source":34},{"target":11,"source":35},{"target":34,"source":35},{"target":29,"source":35},{"target":34,"source":36},{"target":35,"source":36},{"target":11,"source":36},{"target":29,"source":36},{"target":34,"source":37},{"target":35,"source":37},{"target":36,"source":37},{"target":11,"source":37},{"target":29,"source":37},{"target":34,"source":38},{"target":35,"source":38},{"target":36,"source":38},{"target":37,"source":38},{"target":11,"source":38},{"target":29,"source":38},{"target":25,"source":39},{"target":25,"source":40},{"target":24,"source":41},{"target":25,"source":41},{"target":41,"source":42},{"target":25,"source":42},{"target":24,"source":42},{"target":11,"source":43},{"target":26,"source":43},{"target":27,"source":43},{"target":28,"source":44},{"target":11,"source":44},{"target":28,"source":45},{"target":46,"source":47},{"target":47,"source":48},{"target":25,"source":48},{"target":27,"source":48},{"target":11,"source":48},{"target":26,"source":49},{"target":11,"source":49},{"target":49,"source":50},{"target":24,"source":50},{"target":49,"source":51},{"target":26,"source":51},{"target":11,"source":51},{"target":51,"source":52},{"target":39,"source":52},{"target":51,"source":53},{"target":51,"source":54},{"target":49,"source":54},{"target":26,"source":54},{"target":51,"source":55},{"target":49,"source":55},{"target":39,"source":55},{"target":54,"source":55},{"target":26,"source":55},{"target":11,"source":55},{"target":16,"source":55},{"target":25,"source":55},{"target":41,"source":55},{"target":48,"source":55},{"target":49,"source":56},{"target":55,"source":56},{"target":55,"source":57},{"target":41,"source":57},{"target":48,"source":57},{"target":55,"source":58},{"target":48,"source":58},{"target":27,"source":58},{"target":57,"source":58},{"target":11,"source":58},{"target":58,"source":59},{"target":55,"source":59},{"target":48,"source":59},{"target":57,"source":59},{"target":48,"source":60},{"target":58,"source":60},{"target":59,"source":60},{"target":48,"source":61},{"target":58,"source":61},{"target":60,"source":61},{"target":59,"source":61},{"target":57,"source":61},{"target":55,"source":61},{"target":55,"source":62},{"target":58,"source":62},{"target":59,"source":62},{"target":48,"source":62},{"target":57,"source":62},{"target":41,"source":62},{"target":61,"source":62},{"target":60,"source":62},{"target":59,"source":63},{"target":48,"source":63},{"target":62,"source":63},{"target":57,"source":63},{"target":58,"source":63},{"target":61,"source":63},{"target":60,"source":63},{"target":55,"source":63},{"target":55,"source":64},{"target":62,"source":64},{"target":48,"source":64},{"target":63,"source":64},{"target":58,"source":64},{"target":61,"source":64},{"target":60,"source":64},{"target":59,"source":64},{"target":57,"source":64},{"target":11,"source":64},{"target":63,"source":65},{"target":64,"source":65},{"target":48,"source":65},{"target":62,"source":65},{"target":58,"source":65},{"target":61,"source":65},{"target":60,"source":65},{"target":59,"source":65},{"target":57,"source":65},{"target":55,"source":65},{"target":64,"source":66},{"target":58,"source":66},{"target":59,"source":66},{"target":62,"source":66},{"target":65,"source":66},{"target":48,"source":66},{"target":63,"source":66},{"target":61,"source":66},{"target":60,"source":66},{"target":57,"source":67},{"target":25,"source":68},{"target":11,"source":68},{"target":24,"source":68},{"target":27,"source":68},{"target":48,"source":68},{"target":41,"source":68},{"target":25,"source":69},{"target":68,"source":69},{"target":11,"source":69},{"target":24,"source":69},{"target":27,"source":69},{"target":48,"source":69},{"target":41,"source":69},{"target":25,"source":70},{"target":69,"source":70},{"target":68,"source":70},{"target":11,"source":70},{"target":24,"source":70},{"target":27,"source":70},{"target":41,"source":70},{"target":58,"source":70},{"target":27,"source":71},{"target":69,"source":71},{"target":68,"source":71},{"target":70,"source":71},{"target":11,"source":71},{"target":48,"source":71},{"target":41,"source":71},{"target":25,"source":71},{"target":26,"source":72},{"target":27,"source":72},{"target":11,"source":72},{"target":48,"source":73},{"target":48,"source":74},{"target":73,"source":74},{"target":69,"source":75},{"target":68,"source":75},{"target":25,"source":75},{"target":48,"source":75},{"target":41,"source":75},{"target":70,"source":75},{"target":71,"source":75},{"target":64,"source":76},{"target":65,"source":76},{"target":66,"source":76},{"target":63,"source":76},{"target":62,"source":76},{"target":48,"source":76},{"target":58,"source":76}]}
//adapted from mike bostock's example:
//http://bl.ocks.org/4566102
//focused on saving the results of dragging
var cm = tributary.getCodeEditor("graph.json");
var graph = JSON.parse(cm.getValue());
var width = tributary.sw;
var height = tributary.sh;
var shiftKey;
var svg = d3.select("svg")
var link = svg.append("g")
.attr("class", "link")
.selectAll("line");
var brush = svg.append("g")
.datum(function() { return {selected: false, previouslySelected: false}; })
.attr("class", "brush");
var node = svg.append("g")
.attr("class", "node")
.selectAll("circle");
var linkIndices = _.map(graph.links, function(d) {
return {target: d.target, source: d.source};
})
graph.links.forEach(function(d) {
d.source = graph.nodes[d.source];
d.target = graph.nodes[d.target];
});
link = link.data(graph.links).enter().append("line")
.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; });
brush.call(d3.svg.brush()
.x(d3.scale.identity().domain([0, width]))
.y(d3.scale.identity().domain([0, height]))
.on("brushstart", function(d) {
node.each(function(d) { d.previouslySelected = shiftKey && d.selected; });
})
.on("brush", function() {
var extent = d3.event.target.extent();
node.classed("selected", function(d) {
return d.selected = d.previouslySelected ^
(extent[0][0] <= d.x && d.x < extent[1][0]
&& extent[0][1] <= d.y && d.y < extent[1][1]);
});
})
.on("brushend", function() {
d3.event.target.clear();
d3.select(this).call(d3.event.target);
}));
node = node.data(graph.nodes).enter().append("circle")
.attr("r", 4)
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.on("mousedown", function(d) {
if (!d.selected) { // Don't deselect on shift-drag.
if (!shiftKey) node.classed("selected", function(p) { return p.selected = d === p; });
else d3.select(this).classed("selected", d.selected = true);
}
})
.on("mouseup", function(d) {
if (d.selected && shiftKey) d3.select(this).classed("selected", d.selected = false);
})
.call(d3.behavior.drag()
.on("drag", function(d) { nudge(d3.event.dx, d3.event.dy); })
.on("dragend", function(d) {
save();
})
);
function nudge(dx, dy) {
node.filter(function(d) { return d.selected; })
.attr("cx", function(d) { return d.x += dx; })
.attr("cy", function(d) { return d.y += dy; })
link.filter(function(d) { return d.source.selected; })
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; });
link.filter(function(d) { return d.target.selected; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
//d3.event.preventDefault();
}
function save() {
//remove extraneous attributes from graph before saving;
var nodes = _.map(graph.nodes, function(d) {
return {x: d.x, y: d.y };
})
var links = _.map(graph.links, function(d) {
return {source: {x: d.source.x, y: d.source.y },
target: {x: d.target.x, y: d.target.y }
};
})
var out = {"nodes":nodes, "links":linkIndices};
//set the value of the json again, which saves it
cm.setValue(JSON.stringify(out))
}
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.node .selected {
stroke: red;
}
.link {
stroke: #999;
}
.brush .extent {
fill-opacity: .1;
stroke: #fff;
shape-rendering: crispEdges;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment