score:1
Accepted answer
A possible solution is to create a recursive function which will adjust your root
data coordinates in your drawTree
function.
Here is an recursive function which will stagger the nodes left and right. Note the comment where it is mentioned which part of the code controls the calculations of the coordinates.
function adjustClashes(data, siblings = 1, index = 1, radius = 20, height = 400) {
//can the node fit in the current x level?
// if not adjust it
let heightneeded = siblings * radius * 2;
if (heightneeded > height) {
// the code in this if statement will control the calculations for your new coordinates
// In the simplest case we adjust the nodes by staggering odd and even nodes
if (index % 2 != 0){
data.y = data.y + (radius * 2)
} else {
data.y = data.y - (radius * 2)
}
}
// if there are children go deeper and perform same adjustment
if (data.children) {
data.children.forEach((f, i) => {
return adjustClashes( f, data.children.length, i )
})
} else {
return;
}
// finally return the data
return data
}
Full snippet:
var data = {
name: "Root",
img: "https://www.freelogodesign.org/Content/img/logo-samples/flooop.png",
children: [
{
name: "3",
img: "https://www.freelogodesign.org/Content/img/logo-samples/flooop.png"
},
{
name: "4",
img: "https://www.freelogodesign.org/Content/img/logo-samples/flooop.png"
},
{
name: "1",
img: "https://www.freelogodesign.org/Content/img/logo-samples/flooop.png"
},
{
name: "2",
img: "https://www.freelogodesign.org/Content/img/logo-samples/flooop.png"
},
{
name: "1",
img: "https://www.freelogodesign.org/Content/img/logo-samples/flooop.png"
},
{
name: "2",
img: "https://www.freelogodesign.org/Content/img/logo-samples/flooop.png"
},
{
name: "1",
img: "https://www.freelogodesign.org/Content/img/logo-samples/flooop.png"
},
{
name: "2",
img: "https://www.freelogodesign.org/Content/img/logo-samples/flooop.png"
},
{
name: "1",
img: "https://www.freelogodesign.org/Content/img/logo-samples/flooop.png"
},
{
name: "2",
img: "https://www.freelogodesign.org/Content/img/logo-samples/flooop.png"
},
{
name: "1",
img: "https://www.freelogodesign.org/Content/img/logo-samples/flooop.png"
},
{
name: "2",
img: "https://www.freelogodesign.org/Content/img/logo-samples/flooop.png"
},
{
name: "1",
img: "https://www.freelogodesign.org/Content/img/logo-samples/flooop.png"
},
{
name: "2",
img: "https://www.freelogodesign.org/Content/img/logo-samples/flooop.png"
},
{
name: "1",
img: "https://www.freelogodesign.org/Content/img/logo-samples/flooop.png"
},
{
name: "2",
img: "https://www.freelogodesign.org/Content/img/logo-samples/flooop.png"
}
],
parent: [
{
name: "1",
img: "https://www.freelogodesign.org/Content/img/logo-samples/flooop.png"
}
]
};
var bgColors = [
"#fd90b5",
"#6ca1e9",
"#fa975c",
"#eb7092",
"#f88962",
"#a094ed",
"#7f8de1"
];
var dr = 0;
// Left data
var data1 = {
name: data.name,
img: data.img,
children: JSON.parse(JSON.stringify(data.children))
};
// Right data
var data2 = {
name: data.name,
img: data.img,
children: JSON.parse(JSON.stringify(data.parent))
};
// Create d3 hierarchies
var right = d3.hierarchy(data1);
var left = d3.hierarchy(data2);
// Render both trees
drawTree(right, "right");
drawTree(left, "left");
// draw single tree
function drawTree(root, pos) {
var refType;
if (pos == "left") refType = "left";
else refType = "right";
var SWITCH_CONST = 1;
if (pos === "left") {
SWITCH_CONST = -1;
}
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var g = svg.append("g").attr("transform", "translate(" + width / 2 + ",0)");
var tree = d3.tree().size([height, (SWITCH_CONST * (width - 150)) / 2]);
tree(root);
function adjustClashes(
data,
siblings = 1,
index = 1,
radius = 20,
height = 400
) {
//can the node fit in the current x level?
// if not adjust it
let heightneeded = siblings * radius * 2;
if (heightneeded > height) {
// the code in this if statement will control the calculations for your new coordinates
// In the simplest case we adjust the nodes by staggering odd and even nodes
if (index % 2 != 0) {
data.y = data.y + radius * 2;
} else {
data.y = data.y - radius * 2;
}
}
// if there are children go deeper and perform same adjustment
if (data.children) {
data.children.forEach((f, i) => {
return adjustClashes(f, data.children.length, i);
});
} else {
return;
}
// finally return the data
return data;
}
root = adjustClashes(root);
var nodes = root.descendants();
var links = root.links();
nodes[0].x = height / 2;
// Create links
var link = g.selectAll(".link").data(links).enter();
link
.append("path")
.attr("class", "link")
.attr("d", function (d) {
//first return returns a curve and the second will return straight lines in
//return "M" + d.target.y + "," + d.target.x + "C" + (d.target.y + d.source.y) / 2.5 + "," + d.target.x + " " + (d.target.y + d.source.y) / 2 + "," + d.source.x + " " + d.source.y + "," + d.source.x;
return (
"M" +
d.target.y +
"," +
d.target.x +
"A" +
dr +
"," +
dr +
" 1,0 0 " +
d.source.y +
"," +
d.source.x
);
});
link
.append("text")
.attr("font-family", "Arial, Helvetica, sans-serif")
.attr("fill", "Black")
.style("font", "normal 12px Arial")
.attr("transform", function (d) {
return (
"translate(" +
(d.source.y + d.target.y) / 2 +
"," +
(d.source.x + d.target.x) / 2 +
")"
);
})
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.data(nodes)
.text(refType);
// Create nodes
var node = g
.selectAll(".node")
.data(nodes)
.enter()
.append("g")
.attr("class", function (d) {
return "node" + (d.children ? " node--internal" : " node--leaf");
})
.attr("transform", function (d) {
return "translate(" + d.y + "," + d.x + ")";
});
node
.append("circle")
.attr("class", "icon-wrap")
.attr("x", 0)
.attr("y", 0)
.attr("r", 25)
.style("fill", "black");
node
.append("image")
.attr("href", (d) => d.data.img)
.attr("x", "-25")
.attr("y", "-25")
.attr("height", "50")
.attr("width", "50");
node
.append("text")
.attr("dy", 45)
.style("text-anchor", "middle")
.text((d) => d.data.name);
}
.node circle {
fill: #999;
}
.node text {
font: 12px sans-serif;
}
.node--internal circle {
fill: #555;
}
.link {
fill: none;
stroke: #555;
stroke-opacity: 0.4;
stroke-width: 1.5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<svg width="700" height="400"></svg>
Update
The following CodePen.io pen shows for example a 3 level staggering of child nodes and even adds a slight margin to space it out more evenly.
To do this simply add margin
as a default parameter to the adjustClashes
function and change the if statement as follows:
if (heightneeded > height) {
// the code in this if statement will control the calculations for your new coordinates
// In the simplest case we adjust the nodes by staggering odd and even nodes
if (index % 3 == 0) {
data.y = data.y - radius * 2 - margin ;
} else if (index % 3 == 1) {
data.y = data.y;
} else {
data.y = data.y + radius * 2 + margin;
}
}
Source: stackoverflow.com
Related Query
- How to Show all the child nodes when there are many
- how to improve the drilling performance of d3 sunburst chart when there are too many paths? like dynamically show partial levels?
- How to show and hides nodes when you move the mouse over a node in D3 Javascript
- How to avoid the overlapping of text elements on the TreeMap when child elements are opened in D3.js?
- How do I hide the text labels in d3 when the nodes are too small?
- what is the point of calling selectAll when there are no existing nodes yet on D3.js
- How can i show the labels on the x axis when there is data overlap in d3js?
- D3: How to stop child nodes from being attracted towards the center when parent is dragged in force-directed tree?
- MultiBar chart with nvd3 / d3 only shows labels for every other tick on the x-axis. How can I get them all to show up?
- How can I start with all the nodes collapsed in d3js?
- d3.js How to make all the nodes collapsed in Collapsible indented Tree
- How to make all the nodes circle the center node?
- How to modify axis labels in d3 for a stacked bar chart when the axis labels are mapped as part of the scale's domain
- Select all the paths and parent nodes of a child node in tree layout
- How to make grid lines when axes are aligned at the middle?
- How to let line or path follow the shape when shape are move
- How to show the value of each element when hovering
- D3 Tree - How to expand tree to show and highlight all nodes of same name?
- Is there a way to make the nodes draggable/to another parent or child node to rearrange the nodes in d3.js
- D3.js: After setting xAxis labels text-orientation vertical, how to make sure all the texts are placed below the horizontal line
- How to assign alternative depth values only to the child nodes in d3js?
- Calculate how many std deviations the values of certain keys are from the mean
- How to load data to D3 chart from JSON when there are only tuples
- D3 - not all children nodes are shown at the same time
- Drawing a line using d3 is not visible when all data items are the same
- How to change the colors of all highlighted nodes in d3JS force directed graph?
- How to show the unhighlighted/ not selected data points on scatter plots when using brush/group in dc.js? And is multiple brushes possible in dc.js
- How to display "pie chart unavailable" message when all the data is 0 in a pie chart?
- With d3.js, how do you modify corresponding nodes when you have multiple selections for the same data?
- How Can I highlight the parents names and the connection lines when I hover on their child in family tree
More Query from same tag
- d3 - axis ticks not working unlike tickValues
- Plotting multiple lines with different number of values
- D3 Sankey Diagram: Adding New Node and Link with Transition
- What is a "context" in this context: "symbol.context([context])"
- D3js Ordinal Axis does not show all the ticks
- How to create Bubble chart in C3.js
- D3 v4 - Trying to convert dates formatted like this in my data file '2017-09-19T00:00:00' to a more readable 'Sep 19, 2017'
- D3.js add label to bar chart
- Django passing data to D3 - D3. eachFor is not a function
- D3 - rotating rect text elements individually instead of as group
- Plunker bad request with status code 400
- Using c3 js, Is there a way to show more x-axis values when zooming in?
- d3: Multi-Series Line Chart with associative array
- D3 selection variable reuse after append
- d3 mercator, geo, and path methods
- D3 JS Graphs not getting toggled on click of radio buttons
- How do I use D3js in Wordpress?
- append circle to map in d3
- D3 csv return rows
- d3: make the d3.csv function syncronous
- Append multiple data arrays to data points
- Stacked Bar Chart with general update pattern d3.js
- My d3 Scatter plot is not displaying anything at all
- Dynamic rescaling in d3.js has weird artifacts in gridlines
- Modify D3.js Circle Progress Graph to show range of percentages
- How to change the distance between nodes in a force layout?
- D3 Set labels on Legend
- Could not reference properly d3js (4.7) from TypeScript (2.4.2)
- skipping JSON data records based on inner array values- D3
- Filtering and Ordering in dimplejs visualization