D3: Multiple power layouts in one SVG?

I saw solutions for creating several power layouts on one page, where each layout is contained in its own SVG; however, I was not able to find help on how to incorporate multiple power layouts into one SVG. Each layout has its own data associated with it.

An example of what I'm doing right now can be found at http://jsfiddle.net/connorgr/SRAJa/ . I have included the key part of the code below. The end result looks very terrible, as the force layout has never been activated (or deleted) for everyone except the latest node / link data. Is there any way to prevent this?

I cannot combine the data together and use only one layout because of the option used for the visualization that I create.

/** * Creates a force layout in svgObj for each element in graphs * (svg) svgObj - The SVG to include the force layouts in * (json) graphs - An array of {"nodes":[...],"links":[...]} objects */ function generateMultiForce(svgObj, graphs) { for(var i=0; i < graphs.length; i++) { var graph = graphs[i]; var graphArea = svgObj.append("g"); var force = d3.layout.force() .charge(-200) .linkDistance(45) .size([width, height]) .nodes(graph.nodes) .links(graph.links) .start(); var link = graphArea.selectAll(".link") .data(graph.links) .enter().append("line") .attr("class", "link"); var nodeGroup = graphArea.selectAll("g") .data(graph.nodes) .enter().append("g") .call(force.drag); var node = nodeGroup.append("circle") .attr("class", "node") .attr("r", 5) .style("fill", function(d) { return color(d.group); }); var text = nodeGroup.append("text") .attr("x", 8) .attr("y", ".31em") .text(function(d) { return d.name; }); 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; }); nodeGroup.attr("transform", function(d) { return "translate("+d.x+","+d.y+")"; }); }); } } 
+6
source share
2 answers

The following approach limits strength, node, and data binding to their respective power circuits. This way you can add as many layouts as you want for the same SVG without causing interference between node. Each layout can be formatted separately. If you really want the layouts to influence each other, you can edit their respective tick functions.

 function layout1(inputNodes, inputLinks) { var force = d3.layout.force(); var nodes = force.nodes(); var links = force.links(); var update = function() { //append nodes and links from data force.on("tick",function(e){ //tick movement } } for(var i=0; i<inputNodes.length; i++){ nodes.push(inputNodes[i]); } for(var i=0; i<inputLinks.length; i++){ links.push(inputLinks[i]); } update(); } 

Now the second action-oriented layout can have an identical structure and the same variable names:

 function layout2(inputNodes, inputLinks) { var force = d3.layout.force(); var nodes = force.nodes(); var links = force.links(); var update = function() { //append nodes and links from data force.on("tick",function(e){ //tick movement } } for(var i=0; i<inputNodes.length; i++){ nodes.push(inputNodes[i]); } for(var i=0; i<inputLinks.length; i++){ links.push(inputLinks[i]); } update(); } 

Finally, create all the data:

 var layout1 = new layout1(inputNodes, inputLinks); var layout2 = new layout2(inputNodes, inputLinks); 

This method can be adopted to create multiple layouts on the fly. Hope this is close to what you are looking for.

+6
source

You can write the generateMultiForce function as a jquery plugin - this apparently preserves independent graphics and applies a force layout to both:

 var width = 600, height = 600; var color = d3.scale.category20(); var data = [ { "nodes": [ {"name": "Hello"}, {"name": "World"} ], "links": [ {"source": 0, "target": 1, "value": 0.5} ] }, { "nodes": [ {"name": "Zero"}, {"name": "One"}, {"name": "Two"} ], "links": [ {"source": 0, "target": 1, "value": 0.25}, {"source": 1, "target": 2, "value": 0.5}, {"source": 2, "target": 0, "value": 0.25} ] } ]; (function( $ ) { $.fn.generateMultiForce = function(svgObj) { return this.each(function() { var graph = this; var graphArea = svgObj.append("g"); var force = d3.layout.force() .charge(-200) .linkDistance(45) .size([width, height]) .nodes(graph.nodes) .links(graph.links) .start(); var link = graphArea.selectAll(".link") .data(graph.links) .enter().append("line") .attr("class", "link"); var nodeGroup = graphArea.selectAll("g") .data(graph.nodes) .enter().append("g") .call(force.drag); var node = nodeGroup.append("circle") .attr("class", "node") .attr("r", 5) .style("fill", function(d) { return color(d.group); }); var text = nodeGroup.append("text") .attr("x", 8) .attr("y", ".31em") .text(function(d) { return d.name; }); 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; }); nodeGroup.attr("transform", function(d) { return "translate("+d.x+","+d.y+")"; }); }); }); }; })(jQuery); var svgTest = d3.select("body").append("svg") .attr("width", width) .attr("height", height); $(data).generateMultiForce(svgTest); 
+2
source

Source: https://habr.com/ru/post/944050/


All Articles