jquery - 将所有叶子添加到节点 d3
问题描述
我正在尝试使用 d3 制作一个图表(树),但我想显示没有子属性的数据(即它们只是一片叶子),分组在一个圆圈中,单击时显示所有它包含的节点。目前我只实现了这一点:
这是我的data.json:
{"name": "flatmap",
"children": [
{"operator_number": 1, "operator": "flatmap", "word": "WordCount example reads text files and counts how often words occur. The input is text files and the output is text files. each line of which contains a word and the count of how often it occured, separated by a tab."},
{"operator_number": 1, "operator": "flatmap", "word": "Each mapper takes a line as input and breaks it into words. It then emits a key/value pair of the word and 1. Each reducer sums the counts for each word and emits a single key/value with the word and sum."},
{"operator_number": 1, "operator": "flatmap", "word": "As an optimization. the reducer is also used as a combiner on the map outputs. This reduces the amount of data sent across the network by combining each word into a single record."},
{
"name": "map",
"children": [
{"operator_number": 2, "operator": "map", "word": "line", "count": 1, "id": 325590249},
{"operator_number": 2, "operator": "map", "word": "example", "count": 1, "id": -1423699041},
{"operator_number": 2, "operator": "map", "word": "of", "count": 2, "id": 1018490952},
{"operator_number": 2, "operator": "map", "word": "count", "count": 1, "id": 220983708},
{"operator_number": 2, "operator": "map", "word": "and", "count": 3, "id": 101213523},
{"operator_number": 2, "operator": "map", "word": "WordCount", "count": 1, "id": -1806131025},
{"operator_number": 2, "operator": "map", "word": "occured.", "count": 1, "id": -1230160008},
{"operator_number": 2, "operator": "map", "word": "The", "count": 1, "id": -1004784477},
{"operator_number": 2, "operator": "map", "word": "of", "count": 1, "id": 1018490952},
{"operator_number": 2, "operator": "map", "word": "mapper", "count": 1, "id": 1207904727},
{"operator_number": 2, "operator": "map", "word": "and", "count": 4, "id": 101213523},
{"operator_number": 2, "operator": "map", "word": "as", "count": 1, "id": -680231157},
{"operator_number": 2, "operator": "map", "word": "It", "count": 1, "id": 1027745163},
{"operator_number": 2, "operator": "map", "word": "1.", "count": 1, "id": 1677874983},
{"operator_number": 2, "operator": "map", "word": "across", "count": 1, "id": -762857328},
{"operator_number": 2, "operator": "map", "word": "reduces", "count": 1, "id": -245012130},
{"operator_number": 2, "operator": "map", "word": "map", "count": 1, "id": -683473284},
{"operator_number": 2, "operator": "map", "word": "sent", "count": 1, "id": -1873763238},
{"operator_number": 2, "operator": "map", "word": "also", "count": 1, "id": -1106031042},
{"operator_number": 2, "operator": "map", "word": "outputs.", "count": 1, "id": 1544351802},
{"operator_number": 2, "operator": "map", "word": "an", "count": 1, "id": 1302757461},
{"operator_number": 2, "operator": "map", "word": "As", "count": 1, "id": 1898778492},
{"operator_number": 2, "operator": "map", "word": "separated", "count": 1, "id": -1355638496},
{"operator_number": 2, "operator": "map", "word": "it", "count": 1, "id": -147334043},
{"operator_number": 2, "operator": "map", "word": "text", "count": 3, "id": 1471308580},
{"operator_number": 2, "operator": "map", "word": "counts", "count": 1, "id": -341063633},
{"operator_number": 2, "operator": "map", "word": "word", "count": 1, "id": -1996542359},
{"operator_number": 2, "operator": "map", "word": "reads", "count": 1, "id": 1581597220},
{"operator_number": 2, "operator": "map", "word": "tab.", "count": 1, "id": 64393762},
{"operator_number": 2, "operator": "map", "word": "often", "count": 2, "id": -1659162332},
{"operator_number": 2, "operator": "map", "word": "how", "count": 2, "id": -394402229},
{"operator_number": 2, "operator": "map", "word": "input", "count": 1, "id": 398743969},
{"operator_number": 2, "operator": "map", "word": "by", "count": 1, "id": 984685240},
{"operator_number": 2, "operator": "map", "word": "pair", "count": 1, "id": -1791332846},
{"operator_number": 2, "operator": "map", "word": "into", "count": 1, "id": 660477844},
{"operator_number": 2, "operator": "map", "word": "sum.", "count": 1, "id": 1546120510},
{"operator_number": 2, "operator": "map", "word": "reducer", "count": 1, "id": -162177284},
{"operator_number": 2, "operator": "map", "word": "word", "count": 3, "id": -1996542359},
{"operator_number": 2, "operator": "map", "word": "emits", "count": 2, "id": -512399732},
{"operator_number": 2, "operator": "map", "word": "key/value", "count": 2, "id": 40637392},
{"operator_number": 2, "operator": "map", "word": "data", "count": 1, "id": -1989676802},
{"operator_number": 2, "operator": "map", "word": "This", "count": 1, "id": -144610220},
{"operator_number": 2, "operator": "map", "word": "network", "count": 1, "id": 1134884044},
{"operator_number": 2, "operator": "map", "word": "used", "count": 1, "id": 1115971993},
{"operator_number": 2, "operator": "map", "word": "output", "count": 1, "id": 1728288230},
{"operator_number": 2, "operator": "map", "word": "files", "count": 2, "id": 1433752967},
{"operator_number": 2, "operator": "map", "word": "words", "count": 1, "id": 759231116},
{"operator_number": 2, "operator": "map", "word": "which", "count": 1, "id": -112411180},
{"operator_number": 2, "operator": "map", "word": "the", "count": 2, "id": -1147111243},
{"operator_number": 2, "operator": "map", "word": "is", "count": 2, "id": 648427280},
{"operator_number": 2, "operator": "map", "word": "files.", "count": 1, "id": 1064683136},
{"operator_number": 2, "operator": "map", "word": "occur.", "count": 1, "id": -244884859},
{"operator_number": 2, "operator": "map", "word": "a", "count": 2, "id": 1867108634},
{"operator_number": 2, "operator": "map", "word": "contains", "count": 1, "id": -553938667},
{"operator_number": 2, "operator": "map", "word": "each", "count": 1, "id": 1547773355},
{"operator_number": 2, "operator": "map", "word": "breaks", "count": 1, "id": 1400666204},
{"operator_number": 2, "operator": "map", "word": "then", "count": 1, "id": 1571541968},
{"operator_number": 2, "operator": "map", "word": "takes", "count": 1, "id": -2142438010},
{"operator_number": 2, "operator": "map", "word": "sums", "count": 1, "id": -957763246},
{"operator_number": 2, "operator": "map", "word": "with", "count": 1, "id": -787307800},
{"operator_number": 2, "operator": "map", "word": "for", "count": 1, "id": 429617153},
{"operator_number": 2, "operator": "map", "word": "the", "count": 3, "id": -1147111243},
{"operator_number": 2, "operator": "map", "word": "Each", "count": 2, "id": -827945881},
{"operator_number": 2, "operator": "map", "word": "a", "count": 3, "id": 1867108634},
{"operator_number": 2, "operator": "map", "word": "words.", "count": 1, "id": 1130073758},
{"operator_number": 2, "operator": "map", "word": "single", "count": 1, "id": 667253393},
{"operator_number": 2, "operator": "map", "word": "combining", "count": 1, "id": -1048244161},
{"operator_number": 2, "operator": "map", "word": "amount", "count": 1, "id": -71540878},
{"operator_number": 2, "operator": "map", "word": "combiner", "count": 1, "id": 1602507455},
{"operator_number": 2, "operator": "map", "word": "optimization.", "count": 1, "id": 2044230185},
{"operator_number": 2, "operator": "map", "word": "the", "count": 4, "id": -1147111243},
{"operator_number": 2, "operator": "map", "word": "is", "count": 1, "id": 648427280},
{"operator_number": 2, "operator": "map", "word": "record.", "count": 1, "id": 458306687},
{"operator_number": 2, "operator": "map", "word": "on", "count": 1, "id": -2052619489},
{
"name": "reduceBykey",
"children": [
{"operator_number": 3, "operator": "reduceBykey", "word": "sent", "count": 1, "id": -1873763238},
{"operator_number": 3, "operator": "reduceBykey", "word": "example", "count": 1, "id": -1423699041},
{"operator_number": 3, "operator": "reduceBykey", "word": "The", "count": 1, "id": -1004784477},
{"operator_number": 3, "operator": "reduceBykey", "word": "WordCount", "count": 1, "id": -1806131025},
{"operator_number": 3, "operator": "reduceBykey", "word": "mapper", "count": 1, "id": 1207904727},
{"operator_number": 3, "operator": "reduceBykey", "word": "line", "count": 2, "id": 325590249},
{"operator_number": 3, "operator": "reduceBykey", "word": "across", "count": 1, "id": -762857328},
{"operator_number": 3, "operator": "reduceBykey", "word": "As", "count": 1, "id": 1898778492},
{"operator_number": 3, "operator": "reduceBykey", "word": "outputs.", "count": 1, "id": 1544351802},
{"operator_number": 3, "operator": "reduceBykey", "word": "1.", "count": 1, "id": 1677874983},
{"operator_number": 3, "operator": "reduceBykey", "word": "as", "count": 2, "id": -680231157},
{"operator_number": 3, "operator": "reduceBykey", "word": "map", "count": 1, "id": -683473284},
{"operator_number": 3, "operator": "reduceBykey", "word": "of", "count": 4, "id": 1018490952},
{"operator_number": 3, "operator": "reduceBykey", "word": "reduces", "count": 1, "id": -245012130},
{"operator_number": 3, "operator": "reduceBykey", "word": "also", "count": 1, "id": -1106031042},
{"operator_number": 3, "operator": "reduceBykey", "word": "It", "count": 1, "id": 1027745163},
{"operator_number": 3, "operator": "reduceBykey", "word": "count", "count": 1, "id": 220983708},
{"operator_number": 3, "operator": "reduceBykey", "word": "an", "count": 1, "id": 1302757461},
{"operator_number": 3, "operator": "reduceBykey", "word": "and", "count": 7, "id": 101213523},
{"operator_number": 3, "operator": "reduceBykey", "word": "occured.", "count": 1, "id": -1230160008},
{"operator_number": 3, "operator": "reduceBykey", "word": "it", "count": 2, "id": -147334043},
{"operator_number": 3, "operator": "reduceBykey", "word": "reducer", "count": 2, "id": -162177284},
{"operator_number": 3, "operator": "reduceBykey", "word": "counts", "count": 2, "id": -341063633},
{"operator_number": 3, "operator": "reduceBykey", "word": "text", "count": 3, "id": 1471308580},
{"operator_number": 3, "operator": "reduceBykey", "word": "pair", "count": 1, "id": -1791332846},
{"operator_number": 3, "operator": "reduceBykey", "word": "how", "count": 2, "id": -394402229},
{"operator_number": 3, "operator": "reduceBykey", "word": "reads", "count": 1, "id": 1581597220},
{"operator_number": 3, "operator": "reduceBykey", "word": "tab.", "count": 1, "id": 64393762},
{"operator_number": 3, "operator": "reduceBykey", "word": "into", "count": 2, "id": 660477844},
{"operator_number": 3, "operator": "reduceBykey", "word": "This", "count": 1, "id": -144610220},
{"operator_number": 3, "operator": "reduceBykey", "word": "key/value", "count": 2, "id": 40637392},
{"operator_number": 3, "operator": "reduceBykey", "word": "emits", "count": 2, "id": -512399732},
{"operator_number": 3, "operator": "reduceBykey", "word": "word", "count": 5, "id": -1996542359},
{"operator_number": 3, "operator": "reduceBykey", "word": "data", "count": 1, "id": -1989676802},
{"operator_number": 3, "operator": "reduceBykey", "word": "by", "count": 2, "id": 984685240},
{"operator_number": 3, "operator": "reduceBykey", "word": "used", "count": 1, "id": 1115971993},
{"operator_number": 3, "operator": "reduceBykey", "word": "separated", "count": 1, "id": -1355638496},
{"operator_number": 3, "operator": "reduceBykey", "word": "network", "count": 1, "id": 1134884044},
{"operator_number": 3, "operator": "reduceBykey", "word": "often", "count": 2, "id": -1659162332},
{"operator_number": 3, "operator": "reduceBykey", "word": "sum.", "count": 1, "id": 1546120510},
{"operator_number": 3, "operator": "reduceBykey", "word": "input", "count": 2, "id": 398743969},
{"operator_number": 3, "operator": "reduceBykey", "word": "words.", "count": 1, "id": 1130073758},
{"operator_number": 3, "operator": "reduceBykey", "word": "output", "count": 1, "id": 1728288230},
{"operator_number": 3, "operator": "reduceBykey", "word": "sums", "count": 1, "id": -957763246},
{"operator_number": 3, "operator": "reduceBykey", "word": "is", "count": 3, "id": 648427280},
{"operator_number": 3, "operator": "reduceBykey", "word": "contains", "count": 1, "id": -553938667},
{"operator_number": 3, "operator": "reduceBykey", "word": "combiner", "count": 1, "id": 1602507455},
{"operator_number": 3, "operator": "reduceBykey", "word": "files", "count": 2, "id": 1433752967},
{"operator_number": 3, "operator": "reduceBykey", "word": "record.", "count": 1, "id": 458306687},
{"operator_number": 3, "operator": "reduceBykey", "word": "takes", "count": 1, "id": -2142438010},
{"operator_number": 3, "operator": "reduceBykey", "word": "a", "count": 7, "id": 1867108634},
{"operator_number": 3, "operator": "reduceBykey", "word": "on", "count": 1, "id": -2052619489},
{"operator_number": 3, "operator": "reduceBykey", "word": "each", "count": 3, "id": 1547773355},
{"operator_number": 3, "operator": "reduceBykey", "word": "with", "count": 1, "id": -787307800},
{"operator_number": 3, "operator": "reduceBykey", "word": "then", "count": 1, "id": 1571541968},
{"operator_number": 3, "operator": "reduceBykey", "word": "which", "count": 1, "id": -112411180},
{"operator_number": 3, "operator": "reduceBykey", "word": "files.", "count": 1, "id": 1064683136},
{"operator_number": 3, "operator": "reduceBykey", "word": "breaks", "count": 1, "id": 1400666204},
{"operator_number": 3, "operator": "reduceBykey", "word": "combining", "count": 1, "id": -1048244161},
{"operator_number": 3, "operator": "reduceBykey", "word": "for", "count": 1, "id": 429617153},
{"operator_number": 3, "operator": "reduceBykey", "word": "words", "count": 1, "id": 759231116},
{"operator_number": 3, "operator": "reduceBykey", "word": "Each", "count": 2, "id": -827945881},
{"operator_number": 3, "operator": "reduceBykey", "word": "occur.", "count": 1, "id": -244884859},
{"operator_number": 3, "operator": "reduceBykey", "word": "amount", "count": 1, "id": -71540878},
{"operator_number": 3, "operator": "reduceBykey", "word": "optimization.", "count": 1, "id": 2044230185},
{"operator_number": 3, "operator": "reduceBykey", "word": "single", "count": 2, "id": 667253393},
{"operator_number": 3, "operator": "reduceBykey", "word": "the", "count": 9, "id": -1147111243}
]
}
]
}
]
}
<!DOCTYPE html>
<meta charset="UTF-8">
<!-- Custom styling -->
<link rel="stylesheet" href="less/style.css">
<body>
<!-- load the d3.js library -->
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="js/d3-tip.js"></script>
<script>
//var treeData = d3.json("data/data.json");
// Set the dimensions and margins of the diagram
var margin = {top: 20, right: 90, bottom: 30, left: 90},
width = 960 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var colorScale = d3.scaleLinear()
.domain([0, 1])
.range(['red', 'green']);
var widthScale = d3.scaleLinear()
.domain([1,80])
.range([1, 10]);
// append the svg object to the body of the page
// appends a 'group' element to 'svg'
// moves the 'group' element to the top left margin
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 i = 0,
duration = 750,
root;
// show information about data by mouseover
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
var content;
if(d.data.hasOwnProperty("name")){
//console.log("hier 0");
content = "<strong>Operator Number:</strong> <span>" + d.data.name + "</span>";
}
if(d.data.hasOwnProperty("children")){
//console.log("hier 5" + d.data.children.length);
var count_children = d.data.children.length
content += "<br /><strong>Number of Data:</strong> <span>" + count_children + "</span>";
} else{
if(d.data.hasOwnProperty("operator_number")){
//console.log("hier 1"+ d.data.operator_number);
content += "<strong>Operator Number:</strong> <span>" + d.data.operator_number + "</span>";
}
if(d.data.hasOwnProperty("operator")){
//console.log("hier 2"+ d.data.operator);
content += "<br /><strong>Operator Name:</strong> <span>" + d.data.operator + "</span>";
}
if(d.data.hasOwnProperty("word")){
//console.log("hier 3"+ d.data.word);
content += "<br /><strong>Word:</strong> <span>" + d.data.word + "</span>";
}
if(d.data.hasOwnProperty("id")){
//console.log("hier 4", d.data.id);
content+= "<strong>ID:</strong> <span>" + d.data.id + "</span>";
}
}
if (content.length >0 ){
return content;
}else{
return -1;
}
})
svg.call(tip);
// declares a tree layout and assigns the size
var treemap = d3.tree().size([height, width]);
d3.json("data/data-without-brackes.json",function(error, treeData){
// Assigns parent, children, height, depth
console.log("correct");
root= d3.hierarchy(treeData, function(d) {
return d.children;
});
console.log("root", root.children[1]);
root.x0 = height / 4;
root.y0 = 0;
// Collapse after the second level
root.children.forEach(collapse);
update(root);
// Collapse the node and all it's children
function collapse(d) {
if(d.children) {
d._children = d.children
d._children.forEach(collapse)
d.children = null
}
}
function update(source) {
// Assigns the x and y position for the nodes
var treeData = treemap(root);
console.log("line 113- treeData" , treeData);
// Compute the new tree layout.
var nodes = treeData.descendants(),
links = treeData.descendants().slice(1);
// Normalize for fixed-depth.
nodes.forEach(function(d){
// sort nodes, just the operator_nodes
if(d.hasOwnProperty("children")){
operator_nodes.push(d);
}else{
data_nodes.push(d);
}
});
nodes.forEach(function(d){
if(d.hasOwnProperty("children")){
d.y = d.depth * 180;
d.x = 275;
}else{
d.y= (d.depth * 90) + (90 * (d.depth -1));
d.x = 275;
}
});
//nodes.forEach(function(d){ d.y = 180});
// ****************** Nodes section ***************************
// Update the nodes
var node = svg.selectAll('g.node')
.data(nodes, function(d) { return d.id || (d.id = ++i); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
// Enter any new modes at the parent's previous position.
var nodeEnter = node.enter().append('g')
.attr("transform", function(d) {
return "translate(" + source.y0 + "," + source.x0 + ")";
})
.attr("class", function(d, i ){
return "node_" + i // i provides a unique id
+ " node"
+ " cell-level-" + d.depth
+ (!d.children
? " leaf"
:(d.depth === 0
? " root"
: " internal"));
})
.attr("id", function(d){
if(d.children){
return "operator";
}else{
return "data";
}
})
.attr("display", function(d){
if(d.hasOwnProperty("children")){
return "block";
}else{
return "block";
}
})
.on('click', click);
// Add Circle for the nodes
var symbolGeneratorDiamond = d3.symbol()
.type(d3.symbolDiamond)
.size(180);
var pathDataDiamond = symbolGeneratorDiamond();
var symbolGeneratorCircle = d3.symbol()
.type(d3.symbolCircle)
.size(180);
var pathDataCircle = symbolGeneratorCircle();
// Give shape, if has children then diamond, else circle (is data)
nodeEnter.append("path")
.style("stroke", "black")
.style("fill", "white")
.attr("d", function(d) {
if(d.hasOwnProperty("children")){
return pathDataDiamond;
}else{
return pathDataCircle;
}
})
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
})
// Add labels for the nodes
nodeEnter.append('text')
.attr("dy", ".35em")
.attr("x", function(d) {
return d.children || d._children ? -13 : 13;
})
.attr("text-anchor", function(d) {
return d.children || d._children ? "end" : "start";
})
.text(function(d) { if(d.data.name )return d.data.name;
else{
return d.data.word;
} })
.attr("display", function(d){
if(d.data.children){
return "block";
}else{
return "none";
}
});
// UPDATE
var nodeUpdate = nodeEnter.merge(node);
// Transition to the proper position for the node
nodeUpdate.transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + d.y + "," + d.x + ")";
});
// Update the node attributes and style
nodeUpdate.select('path')
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
})
.attr('cursor', 'pointer');
// Remove any exiting nodes
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + source.y + "," + source.x + ")";
})
.remove();
// On exit reduce the node circles size to 0
nodeExit.select('path')
.attr('r', 1e-6);
// On exit reduce the opacity of text labels
nodeExit.select('text')
.style('fill-opacity', 1e-6);
// ****************** links section ***************************
// Update the links...
var link = svg.selectAll('path.link')
.data(links, function(d) { return d.id; })
.style('stroke-width', function(d){
return widthScale(d.data.value)
});
// 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}
return diagonal(o, o)
})
.attr("display", function(d){
if(d.hasOwnProperty("children")){
return "block";
}else{
return "block";
}
})
.style('stroke-width', function(d){
return widthScale(d.data.value)
});
// UPDATE
var linkUpdate = linkEnter.merge(link);
// Transition back to the parent element position
linkUpdate.transition()
.duration(duration)
.attr('d', function(d){ return diagonal(d, d.parent) });
// Remove any exiting links
var linkExit = link.exit().transition()
.duration(duration)
.attr('d', function(d) {
var o = {x: source.x, y: source.y}
return diagonal(o, o)
})
.style('stroke-width', function(d){
return widthScale(d.data.value)
})
.remove();
// Store the old positions for transition.
nodes.forEach(function(d){
d.x0 = d.x;
d.y0 = d.y;
});
// 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
}
// 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);
}
}
})
</script>
</body>
解决方案
推荐阅读
- python - 函数只需要 4 个参数(给定 2 个)
- ms-word - 获取 Microsoft Word 中所有打开文档的文件名
- html - 如何在css中缩小图像
- node.js - 从后端获取计数器的当前值:REST API
- docker - 以分离模式从 docker 内接收键盘输入
- java - 如何在 Java 中使用 glob 来匹配目录和子目录中的文件?
- linkedin - LinkedIn Ads API - 由于语言环境而无法更改定位
- security - 使用 logstash 安全地接收日志消息
- laravel - 在 Laravel Breeze 中自定义登录
- django - 如何显示外键项的列表?