2016-07-11 31 views
5

Se giochi con l'albero pieghevole qui sotto vedrai che quando arrivi alla fine dell'albero e espandi e comprimi i nodi le linee stanno facendo cose strane e non sono del tutto sicuro di ciò che guida il comportamento o se la mia riscrittura di enter link description here è completamente fuori base. Sono uscito da una struttura dati piatta e ho utilizzato stratify per trasformarlo in un layout ad albero. L'unico problema finora è la transizione di linea ... qualche pensiero?d3.js v4 transizione del link wacky nell'esempio di albero comprimibile

var data = [{ 
 
    "name": "Hazer 5000", 
 
    "parent": "CFO", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/stephen.jpg" 
 
    }, { 
 
    "name": "Employee 1", 
 
    "parent": "Hazer 5000", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/cory.jpg" 
 
    }, { 
 
    "name": "Analytics Area", 
 
    "parent": "Hazer 5000", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/matt.jpg" 
 
    }, { 
 
    "name": "Employee 2", 
 
    "parent": "Hazer 5000", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/XinheZhang.jpg" 
 
    }, { 
 
    "name": "Employee 3", 
 
    "parent": "Hazer 5000", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/craig.jpg" 
 
    }, { 
 
    "name": "Employee 4", 
 
    "parent": "Hazer 5000", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/youri.jpg" 
 
    }, { 
 
    "name": "Intern 1", 
 
    "parent": "Analytics Area", 
 
    "img": "" 
 
    }, { 
 
    "name": "Inter 2", 
 
    "parent": "Analytics Area", 
 
    "img": "" 
 
    }, { 
 
    "name": "CFO", 
 
    "parent": null, 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/Brett.jpg" 
 
    }, { 
 
    "name": "CPA", 
 
    "parent": "CFO", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/Wes.jpg" 
 
    }, { 
 
    "name": "Matt's wife", 
 
    "parent": "CPA", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/Amy_R.jpg" 
 
    }, { 
 
    "name": "Employee 5", 
 
    "parent": "CPA", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/DavidBriley.jpg" 
 
    }, { 
 
    "name": "Employee 6", 
 
    "parent": "CPA", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/BrittanyAllred_.jpg" 
 
    }, { 
 
    "name": "Employee 7", 
 
    "parent": "CPA", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/Shea.jpg" 
 
    }, { 
 
    "name": "Employee 8", 
 
    "parent": "Matt's wife", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/Mindy.jpg" 
 
    }, { 
 
    "name": "Employee 9", 
 
    "parent": "Matt's wife", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/Jessica_Stacy.jpg" 
 
    }, { 
 
    "name": "Employee 10", 
 
    "parent": "Matt's wife", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/FraleaneHudson.jpg" 
 
    },{ 
 
    "name": "Employee 11", 
 
    "parent": "Employee 9", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/MeganPierce_.jpg" 
 
    },{ 
 
    "name": "Intern 3", 
 
    "parent": "Employee 8", 
 
    "img": "" 
 
    }, { 
 
    "name": "Intern 4", 
 
    "parent": "Employee 8", 
 
    "img": "" 
 
    } 
 

 
]; 
 

 
var margin = {top: 20, right: 120, bottom: 20, left: 120}, 
 
    width = 960 - margin.right - margin.left, 
 
    height = 800 - margin.top - margin.bottom; 
 

 
var i = 0, 
 
    duration = 750, 
 
    root; 
 

 
var tree = d3.tree() 
 
    .size([height, width]); 
 

 
var svg = d3.select("body").append("svg") 
 
    .attr("width", width + margin.right + margin.left) 
 
    .attr("height", height + margin.top + margin.bottom) 
 
    .append("g") 
 
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 
 

 

 
var stratify = d3.stratify() 
 
    .id(function(d) { 
 
    return d.name;//This position 
 
    }) 
 
    .parentId(function(d) { 
 
    return d.parent; //What position this position reports to 
 
    }); 
 

 
var root = stratify(data); 
 

 
root.each(function(d) { 
 
    
 
    d.name = d.id; //transferring name to a name variable 
 
    d.id = i; //Assigning numerical Ids 
 
    i++; 
 
    
 
    }); 
 

 
    root.x0 = height/2; 
 
    root.y0 = 0; 
 

 
    function collapse(d) { 
 
    if (d.children) { 
 
     d._children = d.children; 
 
     d._children.forEach(collapse); 
 
     d.children = null; 
 
    } 
 
    } 
 

 
    root.children.forEach(collapse); 
 
    update(root); 
 

 

 
d3.select(self.frameElement).style("height", "800px"); 
 

 
function update(source) { 
 

 
    // Compute the new tree layout. 
 
    var nodes = tree(root).descendants(), 
 
     links = nodes.slice(1); 
 

 
    // Normalize for fixed-depth. 
 
    nodes.forEach(function(d) { d.y = d.depth * 180; }); 
 

 
    // Update the nodes… 
 
    var node = svg.selectAll("g.node") 
 
     .data(nodes, function(d) { return d.id || (d.id = ++i); }); 
 

 
    // Enter any new nodes at the parent's previous position. 
 
    var nodeEnter = node.enter().append("g") 
 
     .attr("class", "node") 
 
     .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }) 
 
     .on("click", click); 
 

 
    nodeEnter.append("circle") 
 
     .attr("r", 1e-6) 
 
     .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); 
 

 
    nodeEnter.append("text") 
 
     .attr("x", function(d) { return d.children || d._children ? -10 : 10; }) 
 
     .attr("dy", ".35em") 
 
     .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; }) 
 
     .text(function(d) { return d.name; }) 
 
     .style("fill-opacity", 1e-6); 
 

 
    // Transition nodes to their new position. 
 
    var nodeUpdate = node.merge(nodeEnter).transition() 
 
     .duration(duration) 
 
     .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; }); 
 

 
    nodeUpdate.select("circle") 
 
     .attr("r", 4.5) 
 
     .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); 
 

 
    nodeUpdate.select("text") 
 
     .style("fill-opacity", 1); 
 

 
    // Transition exiting nodes to the parent's new position. 
 
    var nodeExit = node.exit().transition() 
 
     .duration(duration) 
 
     .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; }) 
 
     .remove(); 
 

 
    nodeExit.select("circle") 
 
     .attr("r", 1e-6); 
 

 
    nodeExit.select("text") 
 
     .style("fill-opacity", 1e-6); 
 

 

 
    // Update the links… 
 
    var link = svg.selectAll("path.link") 
 
     .data(links); 
 
    
 
    // Transition links to their new position. 
 
    link.transition() 
 
     .duration(duration) 
 
     .attr("d", connector); 
 

 
    // Enter any new links at the parent's previous position. 
 
    var linkEnter = link.enter().insert("path", "g") 
 
         .attr("class", "link") 
 
         .attr("d", function(d) { 
 
     var o = {x: source.x0, y: source.y0, parent:{x: source.x0, y: source.y0}}; 
 
     return connector(o); 
 
     }); 
 

 
    // Transition links to their new position. 
 
    link.merge(linkEnter).transition() 
 
     .duration(duration) 
 
     .attr("d", connector); 
 

 
    // Transition exiting nodes to the parent's new position. 
 
    link.exit().transition() 
 
     .duration(duration) 
 
     .attr("d", function(d) { 
 
     var o = {x: source.x, y: source.y, parent:{x: source.x, y: source.y}}; 
 
     return connector(o); 
 
     }) 
 
     .remove(); 
 

 
    // Stash the old positions for transition. 
 
    nodes.forEach(function(d) { 
 
    d.x0 = d.x; 
 
    d.y0 = d.y; 
 
    }); 
 
} 
 

 
// Toggle children on click. 
 
function click(d) { 
 
    if (d.children) { 
 
    d._children = d.children; 
 
    d.children = null; 
 
    } else { 
 
    d.children = d._children; 
 
    d._children = null; 
 
    } 
 
    update(d); 
 
} 
 

 
function connector(d) { 
 
    return "M" + d.y + "," + d.x + 
 
    "C" + (d.y + d.parent.y)/2 + "," + d.x + 
 
    " " + (d.y + d.parent.y)/2 + "," + d.parent.x + 
 
    " " + d.parent.y + "," + d.parent.x; 
 
}
.node { 
 
    cursor: pointer; 
 
} 
 

 
.node circle { 
 
    fill: #fff; 
 
    stroke: steelblue; 
 
    stroke-width: 1.5px; 
 
} 
 

 
.node text { 
 
    font: 10px sans-serif; 
 
} 
 

 
.link { 
 
    fill: none; 
 
    stroke: #ccc; 
 
    stroke-width: 1.5px;
<script src="https://d3js.org/d3.v4.min.js"></script>

risposta

6

Sembra un problema con le chiavi utilizzate per l'associazione dati del collegamento. Mi riferisco al fatto che se chiami .data(links) senza un secondo argomento, d3 usa i come chiave quando calcola i set di inserimento/aggiornamento/uscita, e quindi quando espandi/comprimi lo stesso link può avere valori diversi i.

Credo di averlo funzionato, e tutto ciò che ho fatto è stato aggiungere il 2 ° param come una funzione che costruisce un id univoco di collegamento combinando l'id del nodo con l'id del suo nodo genitore.

I.e. invece di questo

var link = svg.selectAll("path.link") 
    .data(links) 

ho fatto questo

var link = svg.selectAll("path.link") 
    .data(links, function(link) { var id = link.id + '->' + link.parent.id; return id; }); 

Provalo ora:

var data = [{ 
 
    "name": "Hazer 5000", 
 
    "parent": "CFO", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/stephen.jpg" 
 
    }, { 
 
    "name": "Employee 1", 
 
    "parent": "Hazer 5000", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/cory.jpg" 
 
    }, { 
 
    "name": "Analytics Area", 
 
    "parent": "Hazer 5000", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/matt.jpg" 
 
    }, { 
 
    "name": "Employee 2", 
 
    "parent": "Hazer 5000", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/XinheZhang.jpg" 
 
    }, { 
 
    "name": "Employee 3", 
 
    "parent": "Hazer 5000", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/craig.jpg" 
 
    }, { 
 
    "name": "Employee 4", 
 
    "parent": "Hazer 5000", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/youri.jpg" 
 
    }, { 
 
    "name": "Intern 1", 
 
    "parent": "Analytics Area", 
 
    "img": "" 
 
    }, { 
 
    "name": "Inter 2", 
 
    "parent": "Analytics Area", 
 
    "img": "" 
 
    }, { 
 
    "name": "CFO", 
 
    "parent": null, 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/Brett.jpg" 
 
    }, { 
 
    "name": "CPA", 
 
    "parent": "CFO", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/Wes.jpg" 
 
    }, { 
 
    "name": "Matt's wife", 
 
    "parent": "CPA", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/Amy_R.jpg" 
 
    }, { 
 
    "name": "Employee 5", 
 
    "parent": "CPA", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/DavidBriley.jpg" 
 
    }, { 
 
    "name": "Employee 6", 
 
    "parent": "CPA", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/BrittanyAllred_.jpg" 
 
    }, { 
 
    "name": "Employee 7", 
 
    "parent": "CPA", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/Shea.jpg" 
 
    }, { 
 
    "name": "Employee 8", 
 
    "parent": "Matt's wife", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/Mindy.jpg" 
 
    }, { 
 
    "name": "Employee 9", 
 
    "parent": "Matt's wife", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/Jessica_Stacy.jpg" 
 
    }, { 
 
    "name": "Employee 10", 
 
    "parent": "Matt's wife", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/FraleaneHudson.jpg" 
 
    },{ 
 
    "name": "Employee 11", 
 
    "parent": "Employee 9", 
 
    "img": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/MeganPierce_.jpg" 
 
    },{ 
 
    "name": "Intern 3", 
 
    "parent": "Employee 8", 
 
    "img": "" 
 
    }, { 
 
    "name": "Intern 4", 
 
    "parent": "Employee 8", 
 
    "img": "" 
 
    } 
 

 
]; 
 

 
var margin = {top: 20, right: 120, bottom: 20, left: 120}, 
 
    width = 960 - margin.right - margin.left, 
 
    height = 800 - margin.top - margin.bottom; 
 

 
var i = 0, 
 
    duration = 750, 
 
    root; 
 

 
var tree = d3.tree() 
 
    .size([height, width]); 
 

 
var svg = d3.select("body").append("svg") 
 
    .attr("width", width + margin.right + margin.left) 
 
    .attr("height", height + margin.top + margin.bottom) 
 
    .append("g") 
 
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 
 

 

 
var stratify = d3.stratify() 
 
    .id(function(d) { 
 
    return d.name;//This position 
 
    }) 
 
    .parentId(function(d) { 
 
    return d.parent; //What position this position reports to 
 
    }); 
 

 
var root = stratify(data); 
 

 
root.each(function(d) { 
 
    
 
    d.name = d.id; //transferring name to a name variable 
 
    d.id = i; //Assigning numerical Ids 
 
    i++; 
 
    
 
    }); 
 

 
    root.x0 = height/2; 
 
    root.y0 = 0; 
 

 
    function collapse(d) { 
 
    if (d.children) { 
 
     d._children = d.children; 
 
     d._children.forEach(collapse); 
 
     d.children = null; 
 
    } 
 
    } 
 

 
    root.children.forEach(collapse); 
 
    update(root); 
 

 

 
d3.select(self.frameElement).style("height", "800px"); 
 

 
function update(source) { 
 

 
    // Compute the new tree layout. 
 
    var nodes = tree(root).descendants(), 
 
     links = nodes.slice(1); 
 

 
    // Normalize for fixed-depth. 
 
    nodes.forEach(function(d) { d.y = d.depth * 180; }); 
 

 
    // Update the nodes… 
 
    var node = svg.selectAll("g.node") 
 
     .data(nodes, function(d) { return d.id || (d.id = ++i); }); 
 

 
    // Enter any new nodes at the parent's previous position. 
 
    var nodeEnter = node.enter().append("g") 
 
     .attr("class", "node") 
 
     .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }) 
 
     .on("click", click); 
 

 
    nodeEnter.append("circle") 
 
     .attr("r", 1e-6) 
 
     .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); 
 

 
    nodeEnter.append("text") 
 
     .attr("x", function(d) { return d.children || d._children ? -10 : 10; }) 
 
     .attr("dy", ".35em") 
 
     .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; }) 
 
     .text(function(d) { return d.name; }) 
 
     .style("fill-opacity", 1e-6); 
 

 
    // Transition nodes to their new position. 
 
    var nodeUpdate = node.merge(nodeEnter).transition() 
 
     .duration(duration) 
 
     .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; }); 
 

 
    nodeUpdate.select("circle") 
 
     .attr("r", 4.5) 
 
     .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); 
 

 
    nodeUpdate.select("text") 
 
     .style("fill-opacity", 1); 
 

 
    // Transition exiting nodes to the parent's new position. 
 
    var nodeExit = node.exit().transition() 
 
     .duration(duration) 
 
     .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; }) 
 
     .remove(); 
 

 
    nodeExit.select("circle") 
 
     .attr("r", 1e-6); 
 

 
    nodeExit.select("text") 
 
     .style("fill-opacity", 1e-6); 
 

 

 
    // Update the links… 
 
    var link = svg.selectAll("path.link") 
 
     .data(links, function(link) { var id = link.id + '->' + link.parent.id; return id; }); 
 
    
 
    // Transition links to their new position. 
 
    link.transition() 
 
     .duration(duration) 
 
     .attr("d", connector); 
 

 
    // Enter any new links at the parent's previous position. 
 
    var linkEnter = link.enter().insert("path", "g") 
 
         .attr("class", "link") 
 
         .attr("d", function(d) { 
 
     var o = {x: source.x0, y: source.y0, parent:{x: source.x0, y: source.y0}}; 
 
     return connector(o); 
 
     }); 
 

 
    // Transition links to their new position. 
 
    link.merge(linkEnter).transition() 
 
     .duration(duration) 
 
     .attr("d", connector); 
 

 
    // Transition exiting nodes to the parent's new position. 
 
    link.exit().transition() 
 
     .duration(duration) 
 
     .attr("d", function(d) { 
 
     var o = {x: source.x, y: source.y, parent:{x: source.x, y: source.y}}; 
 
     return connector(o); 
 
     }) 
 
     .remove(); 
 

 
    // Stash the old positions for transition. 
 
    nodes.forEach(function(d) { 
 
    d.x0 = d.x; 
 
    d.y0 = d.y; 
 
    }); 
 
} 
 

 
// Toggle children on click. 
 
function click(d) { 
 
    if (d.children) { 
 
    d._children = d.children; 
 
    d.children = null; 
 
    } else { 
 
    d.children = d._children; 
 
    d._children = null; 
 
    } 
 
    update(d); 
 
} 
 

 
function connector(d) { 
 
    return "M" + d.y + "," + d.x + 
 
    "C" + (d.y + d.parent.y)/2 + "," + d.x + 
 
    " " + (d.y + d.parent.y)/2 + "," + d.parent.x + 
 
    " " + d.parent.y + "," + d.parent.x; 
 
}
.node { 
 
    cursor: pointer; 
 
} 
 

 
.node circle { 
 
    fill: #fff; 
 
    stroke: steelblue; 
 
    stroke-width: 1.5px; 
 
} 
 

 
.node text { 
 
    font: 10px sans-serif; 
 
} 
 

 
.link { 
 
    fill: none; 
 
    stroke: #ccc; 
 
    stroke-width: 1.5px;
<script src="https://d3js.org/d3.v4.min.js"></script>

+0

'var link = svg.selectAll ("path.link") .data (collegamenti, funzione (d) {return d.id;}); 'è stato abbastanza sufficiente per farlo funzionare. Grazie per avermi indicato nella giusta direzione !! – Tekill

+1

@Yourinium oh yeah - 'd.id' funziona perché c'è sempre un solo collegamento/genitore per bambino. – meetamit

+0

grazie per il tuo aiuto @meetamit – Tekill