D3.js v3からバージョン4に移行しようとしています。私はchangelogをレビューしてすべての機能を更新しましたが、対角関数が削除されたので、ソースノードからターゲットノードへのパスをレンダリングできません。D3.jsでソースからターゲットへのパスをレンダリングできません。v3からv4に移行します。
私はPython ScriptでHTMLとd3.jsを使って生成したParse Treeを使用しています。 Pythonのスクリプトは、ここでそれがD3.jsバージョン3
function drawTree(){
var margin = {top: 20, right: 120, bottom: 20, left: 120},
width = 1060 - margin.right - margin.left,
height = 600 - margin.top - margin.bottom;
var i = 0,
duration = 750,// animation duration
root;// stores the tree structure in json format
var tree = d3.layout.tree()
.size([height, width]);
var edge_weight = d3.scale.linear()
\t \t \t \t \t .domain([0, 100])
.range([0, 100]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
// adding the svg to the html structure
var svg = d3.select("div#viz").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 treeData =
{
"name": "Grandparent",
"size" : 100,
"children": [
{
"name": "Parent A",
"size": 70,
"children": [
{ "name": "Son of A",
"size" : 30,
"children": [
{ "name": "grandson of A",
"size" : 3},
{ "name": "grandson 2 of A",
"size" : 2},
{ "name": "grandson 3 of A",
"size" : 5},
{ "name": "grandaughter of A",
"size" : 20,
"children": [
{ "name": "great-grandson of A",
"size" : 15},
{ "name": "great-grandaughter of A",
"size" : 5}
]
}
],
},
{ "name": "Daughter of A" ,
\t \t "size" : 40
}
]
},
{ "name": "Parent B",
"size" : 30 }],
\t };
edge_weight.domain([0,treeData.size]);
// Assigns parent, children, height, depth
root = treeData;
root.x0 = height/2;
root.y0 = 0;
root.children.forEach(collapse);
update(root);
d3.select(self.frameElement).style("height", "800px");
/**
* Updates the node.
* cloppases and expands the node bases on the structure of the source
* all 'children' nodes are expanded and '_children' nodes collapsed
* @param {json structure} source
*/
function update(source) {
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);
// 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('class', 'node')
.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.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
nodeUpdate.select("circle")
.attr("r", function(d){ console.log(">>>>>>>>", d);return edge_weight(d.size/2);})
.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…
// Update the links…
var link = svg.selectAll("path.link")
.data(links, 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("stroke-width", function(d){
\t return 1;
})
.attr("d", function(d) {
var o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
})
.attr("stroke", function(d){
\t return "lavender";});
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", function(d){
/* calculating the top shift */
var source = {x: d.source.x - edge_weight(calculateLinkSourcePosition(d)), y: d.source.y};
var target = {x: d.target.x, y: d.target.y};
return diagonal({source: source, target: target});
})
.attr("stroke-width", function(d){
\t return edge_weight(d.target.size);
});
// 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};
return diagonal({source: o, target: o});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
/**
* Calculates the source y-axis position of the link.
* @param {json structure} link
*/
function calculateLinkSourcePosition(link) {
\t targetID = link.target.id;
\t var childrenNumber = link.source.children.length;
\t var widthAbove = 0;
\t for (var i = 0; i < childrenNumber; i++)
\t {
\t \t if (link.source.children[i].id == targetID)
\t \t {
\t \t \t // we are done
\t \t \t widthAbove = widthAbove + link.source.children[i].size/2;
\t \t \t break;
\t \t }else {
\t \t \t // keep adding
\t \t \t widthAbove = widthAbove + link.source.children[i].size
\t \t }
\t }
\t return link.source.size/2 - widthAbove;
}
/*
* Toggle children on click.
* @param {node} d
*/
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
}
/*
* Collapses the node d and all the children nodes of d
* @param {node} d
*/
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
/*
* Collapses the node in the tree
*/
function collapseAll() {
\t root.children.forEach(collapse);
\t update(root);
}
/*
* Expands the node d and all the children nodes of d
* @param {node} d
*/
function expand(d) {
\t if (d._children) {
\t \t d._children = null;
\t }
\t if (d.children) {
\t \t d.children.forEach(expand);
\t }
\t
}
/*
* Expands all the nodes in the tree
*/
function expandAll() {
\t root.children.forEach(expand);
\t update(root);
}
}
.node {
cursor: pointer;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node text {
font: 10px sans-serif;
}
.link {
fill: none;
/*stroke: steelblue;*/
opacity: 0.3;
/*stroke-width: 1.5px;*/
}
#levels{
margin-left: 120px;
}
<!DOCTYPE html>
<meta charset="utf-8">
<body onLoad="drawTree()">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.0/d3.min.js"></script>
<button type="button" onclick="collapseAll()">Collapse All</button>
<button type="button" onclick="expandAll()">Expand All</button>
<div id="viz"></div>
</body>
で実行されていて、ここでは私の知る限りV4の移行となったようですが、HMTLドキュメントを生成します。
var margin = {
top: 20,
right: 120,
bottom: 20,
left: 120
},
width = 900 - margin.right - margin.left,
height = 400 - margin.top - margin.bottom;
var i = 0,
duration = 750, // animation duration
root; // stores the tree structure in json format
// declares a tree layout and assigns the size
var treemap = d3.tree().size([height, width]);
var edge_weight = d3.scaleLinear()
.domain([0, 100])
.range([0, 100]);
// Creates a curved (diagonal) path from parent to the child nodes
function diagonal(s, d) {
path = `M ${s.y} ${s.x}
C ${(s.y + d.y)/2} ${s.x},
${(s.y + d.y)/2} ${d.x},
${d.y} ${d.x}`
return path
}
// adding the svg to the html structure
var svg = d3.select("div#viz").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 treeData = {
"name": "Grandparent",
"size": 100,
"children": [{
"name": "Parent A",
"size": 70,
"children": [{
"name": "Son of A",
"size": 30,
"children": [{
"name": "grandson of A",
"size": 3
},
{
"name": "grandson 2 of A",
"size": 2
},
{
"name": "grandson 3 of A",
"size": 5
},
{
"name": "grandaughter of A",
"size": 20,
"children": [{
"name": "great-grandson of A",
"size": 15
},
{
"name": "great-grandaughter of A",
"size": 5
}
]
}
],
},
{
"name": "Daughter of A",
"size": 40
}
]
},
{
"name": "Parent B",
"size": 30
}
],
};
edge_weight.domain([0, treeData.size]);
// Assigns parent, children, height, depth
root = d3.hierarchy(treeData, function(d) {
return d.children;
});
root.x0 = height/2;
root.y0 = 0;
root.children.forEach(collapse);
update(root);
d3.select(self.frameElement).style("height", "800px");
/**
* Updates the node.
* cloppases and expands the node bases on the structure of the source
* all 'children' nodes are expanded and '_children' nodes collapsed
* @param {json structure} source
*/
function update(source) {
// Assigns the x and y position for the nodes
var treeData = treemap(root);
// Compute the new tree layout.
var nodes = treeData.descendants(),
links = treeData.descendants().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('class', 'node')
.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 = nodeEnter.merge(node);
nodeUpdate.transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + d.y + "," + d.x + ")";
});
nodeUpdate.select("circle")
.attr("r", function(d) {
return edge_weight(d.data.size/2);
})
.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(d) {
return d.id;
});
//.data(links, function(d) { return d.target.id; });
// Enter any new links at the parent's previous position.
var linkEnter = link.enter().insert('path', "g")
.attr("class", "link")
.attr('d', function(d) {
console.log("linkEnter", d);
var o = {
x: source.x,
y: source.y
}
console.log("o", o);
return diagonal(o, o)
})
.attr("stroke", function(d) {
return "cyan";
});
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", function(d) {
console.log("lala", d);
/* calculating the top shift */
var source = {
x: d.x - edge_weight(calculateLinkSourcePosition(d)),
y: d.y
};
var target = {
x: d.parent.x,
y: d.parent.y
};
return diagonal({
source: source,
target: target
});
})
.attr("stroke-width", function(d) {
return edge_weight(d.target.size);
});
// 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
};
return diagonal({
source: o,
target: o
});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
console.log("stash", d);
d.x0 = d.x;
d.y0 = d.y;
});
}
/**
* Calculates the source y-axis position of the link.
* @param {json structure} link
*/
function calculateLinkSourcePosition(link) {
targetID = link.target.id;
var childrenNumber = link.source.children.length;
var widthAbove = 0;
for (var i = 0; i < childrenNumber; i++) {
if (link.source.children[i].id == targetID) {
// we are done
widthAbove = widthAbove + link.source.children[i].size/2;
break;
} else {
// keep adding
widthAbove = widthAbove + link.source.children[i].size
}
}
return link.source.size/2 - widthAbove;
}
/*
* Toggle children on click.
* @param {node} d
*/
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
}
/*
* Collapses the node d and all the children nodes of d
* @param {node} d
*/
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
/*
* Collapses the node in the tree
*/
function collapseAll() {
root.children.forEach(collapse);
update(root);
}
/*
* Expands the node d and all the children nodes of d
* @param {node} d
*/
function expand(d) {
if (d._children) {
d.children = d._children;
d._children = null;
}
if (d.children) {
d.children.forEach(expand);
}
}
/*
* Expands all the nodes in the tree
*/
function expandAll() {
root.children.forEach(expand);
update(root);
}
.node {
cursor: pointer;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node text {
font: 10px sans-serif;
}
.link {
fill: none;
/*stroke: steelblue;*/
opacity: 0.3;
/*stroke-width: 1.5px;*/
}
#levels {
margin-left: 120px;
}
<body>
<script src="http://d3js.org/d3.v4.min.js"></script>
<button type="button" onclick="collapseAll()">Collapse All</button>
<button type="button" onclick="expandAll()">Expand All</button>
<div id="viz"></div>
</body>
私はちょうどブラインドほとんどの場合だと、あなたはすぐに私が間違って何をしたかがわかりますが、私は...今、しばらくの間、この見つめてきた
助けをあらかじめありがとう!
私の回答を複製(https://stackoverflow.com/q/40845121/5768908)でチェックしてください。同様の方法が導入されました。 –