module.exports.draw = function (text, id) { cd.yy.clear() cd.parse(text) log.info('Rendering diagram ' + text) /// / Fetch the default direction, use TD if none was found var diagram = d3.select('#' + id) insertMarkers(diagram) // Layout graph, Create a new directed graph var g = new dagre.graphlib.Graph({ multigraph: true }) // Set an object for the graph label g.setGraph({ isMultiGraph: true }) // Default to assigning a new object as a label for each new edge. g.setDefaultEdgeLabel(function () { return {} }) var classes = cDDb.getClasses() var keys = Object.keys(classes) var i for (i = 0; i < keys.length; i++) { var classDef = classes[keys[i]] var node = drawClass(diagram, classDef) // Add nodes to the graph. The first argument is the node id. The second is // metadata about the node. In this case we're going to add labels to each of // our nodes. g.setNode(node.id, node) log.info('Org height: ' + node.height) } var relations = cDDb.getRelations() relations.forEach(function (relation) { log.info('tjoho' + getGraphId(relation.id1) + getGraphId(relation.id2) + JSON.stringify(relation)) g.setEdge(getGraphId(relation.id1), getGraphId(relation.id2), { relation: relation }) }) dagre.layout(g) g.nodes().forEach(function (v) { if (typeof v !== 'undefined') { log.debug('Node ' + v + ': ' + JSON.stringify(g.node(v))) d3.select('#' + v).attr('transform', 'translate(' + (g.node(v).x - (g.node(v).width / 2)) + ',' + (g.node(v).y - (g.node(v).height / 2)) + ' )') } }) g.edges().forEach(function (e) { log.debug('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(g.edge(e))) drawEdge(diagram, g.edge(e), g.edge(e).relation) }) diagram.attr('height', '100%') diagram.attr('width', '100%') diagram.attr('viewBox', '0 0 ' + (g.graph().width + 20) + ' ' + (g.graph().height + 20)) }
function positionGraph() { // Create a new directed graph var g = new Graph(); // Set an object for the graph label g.setGraph({ rankdir: 'BT', nodesep: 150, edgesep: 70, marginx: 10, marginy: 30 }); // Default to assigning a new object as a label for each new edge. g.setDefaultEdgeLabel(function() { return {}; }); // Automatically label each of the nodes model.schemas.forEach(function(schema) { var el = document.getElementById(schema.id); var style = window.getComputedStyle(el); var width = parseInt(style.width, 10); var height = parseInt(style.height, 10); g.setNode(schema.id, { label: schema.name, width: width, height: height }); }); model.schemaReferences().forEach(function(key) { g.setEdge(key.keys.schema.id, key.ref()); }); var grp = dagre.layout(g); g.nodes().forEach(function(v) { console.log("Node " + v + ": " + JSON.stringify(g.node(v))); var el = document.getElementById(v); var node = g.node(v); var top = node.y - (node.height / 2); var left = node.x - (node.width / 2); el.style.top = top + 'px'; el.style.left = left + 'px'; }); }
this.render = function() { if(this.held()) { return; } var self = this; // Give plugins a chance to play with the config and preprocess the graph. var config = dagre.layout(); var graph = this.graph.copy(); this.doPreLayout(config, graph); // Instead of a list of IDs, our data should be a list of objects. var nodes = graph.nodes().map(function(id) { return graph.node(id); }); this.nodes = nodes; // Perform graph layout. var result = this.renderNodes.run(nodes); var layout = config.run(graph); this.doPostLayout(layout); // Augment existing node data with layout information. nodes.forEach(function(node) { node.layout = layout.node(node.id); }); this.positionNodes.run(nodes); var g = graph; var edges = layout.edges().map(function(id) { return { id: id, source: g.node(g.incidentNodes(id)[0]), target: g.node(g.incidentNodes(id)[1]), value: g.edge(id), layout: layout.edge(id) }; }); this.edges = edges; this.renderEdges.run(edges); this.positionEdges.run(edges); this.layout = layout; this.doPostRender(); return this; };
function Renderer() { // Set up defaults... this._layout = layout(); this.drawNodes(defaultDrawNodes); this.drawEdgeLabels(defaultDrawEdgeLabels); this.drawEdgePaths(defaultDrawEdgePaths); this.positionNodes(defaultPositionNodes); this.positionEdgeLabels(defaultPositionEdgeLabels); this.positionEdgePaths(defaultPositionEdgePaths); this.transition(defaultTransition); this.postLayout(defaultPostLayout); this.postRender(defaultPostRender); this.edgeInterpolate('bundle'); this.edgeTension(0.95); }
render: function(svg, graph, layout) { var renderedGraph = graph; if(layout) { // Performs layout and draw the graph // we simplifies the graph so dagre process the layout faster var simpleGraph = this.createGraph(); planLayout.simplify(graph, simpleGraph, 'end'); // add hosts back var clusters = graph.nodes().filter(function(v) { return !!graph.children(v).length; }); _.each(clusters, function(clusterKey) { simpleGraph.setNode(clusterKey, graph.node(clusterKey)); }); // dagre layout dagre.layout(simpleGraph, {debugTiming: false}); // unwrap simplified nodes planLayout.unwrap(simpleGraph, 'end'); planLayout.unwrapEdges(simpleGraph, graph); renderedGraph = simpleGraph; var bbox = bboxFactory.create(); // cleanup layout data from graph _.each(graph.nodes(), function(nodeKey) { var node = graph.node(nodeKey); delete node.simplified; delete node.merged; delete node.unwraped; delete node.mergeId; bbox.addPoint(node.x, node.y); bbox.addPoint(node.x + node.width, node.y + node.height); }); this.bbox = bbox; } // prepare groups to draw clusters, edges and nodes. var clustersGroup = this.createOrSelectGroup(svg, 'clusters'), edgesGroup = this.createOrSelectGroup(svg, 'edges'), nodesGroup = this.createOrSelectGroup(svg, 'nodes'); // draw nodes this.createNodes(nodesGroup, renderedGraph); this.createClusters(clustersGroup, renderedGraph); this.createEdges(edgesGroup, renderedGraph); },
function layout(paper) { var graph = paper.model; var i; var g = new dagre.graphlib.Graph(); g.setGraph({}); g.setDefaultEdgeLabel(function() {return{};}); var nodes = graph.getElements(); for (i = 0; i < nodes.length; i++) { var node = nodes[i]; if (node.get('type') === joint.shapes.flo.NODE_TYPE) { g.setNode(node.id, node.get('size')); } } var links = graph.getLinks(); for (i = 0; i < links.length; i++) { var link = links[i]; if (link.get('type') === joint.shapes.flo.LINK_TYPE) { var options = { minlen: 1.5 }; // if (link.get('labels') && link.get('labels').length > 0) { // options.minlen = 1 + link.get('labels').length * 0.5; // } g.setEdge(link.get('source').id, link.get('target').id, options); link.set('vertices', []); } } g.graph().rankdir = 'LR'; dagre.layout(g); g.nodes().forEach(function(v) { var node = graph.getCell(v); if (node) { var bbox = node.getBBox(); node.translate(g.node(v).x - bbox.x, g.node(v).y - bbox.y); } }); }
layout: function(graphOrCells, opt) { var graph; if (graphOrCells instanceof joint.dia.Graph) { graph = graphOrCells; } else { graph = (new joint.dia.Graph()).resetCells(graphOrCells); } // This is not needed anymore. graphOrCells = null; opt = _.defaults(opt || {}, { resizeClusters: true, clusterPadding: 10 }); // create a graphlib.Graph that represents the joint.dia.Graph var glGraph = graph.toGraphLib({ directed: true, // We are about to use edge naming feature. multigraph: true, // We are able to layout graphs with embeds. compound: true, setNodeLabel: function(element) { return { width: element.get('size').width, height: element.get('size').height, rank: element.get('rank') }; }, setEdgeLabel: function(link) { return { minLen: link.get('minLen') || 1 }; }, setEdgeName: function(link) { // Graphlib edges have no ids. We use edge name property // to store and retrieve ids instead. return link.id; } }); var glLabel = {}; var marginX = opt.marginX || 0; var marginY = opt.marginY || 0; // Dagre layout accepts options as lower case. // Direction for rank nodes. Can be TB, BT, LR, or RL if (opt.rankDir) glLabel.rankdir = opt.rankDir; // Alignment for rank nodes. Can be UL, UR, DL, or DR if (opt.align) glLabel.align = opt.align; // Number of pixels that separate nodes horizontally in the layout. if (opt.nodeSep) glLabel.nodesep = opt.nodeSep; // Number of pixels that separate edges horizontally in the layout. if (opt.edgeSep) glLabel.edgesep = opt.edgeSep; // Number of pixels between each rank in the layout. if (opt.rankSep) glLabel.ranksep = opt.rankSep; // Number of pixels to use as a margin around the left and right of the graph. if (marginX) glLabel.marginx = marginX; // Number of pixels to use as a margin around the top and bottom of the graph. if (marginY) glLabel.marginy = marginY; // Set the option object for the graph label. glGraph.setGraph(glLabel); // Executes the layout. dagre.layout(glGraph, { debugTiming: !!opt.debugTiming }); // Wrap all graph changes into a batch. graph.startBatch('layout'); // Update the graph. graph.fromGraphLib(glGraph, { importNode: function(v, gl) { var element = this.getCell(v); var glNode = gl.node(v); if (opt.setPosition) { opt.setPosition(element, glNode); } else { element.set('position', { x: glNode.x - glNode.width / 2, y: glNode.y - glNode.height / 2 }); } }, importEdge: function(edgeObj, gl) { var link = this.getCell(edgeObj.name); var glEdge = gl.edge(edgeObj); var points = glEdge.points || []; if (opt.setLinkVertices) { if (opt.setVertices) { opt.setVertices(link, points); } else { // Remove the first and last point from points array. // Those are source/target element connection points // ie. they lies on the edge of connected elements. link.set('vertices', points.slice(1, points.length - 1)); } } } }); if (opt.resizeClusters) { // Resize and reposition cluster elements (parents of other elements) // to fit their children. // 1. filter clusters only // 2. map id on cells // 3. sort cells by their depth (the deepest first) // 4. resize cell to fit their direct children only. _.chain(glGraph.nodes()) .filter(function(v) { return glGraph.children(v).length > 0; }) .map(graph.getCell, graph) .sortBy(function(cluster) { return -cluster.getAncestors().length; }) .invoke('fitEmbeds', { padding: opt.clusterPadding }) .value(); } graph.stopBatch('layout'); // Width and height of the graph extended by margins. var glSize = glGraph.graph(); // Return the bounding box of the graph after the layout. return g.Rect( marginX, marginY, Math.abs(glSize.width - 2 * marginX), Math.abs(glSize.height - 2 * marginY) ); },
layout: function(graph, opt) { opt = _.defaults(opt || {}, { resizeClusters: true, clusterPadding: 10 }); // create a graphlib.Graph that represents the joint.dia.Graph var glGraph = graph.toGraphLib({ directed: true, // We are about to use edge naming feature. multigraph: true, // We are able to layout graphs with embeds. compound: true, setNodeLabel: function(element) { return { width: element.get('size').width, height: element.get('size').height, rank: element.get('rank') }; }, setEdgeLabel: function(link) { return { minLen: link.get('minLen') || 1 }; }, setEdgeName: function(link) { // Graphlib edges have no ids. We use edge name property // to store and retrieve ids instead. return link.id; } }); var glLabel = {}; // Dagre layout accepts options as lower case. if (opt.rankDir) glLabel.rankdir = opt.rankDir; if (opt.nodeSep) glLabel.nodesep = opt.nodeSep; if (opt.edgeSep) glLabel.edgesep = opt.edgeSep; if (opt.rankSep) glLabel.ranksep = opt.rankSep; if (opt.marginX) glLabel.marginx = opt.marginX; if (opt.marginY) glLabel.marginy = opt.marginY; // Set the option object for the graph label glGraph.setGraph(glLabel); // executes the layout dagre.layout(glGraph, { debugTiming: !!opt.debugTiming }); // Update the graph graph.fromGraphLib(glGraph, { importNode: function(v, gl) { var element = this.getCell(v); var glNode = gl.node(v); if (opt.setPosition) { opt.setPosition(element, glNode); } else { element.set('position', { x: glNode.x - glNode.width / 2, y: glNode.y - glNode.height / 2 }); } }, importEdge: function(edgeObj, gl) { var link = this.getCell(edgeObj.name); var glEdge = gl.edge(edgeObj); if (opt.setLinkVertices) { if (opt.setVertices) { opt.setVertices(link, glEdge.points); } else { link.set('vertices', glEdge.points); } } } }); if (opt.resizeClusters) { // Resize and reposition cluster elements (parents of other elements) // to fit their children. // 1. filter clusters only // 2. map id on cells // 3. sort cells by their depth (the deepest first) // 4. resize cell to fit their direct children only. _.chain(glGraph.nodes()) .filter(function(v) { return glGraph.children(v).length > 0; }) .map(graph.getCell, graph) .sortBy(function(cluster) { return -cluster.getAncestors().length; }) .invoke('fitEmbeds', { padding: opt.clusterPadding }) .value(); } // Return an object with height and width of the graph. return glGraph.graph(); }
function process() { var g = new dagre.Digraph(), properties, node, library = container.analyzer, str = library.stringify(), libraryNodes = str.nodes, libraryEdges = str.edges; // create the graph // each element of the graph has // - label // - width // - height // - properties _.forOwn(libraryNodes, function (properties, k) { var label = k.match(/\S*?-(.*)/)[1]; // console.log(k, label.length); node = { label: k, width: label.length * 10 }; // lines + header + padding bottom node.height = properties.length * 15 + 50; node.properties = properties; properties.forEach(function (v) { node.width = Math.max(node.width, v.name.length * 10); }); g.addNode(k, node); }); // build the edges from node to node _.forOwn(libraryEdges, function (links) { links.forEach(function (link) { if (g.hasNode(link.from) && g.hasNode(link.to)) { g.addEdge(null, link.from, link.to); } }); }); // layout of the graph var layout = dagre.layout() .nodeSep(30) // .rankSep(70) // .rankDir('TB') .run(g); var nodes = [], edges = [], center = {x: 0, y: 0}, mn = {x: Infinity, y: Infinity}, mx = {x: -Infinity, y: -Infinity}, total = g.nodes().length; // update the node info of the node adding: // - x // - y // - predecessors // - successors layout.eachNode(function (k, layoutInfo) { var x = layoutInfo.x; var y = layoutInfo.y; node = g.node(k); node.x = x; node.y = y; node.predecessors = g.predecessors(k); node.successors = g.successors(k); nodes.push(node); // calculate the bbox of the graph to center the graph var mnx = x - node.width / 2; var mny = y - node.height / 2; var mxx = x + node.width / 2; var mxy = y + node.height / 2; center.x += x; center.y += y; mn.x = Math.min(mn.x, mnx); mn.y = Math.min(mn.y, mny); // console.log(x, y, ' dim ', node.width, node.height); mx.x = Math.max(mx.x, mxx); mx.y = Math.max(mx.y, mxy); }); center.x /= (total || 1); center.y /= (total || 1); // create the edges from property to node _(libraryEdges).forOwn(function (links) { links.forEach(function (link) { if (g.hasNode(link.from) && g.hasNode(link.to)) { edges.push(link); } }); }); return { edges: edges, nodes: nodes, center: center, mn: mn, mx: mx }; }
/** * Layout engine runner * After the layout engine run nodes and edges have x-y-coordinates. Engine is * not run if the number of nodes is bigger than `MAX_NODES`. * @param {Object} graph dagre graph instance * @param {Map} imNodes new node set * @param {Map} imEdges new edge set * @param {Object} opts dimensions, scales, etc. * @return {Object} Layout with nodes, edges, dimensions */ function runLayoutEngine(graph, imNodes, imEdges, opts) { let nodes = imNodes; let edges = imEdges; const options = opts || {}; const scale = options.scale || DEFAULT_SCALE; const ranksep = scale(RANK_SEPARATION_FACTOR); const nodesep = scale(NODE_SEPARATION_FACTOR); const nodeWidth = scale(NODE_SIZE_FACTOR); const nodeHeight = scale(NODE_SIZE_FACTOR); // configure node margins graph.setGraph({ nodesep, ranksep }); // add nodes to the graph if not already there nodes.forEach(node => { const gNodeId = graphNodeId(node.get('id')); if (!graph.hasNode(gNodeId)) { graph.setNode(gNodeId, { width: nodeWidth, height: nodeHeight }); } }); // remove nodes that are no longer there or are 0-degree nodes graph.nodes().forEach(gNodeId => { const nodeId = fromGraphNodeId(gNodeId); if (!nodes.has(nodeId) || nodes.get(nodeId).get('degree') === 0) { graph.removeNode(gNodeId); } }); // add edges to the graph if not already there edges.forEach(edge => { const s = graphNodeId(edge.get('source')); const t = graphNodeId(edge.get('target')); if (!graph.hasEdge(s, t)) { const virtualNodes = s === t ? 1 : 0; graph.setEdge(s, t, {id: edge.get('id'), minlen: virtualNodes}); } }); // remove edges that are no longer there graph.edges().forEach(edgeObj => { const edge = [fromGraphNodeId(edgeObj.v), fromGraphNodeId(edgeObj.w)]; const edgeId = edge.join(EDGE_ID_SEPARATOR); if (!edges.has(edgeId)) { graph.removeEdge(edgeObj.v, edgeObj.w); } }); dagre.layout(graph); const layout = graph.graph(); // apply coordinates to nodes and edges graph.nodes().forEach(gNodeId => { const graphNode = graph.node(gNodeId); const nodeId = fromGraphNodeId(gNodeId); nodes = nodes.setIn([nodeId, 'x'], graphNode.x); nodes = nodes.setIn([nodeId, 'y'], graphNode.y); }); graph.edges().forEach(graphEdge => { const graphEdgeMeta = graph.edge(graphEdge); const edge = edges.get(graphEdgeMeta.id); let points = fromJS(graphEdgeMeta.points); // set beginning and end points to node coordinates to ignore node bounding box const source = nodes.get(fromGraphNodeId(edge.get('source'))); const target = nodes.get(fromGraphNodeId(edge.get('target'))); points = points.mergeIn([0], {x: source.get('x'), y: source.get('y')}); points = points.mergeIn([points.size - 1], {x: target.get('x'), y: target.get('y')}); edges = edges.setIn([graphEdgeMeta.id, 'points'], points); }); // return object with the width and height of layout return { width: layout.width, height: layout.height, nodes, edges }; }
if("object"==typeof exports)var graphlib=require("graphlib"),dagre=require("dagre");graphlib=graphlib||"undefined"!=typeof window&&window.graphlib,dagre=dagre||"undefined"!=typeof window&&window.dagre,joint.layout.DirectedGraph={layout:function(a,b){var c;c=a instanceof joint.dia.Graph?a:(new joint.dia.Graph).resetCells(a),a=null,b=_.defaults(b||{},{resizeClusters:!0,clusterPadding:10});var d=c.toGraphLib({directed:!0,multigraph:!0,compound:!0,setNodeLabel:function(a){return{width:a.get("size").width,height:a.get("size").height,rank:a.get("rank")}},setEdgeLabel:function(a){return{minLen:a.get("minLen")||1}},setEdgeName:function(a){return a.id}}),e={};return b.rankDir&&(e.rankdir=b.rankDir),b.align&&(e.align=b.align),b.nodeSep&&(e.nodesep=b.nodeSep),b.edgeSep&&(e.edgesep=b.edgeSep),b.rankSep&&(e.ranksep=b.rankSep),b.marginX&&(e.marginx=b.marginX),b.marginY&&(e.marginy=b.marginY),d.setGraph(e),dagre.layout(d,{debugTiming:!!b.debugTiming}),c.startBatch("layout"),c.fromGraphLib(d,{importNode:function(a,c){var d=this.getCell(a),e=c.node(a);b.setPosition?b.setPosition(d,e):d.set("position",{x:e.x-e.width/2,y:e.y-e.height/2})},importEdge:function(a,c){var d=this.getCell(a.name),e=c.edge(a),f=e.points||[];b.setLinkVertices&&(b.setVertices?b.setVertices(d,f):d.set("vertices",f.slice(1,f.length-1)))}}),b.resizeClusters&&_.chain(d.nodes()).filter(function(a){return d.children(a).length>0}).map(c.getCell,c).sortBy(function(a){return-a.getAncestors().length}).invoke("fitEmbeds",{padding:b.clusterPadding}).value(),c.stopBatch("layout"),d.graph()},fromGraphLib:function(a,b){b=b||{};var c=b.importNode||_.noop,d=b.importEdge||_.noop,e=this instanceof joint.dia.Graph?this:new joint.dia.Graph;return a.nodes().forEach(function(d){c.call(e,d,a,e,b)}),a.edges().forEach(function(c){d.call(e,c,a,e,b)}),e},toGraphLib:function(a,b){b=b||{};var c=_.pick(b,"directed","compound","multigraph"),d=new graphlib.Graph(c),e=b.setNodeLabel||_.noop,f=b.setEdgeLabel||_.noop,g=b.setEdgeName||_.noop;return a.get("cells").each(function(a){if(a.isLink()){var b=a.get("source"),c=a.get("target");if(!b.id||!c.id)return;d.setEdge(b.id,c.id,f(a),g(a))}else d.setNode(a.id,e(a)),d.isCompound()&&a.has("parent")&&d.setParent(a.id,a.get("parent"))}),d}},joint.dia.Graph.prototype.toGraphLib=function(a){return joint.layout.DirectedGraph.toGraphLib(this,a)},joint.dia.Graph.prototype.fromGraphLib=function(a,b){return joint.layout.DirectedGraph.fromGraphLib.call(this,a,b)};
if("object"==typeof exports)var graphlib=require("graphlib"),dagre=require("dagre");graphlib=graphlib||"undefined"!=typeof window&&window.graphlib,dagre=dagre||"undefined"!=typeof window&&window.dagre,joint.dia.Graph.prototype.toGraphLib=function(a){a=a||{};var b=_.pick(a,"directed","compound","multigraph"),c=new graphlib.Graph(b),d=a.setNodeLabel||_.noop,e=a.setEdgeLabel||_.noop,f=a.setEdgeName||_.noop;return this.get("cells").each(function(a){if(a.isLink()){var b=a.get("source"),g=a.get("target");if(!b.id||!g.id)return;c.setEdge(b.id,g.id,e(a),f(a))}else c.setNode(a.id,d(a)),c.isCompound()&&a.has("parent")&&c.setParent(a.id,a.get("parent"))}),c},joint.dia.Graph.prototype.fromGraphLib=function(a,b){b=b||{};var c=b.importNode||_.noop,d=b.importEdge||_.noop;a.nodes().forEach(function(d){c.call(this,d,a,this,b)},this),a.edges().forEach(function(c){d.call(this,c,a,this,b)},this)},joint.layout.DirectedGraph={layout:function(a,b){b=_.defaults(b||{},{resizeClusters:!0,clusterPadding:10});var c=a.toGraphLib({directed:!0,multigraph:!0,compound:!0,setNodeLabel:function(a){return{width:a.get("size").width,height:a.get("size").height,rank:a.get("rank")}},setEdgeLabel:function(a){return{minLen:a.get("minLen")||1}},setEdgeName:function(a){return a.id}}),d={};return b.rankDir&&(d.rankdir=b.rankDir),b.nodeSep&&(d.nodesep=b.nodeSep),b.edgeSep&&(d.edgesep=b.edgeSep),b.rankSep&&(d.ranksep=b.rankSep),b.marginX&&(d.marginx=b.marginX),b.marginY&&(d.marginy=b.marginY),c.setGraph(d),dagre.layout(c,{debugTiming:!!b.debugTiming}),a.fromGraphLib(c,{importNode:function(a,c){var d=this.getCell(a),e=c.node(a);b.setPosition?b.setPosition(d,e):d.set("position",{x:e.x-e.width/2,y:e.y-e.height/2})},importEdge:function(a,c){var d=this.getCell(a.name),e=c.edge(a);b.setLinkVertices&&(b.setVertices?b.setVertices(d,e.points):d.set("vertices",e.points))}}),b.resizeClusters&&_.chain(c.nodes()).filter(function(a){return c.children(a).length>0}).map(a.getCell,a).sortBy(function(a){return-a.getAncestors().length}).invoke("fitEmbeds",{padding:b.clusterPadding}).value(),c.graph()}};
function Graph(props) { var g = new dagre.graphlib.Graph(); g.setGraph({ width: 1000, height: 1000, nodesep: 50, edgesep: 150, ranksep: 150, marginx: 100, marginy: 100, }); var edgeLabels = {}; React.Children.forEach(props.children, function(child) { if (!child) { return; } if (child.type.isVertex) { g.setNode(child.key, { label: child, width: child.props.width, height: child.props.height, }); } else if (child.type.isEdge) { const relationshipKey = child.props.source + ':' + child.props.target; if (!edgeLabels[relationshipKey]) { edgeLabels[relationshipKey] = []; } edgeLabels[relationshipKey].push(child); } }); Object.keys(edgeLabels).forEach(key => { const children = edgeLabels[key]; const child = children[0]; g.setEdge(child.props.source, child.props.target, { label: child, allChildren: children.map(c => c.props.children), weight: child.props.weight, }); }); dagre.layout(g); var activeNode = g .nodes() .map(v => g.node(v)) .find(node => node.label.props.isActive); const [winX, winY] = [window.innerWidth / 2, window.innerHeight / 2]; var focusDx = activeNode ? winX - activeNode.x : 0; var focusDy = activeNode ? winY - activeNode.y : 0; var nodes = g.nodes().map(v => { var node = g.node(v); return ( <Motion style={{ x: props.isDragging ? node.x + focusDx : spring(node.x + focusDx), y: props.isDragging ? node.y + focusDy : spring(node.y + focusDy), }} key={node.label.key}> {interpolatingStyle => React.cloneElement(node.label, { x: interpolatingStyle.x + props.dx, y: interpolatingStyle.y + props.dy, vanillaX: node.x, vanillaY: node.y, })} </Motion> ); }); var edges = g.edges().map(e => { var edge = g.edge(e); let idx = 0; return ( <Motion style={edge.points.reduce((bag, point) => { bag[idx + ':x'] = props.isDragging ? point.x + focusDx : spring(point.x + focusDx); bag[idx + ':y'] = props.isDragging ? point.y + focusDy : spring(point.y + focusDy); idx++; return bag; }, {})} key={edge.label.key}> {interpolatedStyle => { let points = []; Object.keys(interpolatedStyle).forEach(key => { const [idx, prop] = key.split(':'); if (!points[idx]) { points[idx] = {x: props.dx, y: props.dy}; } points[idx][prop] += interpolatedStyle[key]; }); return React.cloneElement(edge.label, { points, id: edge.label.key, children: edge.allChildren.join(', '), }); }} </Motion> ); }); return ( <div style={{ position: 'relative', height: '100%', }}> {edges} {nodes} </div> ); }
directedGraph: function (slide, data, settings, name) { slide.name = name; /** * to make the line you need to provide the start point and the extension length * we will generate the extension from second point coordinates */ function getCoordinates(x1, y1, x2, y2) { var flipH = false, flipV = false; if (y2 < y1) { flipV = true; } if (x2 < x1) { flipH = true; } return { x: x1 < x2 ? x1 : x2, y: y1 < y2 ? y1 : y2, cx: Math.abs(x2 - x1), cy: Math.abs(y2 - y1), flipH: flipH, flipV: flipV } } // Create a new directed graph var g = new dagre.graphlib.Graph(); // Set an object for the graph label g.setGraph({}); // Default to assigning a new object as a label for each new edge. g.setDefaultEdgeLabel(function () { return {}; }); var offset = 50; //margin from borders for (var i in data.nodes) { g.setNode(data.nodes[i].id, { label: data.nodes[i].label, width: settings.nodeWidth * 2, height: 50 }); } for (var i in data.edges) { g.setEdge(data.edges[i].source.id, data.edges[i].target.id); } dagre.layout(g); g.nodes().forEach(function (node) { var n = g.node(node); slide.addShape('rect', { x: n.x - n.width / 2 + offset, y: n.y - n.height / 2 + offset, cx: n.width, cy: n.height, fill: settings.nodeColor.substr(1) }); slide.addText(n.label, { x: n.x - n.width / 2 + offset, y: n.y - n.height / 2 + offset, cx: n.width, cy: n.height, color: '000000', font_size: 15 }); }); g.edges().forEach(function (edge) { var e = g.edge(edge).points; for (var i = 0; i < e.length - 1; i++) { var coord = getCoordinates(e[i].x + offset, e[i].y + offset, e[i + 1].x + offset, e[i + 1].y + offset); slide.addShape('line', { x: coord.x, y: coord.y, cx: coord.cx, cy: coord.cy, line: settings.edgeColor.substr(1), line_size: settings.edgeWidth, flip_vertical: coord.flipV, flip_horizontal: coord.flipH, line_tail: i == e.length - 2 ? 'triangle' : 'none' }); } }); },
DagreLayout.prototype.run = function(){ let options = this.options; let layout = this; let cy = options.cy; // cy is automatically populated for us in the constructor let eles = options.eles; let getVal = function( ele, val ){ return isFunction(val) ? val.apply( ele, [ ele ] ) : val; }; let bb = options.boundingBox || { x1: 0, y1: 0, w: cy.width(), h: cy.height() }; if( bb.x2 === undefined ){ bb.x2 = bb.x1 + bb.w; } if( bb.w === undefined ){ bb.w = bb.x2 - bb.x1; } if( bb.y2 === undefined ){ bb.y2 = bb.y1 + bb.h; } if( bb.h === undefined ){ bb.h = bb.y2 - bb.y1; } let g = new dagre.graphlib.Graph({ multigraph: true, compound: true }); let gObj = {}; let setGObj = function( name, val ){ if( val != null ){ gObj[ name ] = val; } }; setGObj( 'nodesep', options.nodeSep ); setGObj( 'edgesep', options.edgeSep ); setGObj( 'ranksep', options.rankSep ); setGObj( 'rankdir', options.rankDir ); setGObj( 'ranker', options.ranker ); g.setGraph( gObj ); g.setDefaultEdgeLabel(function() { return {}; }); g.setDefaultNodeLabel(function() { return {}; }); // add nodes to dagre let nodes = eles.nodes(); for( let i = 0; i < nodes.length; i++ ){ let node = nodes[i]; let nbb = node.layoutDimensions( options ); g.setNode( node.id(), { width: nbb.w, height: nbb.h, name: node.id() } ); // console.log( g.node(node.id()) ); } // set compound parents for( let i = 0; i < nodes.length; i++ ){ let node = nodes[i]; if( node.isChild() ){ g.setParent( node.id(), node.parent().id() ); } } // add edges to dagre let edges = eles.edges().stdFilter(function( edge ){ return !edge.source().isParent() && !edge.target().isParent(); // dagre can't handle edges on compound nodes }); for( let i = 0; i < edges.length; i++ ){ let edge = edges[i]; g.setEdge( edge.source().id(), edge.target().id(), { minlen: getVal( edge, options.minLen ), weight: getVal( edge, options.edgeWeight ), name: edge.id() }, edge.id() ); // console.log( g.edge(edge.source().id(), edge.target().id(), edge.id()) ); } dagre.layout( g ); let gNodeIds = g.nodes(); for( let i = 0; i < gNodeIds.length; i++ ){ let id = gNodeIds[i]; let n = g.node( id ); cy.getElementById(id).scratch().dagre = n; } let dagreBB; if( options.boundingBox ){ dagreBB = { x1: Infinity, x2: -Infinity, y1: Infinity, y2: -Infinity }; nodes.forEach(function( node ){ let dModel = node.scratch().dagre; dagreBB.x1 = Math.min( dagreBB.x1, dModel.x ); dagreBB.x2 = Math.max( dagreBB.x2, dModel.x ); dagreBB.y1 = Math.min( dagreBB.y1, dModel.y ); dagreBB.y2 = Math.max( dagreBB.y2, dModel.y ); }); dagreBB.w = dagreBB.x2 - dagreBB.x1; dagreBB.h = dagreBB.y2 - dagreBB.y1; } else { dagreBB = bb; } let constrainPos = function( p ){ if( options.boundingBox ){ let xPct = dagreBB.w === 0 ? 0 : (p.x - dagreBB.x1) / dagreBB.w; let yPct = dagreBB.h === 0 ? 0 : (p.y - dagreBB.y1) / dagreBB.h; return { x: bb.x1 + xPct * bb.w, y: bb.y1 + yPct * bb.h }; } else { return p; } }; nodes.layoutPositions(layout, options, function( ele ){ ele = typeof ele === "object" ? ele : this; let dModel = ele.scratch().dagre; return constrainPos({ x: dModel.x, y: dModel.y }); }); return this; // chaining };
arguments.length>1?(this._strictGetNode(b),b in this._incidentEdges[a]?this._incidentEdges[a][b].keys():[]):g.union(e.values(this._incidentEdges[a])).keys()},d.prototype.toString=function(){return"Graph "+JSON.stringify(this,null,2)},d.prototype.addNode=function(a,b){return a=f.prototype.addNode.call(this,a,b),this._incidentEdges[a]={},a},d.prototype.delNode=function(a){f.prototype.delNode.call(this,a),delete this._incidentEdges[a]},d.prototype.addEdge=function(a,b,c,d){return f.prototype._addEdge.call(this,a,b,c,d,this._incidentEdges,this._incidentEdges)},d.prototype.delEdge=function(a){f.prototype._delEdge.call(this,a,this._incidentEdges,this._incidentEdges)}},{"./BaseGraph":25,"./util":45,"cp-data":19}],30:[function(a,b,c){function d(a){function b(c,e){d.has(c)||(d.add(c),e.push(c),a.neighbors(c).forEach(function(a){b(a,e)}))}var c=[],d=new e;return a.nodes().forEach(function(a){var d=[];b(a,d),d.length>0&&c.push(d)}),c}var e=a("cp-data").Set;b.exports=d},{"cp-data":19}],31:[function(a,b,c){function d(a,b,c,d){function f(b){var d=a.incidentNodes(b),e=d[0]!==i?d[0]:d[1],f=g[e],k=c(b),l=j.distance+k;if(0>k)throw new Error("dijkstra does not allow negative edge weights. Bad edge: "+b+" Weight: "+k);l<f.distance&&(f.distance=l,f.predecessor=i,h.decrease(e,l))}var g={},h=new e;c=c||function(){return 1},d=d||(a.isDirected()?function(b){return a.outEdges(b)}:function(b){return a.incidentEdges(b)}),a.eachNode(function(a){var c=a===b?0:Number.POSITIVE_INFINITY;g[a]={distance:c},h.add(a,c)});for(var i,j;h.size()>0&&(i=h.removeMin(),j=g[i],j.distance!==Number.POSITIVE_INFINITY);)d(i).forEach(f);return g}var e=a("cp-data").PriorityQueue;b.exports=d},{"cp-data":19}],32:[function(a,b,c){function d(a,b,c){var d={};return a.eachNode(function(f){d[f]=e(a,f,b,c)}),d}var e=a("./dijkstra");b.exports=d},{"./dijkstra":31}],33:[function(a,b,c){function d(a){return e(a).filter(function(a){return a.length>1})}var e=a("./tarjan");b.exports=d},{"./tarjan":39}],34:[function(a,b,c){function d(a,b,c){var d={},e=a.nodes();return b=b||function(){return 1},c=c||(a.isDirected()?function(b){return a.outEdges(b)}:function(b){return a.incidentEdges(b)}),e.forEach(function(f){d[f]={},d[f][f]={distance:0},e.forEach(function(a){f!==a&&(d[f][a]={distance:Number.POSITIVE_INFINITY})}),c(f).forEach(function(c){var e=a.incidentNodes(c),g=e[0]!==f?e[0]:e[1],h=b(c);h<d[f][g].distance&&(d[f][g]={distance:h,predecessor:f})})}),e.forEach(function(a){var b=d[a];e.forEach(function(c){var f=d[c];e.forEach(function(c){var d=f[a],e=b[c],g=f[c],h=d.distance+e.distance;h<g.distance&&(g.distance=h,g.predecessor=e.predecessor)})})}),d}b.exports=d},{}],35:[function(a,b,c){function d(a){try{e(a)}catch(b){if(b instanceof e.CycleException)return!1;throw b}return!0}var e=a("./topsort");b.exports=d},{"./topsort":40}],36:[function(a,b,c){function d(a,b,c){function d(b,e){if(f.has(b))throw new Error("The input graph is not a tree: "+a);f.add(b),a.neighbors(b).forEach(function(a){a!==e&&d(a,b)}),c(b)}var f=new e;if(a.isDirected())throw new Error("This function only works for undirected graphs");d(b)}var e=a("cp-data").Set;b.exports=d},{"cp-data":19}],37:[function(a,b,c){function d(a,b,c){function d(b,e){if(f.has(b))throw new Error("The input graph is not a tree: "+a);f.add(b),c(b),a.neighbors(b).forEach(function(a){a!==e&&d(a,b)})}var f=new e;if(a.isDirected())throw new Error("This function only works for undirected graphs");d(b)}var e=a("cp-data").Set;b.exports=d},{"cp-data":19}],38:[function(a,b,c){function d(a,b){function c(c){var e=a.incidentNodes(c),f=e[0]!==d?e[0]:e[1],g=i.priority(f);if(void 0!==g){var j=b(c);g>j&&(h[f]=d,i.decrease(f,j))}}var d,g=new e,h={},i=new f;if(0===a.order())return g;a.eachNode(function(a){i.add(a,Number.POSITIVE_INFINITY),g.addNode(a)}),i.decrease(a.nodes()[0],0);for(var j=!1;i.size()>0;){if(d=i.removeMin(),d in h)g.addEdge(null,d,h[d]);else{if(j)throw new Error("Input graph is not connected: "+a);j=!0}a.incidentEdges(d).forEach(c)}return g}var e=a("../Graph"),f=a("cp-data").PriorityQueue;b.exports=d},{"../Graph":29,"cp-data":19}],39:[function(a,b,c){function d(a){function b(g){var h=e[g]={onStack:!0,lowlink:c,index:c++};if(d.push(g),a.successors(g).forEach(function(a){a in e?e[a].onStack&&(h.lowlink=Math.min(h.lowlink,e[a].index)):(b(a),h.lowlink=Math.min(h.lowlink,e[a].lowlink))}),h.lowlink===h.index){var i,j=[];do i=d.pop(),e[i].onStack=!1,j.push(i);while(g!==i);f.push(j)}}if(!a.isDirected())throw new Error("tarjan can only be applied to a directed graph. Bad input: "+a);var c=0,d=[],e={},f=[];return a.nodes().forEach(function(a){a in e||b(a)}),f}b.exports=d},{}],40:[function(a,b,c){function d(a){function b(g){if(g in d)throw new e;g in c||(d[g]=!0,c[g]=!0,a.predecessors(g).forEach(function(a){b(a)}),delete d[g],f.push(g))}if(!a.isDirected())throw new Error("topsort can only be applied to a directed graph. Bad input: "+a);var c={},d={},f=[],g=a.sinks();if(0!==a.order()&&0===g.length)throw new e;return a.sinks().forEach(function(a){b(a)}),f}function e(){}b.exports=d,d.CycleException=e,e.prototype.toString=function(){return"Graph has at least one cycle"}},{}],41:[function(a,b,c){function d(a){function b(){a.call(this),this._parents={},this._children={},this._children[null]=new e}return b.prototype=new a,b.prototype.constructor=b,b.prototype.parent=function(a,b){if(this._strictGetNode(a),arguments.length<2)return this._parents[a];if(a===b)throw new Error("Cannot make "+a+" a parent of itself");null!==b&&this._strictGetNode(b),this._children[this._parents[a]].remove(a),this._parents[a]=b,this._children[b].add(a)},b.prototype.children=function(a){return null!==a&&this._strictGetNode(a),this._children[a].keys()},b.prototype.addNode=function(b,c){return b=a.prototype.addNode.call(this,b,c),this._parents[b]=null,this._children[b]=new e,this._children[null].add(b),b},b.prototype.delNode=function(b){var c=this.parent(b);return this._children[b].keys().forEach(function(a){this.parent(a,c)},this),this._children[c].remove(b),delete this._parents[b],delete this._children[b],a.prototype.delNode.call(this,b)},b.prototype.copy=function(){var b=a.prototype.copy.call(this);return this.nodes().forEach(function(a){b.parent(a,this.parent(a))},this),b},b.prototype.filterNodes=function(b){function c(a){var b=d.parent(a);return null===b||e.hasNode(b)?(f[a]=b,b):b in f?f[b]:c(b)}var d=this,e=a.prototype.filterNodes.call(this,b),f={};return e.eachNode(function(a){e.parent(a,c(a))}),e},b}var e=a("cp-data").Set;b.exports=d},{"cp-data":19}],42:[function(a,b,c){function d(a){return Object.prototype.toString.call(a).slice(8,-1)}var e=a("../Graph"),f=a("../Digraph"),g=a("../CGraph"),h=a("../CDigraph");c.decode=function(a,b,c){if(c=c||f,"Array"!==d(a))throw new Error("nodes is not an Array");if("Array"!==d(b))throw new Error("edges is not an Array");if("string"==typeof c)switch(c){case"graph":c=e;break;case"digraph":c=f;break;case"cgraph":c=g;break;case"cdigraph":c=h;break;default:throw new Error("Unrecognized graph type: "+c)}var i=new c;return a.forEach(function(a){i.addNode(a.id,a.value)}),i.parent&&a.forEach(function(a){a.children&&a.children.forEach(function(b){i.parent(b,a.id)})}),b.forEach(function(a){i.addEdge(a.id,a.u,a.v,a.value)}),i},c.encode=function(a){var b=[],c=[];a.eachNode(function(c,d){var e={id:c,value:d};if(a.children){var f=a.children(c);f.length&&(e.children=f)}b.push(e)}),a.eachEdge(function(a,b,d,e){c.push({id:a,u:b,v:d,value:e})});var d;if(a instanceof h)d="cdigraph";else if(a instanceof g)d="cgraph";else if(a instanceof f)d="digraph";else{if(!(a instanceof e))throw new Error("Couldn't determine type of graph: "+a);d="graph"}return{nodes:b,edges:c,type:d}}},{"../CDigraph":26,"../CGraph":27,"../Digraph":28,"../Graph":29}],43:[function(a,b,c){var d=a("cp-data").Set;c.all=function(){return function(){return!0}},c.nodesFromList=function(a){var b=new d(a);return function(a){return b.has(a)}}},{"cp-data":19}],44:[function(a,b,c){var d=a("./Graph"),e=a("./Digraph");d.prototype.toDigraph=d.prototype.asDirected=function(){var a=new e;return this.eachNode(function(b,c){a.addNode(b,c)}),this.eachEdge(function(b,c,d,e){a.addEdge(null,c,d,e),a.addEdge(null,d,c,e)}),a},e.prototype.toGraph=e.prototype.asUndirected=function(){var a=new d;return this.eachNode(function(b,c){a.addNode(b,c)}),this.eachEdge(function(b,c,d,e){a.addEdge(b,c,d,e)}),a}},{"./Digraph":28,"./Graph":29}],45:[function(a,b,c){c.values=function(a){var b,c=Object.keys(a),d=c.length,e=new Array(d);for(b=0;d>b;++b)e[b]=a[c[b]];return e}},{}],46:[function(a,b,c){b.exports="0.7.4"},{}]},{},[1]),"object"==typeof exports)var dagre=require("dagre");joint.layout.DirectedGraph={layout:function(a,b){b=b||{};var c=this._prepareData(a),d=dagre.layout();b.debugLevel&&d.debugLevel(b.debugLevel),b.rankDir&&d.rankDir(b.rankDir),b.rankSep&&d.rankSep(b.rankSep),b.edgeSep&&d.edgeSep(b.edgeSep),b.nodeSep&&d.nodeSep(b.nodeSep);var e=d.run(c);return e.eachNode(function(c,d){if(!d.dummy){var e=a.getCell(c);b.setPosition?b.setPosition(e,d):e.set("position",{x:d.x-d.width/2,y:d.y-d.height/2})}}),b.setLinkVertices&&e.eachEdge(function(c,d,e,f){var g=a.getCell(c);g&&(b.setVertices?b.setVertices(g,f.points):g.set("vertices",f.points))}),{width:e.graph().width,height:e.graph().height}},_prepareData:function(a){var b=new dagre.Digraph;return _.each(a.getElements(),function(a){b.hasNode(a.id)||b.addNode(a.id,{width:a.get("size").width,height:a.get("size").height,rank:a.get("rank")})}),_.each(a.getLinks(),function(a){if(!b.hasEdge(a.id)){var c=a.get("source").id,d=a.get("target").id;b.addEdge(a.id,c,d,{minLen:a.get("minLen")||1})}}),b}};