2016-02-03 82 views
1

我正在關注this tutorial以生成雙樹並將肘形連接器轉換爲對角連接器。 這是我試過的在d3 js雙樹中單獨鏈接鏈接

截至目前,應該走向左邊的邊也朝着正確的方向走,我該如何將這些邊翻轉到左邊。

我試着替換nodes.forEach函數如下。在第二種情況下,鏈接被翻轉,但節點從右向左移動。

nodes.forEach(function(d) { 
    if(d.isRight) 
    { 
     d.y = d.depth * 180 + halfWidth; 
    } 
    else 
    { 
     d.y = width - (d.depth * 180 + halfWidth); 
    } 

    }); 

沒有工作。任何幫助表示讚賞。

var margin = { 
 
    top: 30, 
 
    right: 10, 
 
    bottom: 10, 
 
    left: 10 
 
    }, 
 
    width = 960 - margin.left - margin.right, 
 
    halfWidth = width/2, 
 
    height = 500 - margin.top - margin.bottom, 
 
    i = 0, 
 
    duration = 500, 
 
    root; 
 

 
var getChildren = function(d) { 
 
    var a = []; 
 
    if (d.winners) 
 
    for (var i = 0; i < d.winners.length; i++) { 
 
     d.winners[i].isRight = false; 
 
     d.winners[i].parent = d; 
 
     a.push(d.winners[i]); 
 
    } 
 
    if (d.challengers) 
 
    for (var i = 0; i < d.challengers.length; i++) { 
 
     d.challengers[i].isRight = true; 
 
     d.challengers[i].parent = d; 
 
     a.push(d.challengers[i]); 
 
    } 
 
    return a.length ? a : null; 
 
}; 
 

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

 
var diagonal = d3.svg.diagonal() 
 
    .projection(function(d) { 
 
    return [d.y, d.x]; 
 
    }); 
 

 
var connector = diagonal; 
 

 
var calcLeft = function(d) { 
 
    var l = d.y; 
 
    if (!d.isRight) { 
 
    l = d.y - halfWidth; 
 
    l = halfWidth - l; 
 
    } 
 
    return { 
 
    x: d.x, 
 
    y: l 
 
    }; 
 
}; 
 

 
var vis = d3.select("#chart").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 + ")"); 
 

 
setTimeout(function() { 
 
    var json = { 
 
    "name": "Overall Winner", 
 
    "winners": [{ 
 
     "name": "Winner Left 1", 
 
     "winners": [{ 
 
     "name": "Winner Left 3" 
 
     }, { 
 
     "name": "Winner Left 4" 
 
     }] 
 
    }, { 
 
     "name": "Winner Left 2" 
 
    }], 
 
    "challengers": [{ 
 
     "name": "Challenger Right 1", 
 
     "challengers": [{ 
 
     "name": "Challenger Right 3" 
 
     }, { 
 
     "name": "Challenger Right 4" 
 
     }] 
 
    }, { 
 
     "name": "Challenger Right 2", 
 
     "challengers": [{ 
 
     "name": "Challenger Right 5" 
 
     }, { 
 
     "name": "Challenger Right 6" 
 
     }] 
 
    }] 
 
    }; 
 

 
    root = json; 
 
    root.x0 = height/2; 
 
    root.y0 = width/2; 
 

 
    var t1 = d3.layout.tree().size([height, halfWidth]).children(function(d) { 
 
     return d.winners; 
 
    }), 
 
    t2 = d3.layout.tree().size([height, halfWidth]).children(function(d) { 
 
     return d.challengers; 
 
    }); 
 
    t1.nodes(root); 
 
    t2.nodes(root); 
 

 
    var rebuildChildren = function(node) { 
 
    node.children = getChildren(node); 
 
    if (node.children) node.children.forEach(rebuildChildren); 
 
    } 
 
    rebuildChildren(root); 
 
    root.isRight = false; 
 
    update(root); 
 
}); 
 

 
var toArray = function(item, arr, d) { 
 
    arr = arr || []; 
 
    var dr = d || 1; 
 
    var i = 0, 
 
    l = item.children ? item.children.length : 0; 
 
    arr.push(item); 
 
    if (item.position && item.position === 'left') { 
 
    dr = -1; 
 
    } 
 
    item.y = dr * item.y; 
 
    for (; i < l; i++) { 
 
    toArray(item.children[i], arr, dr); 
 
    } 
 
    return arr; 
 
}; 
 

 
function update(source) { 
 
    // Compute the new tree layout. 
 
    var nodes = toArray(source); 
 

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

 
    // Update the nodes… 
 
    var node = vis.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("dy", function(d) { 
 
     return d.isRight ? 14 : -8; 
 
    }) 
 
    .attr("text-anchor", "middle") 
 
    .text(function(d) { 
 
     return d.name; 
 
    }) 
 
    .style("fill-opacity", 1e-6); 
 

 
    // Transition nodes to their new position. 
 
    var nodeUpdate = node.transition() 
 
    .duration(duration) 
 
    .attr("transform", function(d) { 
 
     p = calcLeft(d); 
 
     return "translate(" + p.y + "," + p.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) { 
 
     p = calcLeft(d.parent || source); 
 
     return "translate(" + p.y + "," + p.x + ")"; 
 
    }) 
 
    .remove(); 
 

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

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

 
    // Update the links... 
 
    var link = vis.selectAll("path.link") 
 
    .data(tree.links(nodes), function(d) { 
 
     return d.target.id; 
 
    }); 
 

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

 
    // Transition links to their new position. 
 
    link.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 = calcLeft(d.source || source); 
 
     if (d.source.isRight) o.y -= halfWidth - (d.target.y - d.source.y); 
 
     else o.y += halfWidth - (d.target.y - d.source.y); 
 
     return connector({ 
 
     source: o, 
 
     target: o 
 
     }); 
 
    }) 
 
    .remove(); 
 

 
    // Stash the old positions for transition. 
 
    nodes.forEach(function(d) { 
 
    var p = calcLeft(d); 
 
    d.x0 = p.x; 
 
    d.y0 = p.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(source); 
 
    } 
 
}
.node circle { 
 

 
    cursor: pointer; 
 

 
    fill: #fff; 
 

 
    stroke: steelblue; 
 

 
    stroke-width: 1.5px; 
 

 
} 
 

 
.node text { 
 

 
    font: 10px sans-serif; 
 

 
} 
 

 
path.link { 
 

 
    fill: none; 
 

 
    stroke: #ccc; 
 

 
    stroke-width: 1.5px; 
 

 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 
 
<div id="chart"></div>

+1

我想與大家分享一些東西的思想http://plnkr.co/edit/Ixnq1vkzxNx379deFF1T?p=preview可能是你可以通過它即興.. – Cyril

+0

感謝您的幫助,即使我這麼長時間擺弄它。有沒有辦法使用兩個單獨的'd.y'值來繪製節點和邊緣。所以我可以使用默認的'd.y = d.depth * 180 + halfWidth;'爲節點和'd.y = width - (d.depth * 180 + halfWidth);'爲邊緣? –

+0

其實我試圖用對角線連接器做到這一點,它不工作。 –

回答

1

隨着一些努力發現周圍的工作做同樣的。

這是代碼。

var margin = { 
 
    top: 30, 
 
    right: 10, 
 
    bottom: 10, 
 
    left: 10 
 
    }, 
 
    width = 960 - margin.left - margin.right, 
 
    halfWidth = width/2, 
 
    height = 500 - margin.top - margin.bottom, 
 
    i = 0, 
 
    duration = 500, 
 
    root; 
 

 
var getChildren = function(d) { 
 
    var a = []; 
 
    if (d.winners) 
 
    for (var i = 0; i < d.winners.length; i++) { 
 
     d.winners[i].isRight = false; 
 
     d.winners[i].parent = d; 
 
     a.push(d.winners[i]); 
 
    } 
 
    if (d.challengers) 
 
    for (var i = 0; i < d.challengers.length; i++) { 
 
     d.challengers[i].isRight = true; 
 
     d.challengers[i].parent = d; 
 
     a.push(d.challengers[i]); 
 
    } 
 
    return a.length ? a : null; 
 
}; 
 

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

 
var diagonal = d3.svg.diagonal() 
 
    .projection(function(d) { 
 
    return [d.y, d.x]; 
 
    }); 
 

 
var connector = diagonal; 
 

 
var calcLeft = function(d) { 
 
    var l = d.y; 
 
    if (!d.isRight) { 
 
    l = d.y - halfWidth; 
 
    l = halfWidth - l; 
 
    } 
 
    return { 
 
    x: d.x, 
 
    y: l 
 
    }; 
 
}; 
 

 
var vis = d3.select("#chart").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 + ")"); 
 

 
setTimeout(function() { 
 
    var json = { 
 
    "name": "Overall Winner", 
 
    "winners": [{ 
 
     "name": "Winner Left 1", 
 
     "winners": [{ 
 
     "name": "Winner Left 3" 
 
     }, { 
 
     "name": "Winner Left 4" 
 
     }] 
 
    }, { 
 
     "name": "Winner Left 2" 
 
    }], 
 
    "challengers": [{ 
 
     "name": "Challenger Right 1", 
 
     "challengers": [{ 
 
     "name": "Challenger Right 3" 
 
     }, { 
 
     "name": "Challenger Right 4" 
 
     }] 
 
    }, { 
 
     "name": "Challenger Right 2", 
 
     "challengers": [{ 
 
     "name": "Challenger Right 5" 
 
     }, { 
 
     "name": "Challenger Right 6" 
 
     }] 
 
    }] 
 
    }; 
 

 
    root = json; 
 
    root.x0 = height/2; 
 
    root.y0 = width/2; 
 

 
    var t1 = d3.layout.tree().size([height, halfWidth]).children(function(d) { 
 
     return d.winners; 
 
    }), 
 
    t2 = d3.layout.tree().size([height, halfWidth]).children(function(d) { 
 
     return d.challengers; 
 
    }); 
 
    t1.nodes(root); 
 
    t2.nodes(root); 
 

 
    var rebuildChildren = function(node) { 
 
    node.children = getChildren(node); 
 
    if (node.children) node.children.forEach(rebuildChildren); 
 
    } 
 
    rebuildChildren(root); 
 
    root.isRight = false; 
 
    update(root); 
 
}); 
 

 
var toArray = function(item, arr, d) { 
 
    arr = arr || []; 
 
    var dr = d || 1; 
 
    var i = 0, 
 
    l = item.children ? item.children.length : 0; 
 
    arr.push(item); 
 
    if (item.position && item.position === 'left') { 
 
    dr = -1; 
 
    } 
 
    item.y = dr * item.y; 
 
    for (; i < l; i++) { 
 
    toArray(item.children[i], arr, dr); 
 
    } 
 
    return arr; 
 
}; 
 

 
function update(source) { 
 
    // Compute the new tree layout. 
 
    var nodes = toArray(source); 
 

 
    // Normalize for fixed-depth. 
 
    nodes.forEach(function(d) { 
 
    if (d.isRight) { 
 
     d.y = d.depth * 180 + halfWidth; 
 
    } else { 
 
     d.y = width - (d.depth * 180 + halfWidth); 
 
    } 
 

 
    }); 
 

 

 
    // Update the nodes… 
 
    var node = vis.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("dy", function(d) { 
 
     return d.isRight ? 14 : -8; 
 
    }) 
 
    .attr("text-anchor", "middle") 
 
    .text(function(d) { 
 
     return d.name; 
 
    }) 
 
    .style("fill-opacity", 1e-6); 
 

 
    // Transition nodes to their new position. 
 
    var nodeUpdate = node.transition() 
 
    .duration(duration) 
 
    .attr("transform", function(d) { 
 
     console.log(d); 
 
     p = calcLeft(d); 
 
     if (d.isRight) { 
 

 
     return "translate(" + p.y + "," + p.x + ")"; 
 
     } else { 
 
     if (p.y != 470) { 
 
      var temp = p.y - 470; 
 
      p.y = 470 - temp; 
 
      return "translate(" + p.y + "," + p.x + ")"; 
 
     } else { 
 
      return "translate(" + p.y + "," + p.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) { 
 
     p = calcLeft(d.parent || source); 
 
     return "translate(" + p.y + "," + p.x + ")"; 
 
    }) 
 
    .remove(); 
 

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

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

 
    // Update the links... 
 
    var link = vis.selectAll("path.link") 
 
    .data(tree.links(nodes), function(d) { 
 
     return d.target.id; 
 
    }); 
 

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

 
    // Transition links to their new position. 
 
    link.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 = calcLeft(d.source || source); 
 
     if (d.source.isRight) o.y -= halfWidth - (d.target.y - d.source.y); 
 
     else o.y += halfWidth - (d.target.y - d.source.y); 
 
     return connector({ 
 
     source: o, 
 
     target: o 
 
     }); 
 
    }) 
 
    .remove(); 
 

 
    // Stash the old positions for transition. 
 
    nodes.forEach(function(d) { 
 
    var p = calcLeft(d); 
 
    d.x0 = p.x; 
 
    d.y0 = p.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(source); 
 
    } 
 
}
.node circle { 
 
    cursor: pointer; 
 
    fill: #fff; 
 
    stroke: steelblue; 
 
    stroke-width: 1.5px; 
 
} 
 
.node text { 
 
    font: 10px sans-serif; 
 
} 
 
path.link { 
 
    fill: none; 
 
    stroke: #ccc; 
 
    stroke-width: 1.5px; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 
 
<div id="chart"></div>