I try to create an ERM with Dagre-D3. The relations should be displayed directly between the entities attributes. (see screenshot). By grouping the attributes in parent nodes I'm quite there, but some of the algorithms in the dagre graphlib separate the attribute nodes to keep linking simple. I wouldn't mind to have slightly more complex links but kept the attributes together...
var width = window.innerWidth,
initialHeight = window.innerHeight,
svg = d3.select("body div.container svg"),
inner = svg.append("g");
svg
.attr('width', width)
.attr('height', initialHeight);
// Set up zoom support
var zoom = d3.behavior.zoom().on("zoom", function() {
inner.attr("transform", "translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")");
});
svg.call(zoom);
// create graph
var g = new dagreD3.graphlib.Graph({
multigraph: false,
compound: true
}).setGraph({
rankdir: "LR",
edgesep: 25,
nodesep: 0
});
// customer entity
g.setNode('customer', {label:'customer', class: 'entity-name', labelStyle: 'font-weight:bold;', width: 80});
g.setNode('customer_parent',{label:'customer_par', width: 80});
// customer attributes
g.setNode('cust_id', {label: 'id', width: 80});
g.setNode('cust_first_name',{label: 'first_name', width: 80});
g.setNode('cust_last_name', {label: 'last_name', width: 80});
g.setNode('cust_city', {label: 'city', width: 80});
g.setNode('cust_country', {label: 'country', width: 80});
// assign parent
g.setParent('customer','customer_parent');
g.setParent('cust_id','customer_parent');
g.setParent('cust_first_name','customer_parent');
g.setParent('cust_last_name','customer_parent');
g.setParent('cust_city','customer_parent');
g.setParent('cust_country','customer_parent');
// city entity
g.setNode('city', {label:'city', class: 'entity-name', labelStyle: 'font-weight:bold;', width: 80});
g.setNode('city_parent',{label:'city_parent'});
// city attributes
g.setNode('city_id', {label: 'id', width: 80});
g.setNode('city_name', {label: 'name', width: 80});
g.setNode('city_country',{label: 'country', width: 80});
// assign parent
g.setParent('city','city_parent');
g.setParent('city_id','city_parent');
g.setParent('city_name','city_parent');
g.setParent('city_country','city_parent');
// country entity
g.setNode('country', {label:'country', width: 80, class: 'entity-name', labelStyle: 'font-weight:bold;'});
g.setNode('country_parent',{label:'country_parent', width: 80});
// country attributes
g.setNode('coun_id', {label: 'id', width: 80});
g.setNode('coun_name',{label: 'name', width: 80});
g.setNode('coun_iso',{label: 'iso', width: 80});
// assign parent
g.setParent('country','country_parent');
g.setParent('coun_id','country_parent');
g.setParent('coun_name','country_parent');
g.setParent('coun_iso','country_parent');
// set links
g.setEdge('cust_city','city_id', {label: '', lineInterpolate: 'monotone'});
g.setEdge('cust_country','city_country', {label: '', lineInterpolate: 'monotone'});
g.setEdge('cust_country','coun_id', {label: '', lineInterpolate: 'monotone'});
g.setEdge('city_country','coun_id', {label: '', lineInterpolate: 'monotone'});
// Create the renderer
var render = dagreD3.render();
// Run the renderer. This is what draws the final graph.
render(inner, g);
// adjust height
var initialScale = 1; //0.75;
// Center the graph
zoom
.translate([(svg.attr("width") - g.graph().width * initialScale) / 2, 20])
.scale(initialScale)
.event(svg);
To illustrate what I'm trying to do I created a jsFiddle: ERM with dagre-d3
and here comes the screenshot: