Javascript 在d3.js树状图布局中,如何使最后一个子项可单击并填充整个树状图布局
Im使用d3.js树形图布局。在树状图中,单击具有“子”属性的父段时,它将转换为其各自的子段。但是,单击最后一个没有任何子属性的子节点时,它不会使转换恰好填充整个布局中的该子节点。在我正在编写的代码中,我可以在单击最后一个孩子时重定向到一个新窗口,但不确定如何进行转换 在链接中找到我的代码Javascript 在d3.js树状图布局中,如何使最后一个子项可单击并填充整个树状图布局,javascript,reactjs,d3.js,Javascript,Reactjs,D3.js,Im使用d3.js树形图布局。在树状图中,单击具有“子”属性的父段时,它将转换为其各自的子段。但是,单击最后一个没有任何子属性的子节点时,它不会使转换恰好填充整个布局中的该子节点。在我正在编写的代码中,我可以在单击最后一个孩子时重定向到一个新窗口,但不确定如何进行转换 在链接中找到我的代码 类TreemapChart扩展了React.Component{ componentDidMount(){ const self=这个; var margin={top:20,right:0,bottom:0
类TreemapChart扩展了React.Component{
componentDidMount(){
const self=这个;
var margin={top:20,right:0,bottom:0,left:0},
宽度=960,
高度=500-页边距.顶部-页边距.底部,
过渡;
var x=d3.0刻度
.linear()
.domain([0,宽度])
.范围([0,宽度]);
变量y=d3.0标度
.linear()
.domain([0,高度])
.范围([0,高度]);
var treemap=d3.layout
.treemap()
.儿童(功能(d,深度){
返回深度?空:d.\u子项;
})
.排序(功能(a、b){
返回a.value-b.value;
})
.比率((高度/宽度)*0.5*(1+数学sqrt(5)))
.圆形(假);
var svg=d3
.选择(“图表”)
.append(“svg”)
.attr(“宽度”,宽度+边距。左侧+边距。右侧)
.attr(“高度”,高度+边距。底部+边距。顶部)
.style(“左边距”、-margin.left+“px”)
.style(“margin.right”、-margin.right+“px”)
.附加(“g”)
.attr(“转换”、“平移”(“+margin.left+”,“+margin.top+”)
.风格(“形状渲染”、“边缘”);
//.on(“mousemove”,函数(d){
//工具样式(“左”,d3.event.pageX+10+“px”)
//工具样式(“顶部”,d3.event.pageY-20+“px”)
//工具样式(“显示”、“内联块”);
//html(d.children?null:d.name+“
”;
//}).on(“mouseout”,函数(d){
//工具样式(“显示”、“无”);
// });
var祖父母=svg.append(“g”).attr(“类”、“祖父母”);
祖父母
.append(“rect”)
.attr(“y”,-margin.top)
.attr(“宽度”,宽度)
.attr(“高度”,边距,顶部);
祖父母
.append(“文本”)
.attr(“x”,6)
.attr(“y”,6-页边距。顶部)
.attr(“dy”,“.35em”);
函数数据映射(根){
初始化(根);
积累(根);
累加计数(根);
布局(根);
显示(根);
函数初始化(根){
root.x=root.y=0;
root.dx=宽度;
root.dy=高度;
根深度=0;
}
//聚合内部节点的值。这通常由
//树映射布局,但由于我们的自定义实现,这里没有。
//我们还拍摄了原始子对象(_children)的快照,以避免
//计算布局时覆盖的子级。
函数累加(d){
返回(d.(子项=d.子项)
?(d.value=d.children.reduce(函数p,v){
返回p+累计(v);
}, 0))
:d.价值;
}
函数累加器计数(d){
返回(d.(子项=d.子项)
?(d.count=d.children.reduce(函数p,v){
返回p+累计计数(v);
}, 0))
:d.计数;
}
功能布局(d){
如果(d.(儿童){
树映射节点({u子节点:d.{u子节点});
d、 _children.forEach(函数(c){
c、 x=d.x+c.x*d.dx;
c、 y=d.y+c.y*d.dy;
c、 dx*=d.dx;
c、 dy*=d.dy;
c、 父代=d;
布局图(c);
});
}
}
功能显示(d){
//控制台日志(d);
祖父母
.基准面(d.母面)
。打开(“单击”,转换)
.选择(“文本”)
.文本(名称(d));
变量g1=svg
.插入(“g”,“祖父母”)
.基准(d)
.attr(“类别”、“深度”);
变量g=g1
.全选(“g”)
.数据(d._儿童)
.输入()
.附加(“g”);
g、 过滤器(功能(d){
返回d.U儿童;
})
.分类(“儿童”,真实)
。打开(“点击”,转换);
g、 全选(“.child”)
.数据(功能(d){
返回d.| | |[d];
})
.输入()
.append(“rect”)
.attr(“类”、“子类”)
.呼叫(rect);
g、 附加(“rect”)
.attr(“类”、“父类”)
.call(rect)
.打开(“单击”,功能(d){
如果(!d._儿童){
打开(d.url);
}
})
.附加(“标题”)
.文本(功能(d){
返回`${d.name}(${d.count})`;
});
g、 附加(“文本”)
.attr(“dx”、“1rem”)
.attr(“dy”、“2rem”)
.文本(功能(d){
返回`${d.name}`;
})
.电话(文本);
功能转换(d){
self.props.onClickSegment(d.metricsValue);
如果(转换| |!d)返回;
转换=真;
var g2=显示器(d),
t1=g1.transition().持续时间(750),
t2=g2.transition().持续时间(750);
//仅在输入新元素后更新域。
x、 域([d.x,d.x+d.dx]);
y、 域([d.y,d.y+d.dy]);
//在转换期间启用抗锯齿。
style(“形状渲染”,null);
//在父节点的顶部绘制子节点。
svg.selectAll(“.depth”).sort(函数(a、b){
返回a.depth-b.depth;
});
//在输入文本时淡入淡出。
g2.选择全部(“文本”)。样式(“填充不透明度”,0);
//转换到新视图。
t1.选择全部(“文本”)
.通话(文本)
.style(“fil
class TreemapChart extends React.Component {
componentDidMount() {
const self = this;
var margin = { top: 20, right: 0, bottom: 0, left: 0 },
width = 960,
height = 500 - margin.top - margin.bottom,
transitioning;
var x = d3.scale
.linear()
.domain([0, width])
.range([0, width]);
var y = d3.scale
.linear()
.domain([0, height])
.range([0, height]);
var treemap = d3.layout
.treemap()
.children(function(d, depth) {
return depth ? null : d._children;
})
.sort(function(a, b) {
return a.value - b.value;
})
.ratio((height / width) * 0.5 * (1 + Math.sqrt(5)))
.round(false);
var svg = d3
.select("#chart")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.bottom + margin.top)
.style("margin-left", -margin.left + "px")
.style("margin.right", -margin.right + "px")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.style("shape-rendering", "crispEdges");
// .on("mousemove", function (d) {
// tool.style("left", d3.event.pageX + 10 + "px")
// tool.style("top", d3.event.pageY - 20 + "px")
// tool.style("display", "inline-block");
// tool.html(d.children ? null : d.name + "<br>" );
// }).on("mouseout", function (d) {
// tool.style("display", "none");
// });
var grandparent = svg.append("g").attr("class", "grandparent");
grandparent
.append("rect")
.attr("y", -margin.top)
.attr("width", width)
.attr("height", margin.top);
grandparent
.append("text")
.attr("x", 6)
.attr("y", 6 - margin.top)
.attr("dy", ".35em");
function dataMap(root) {
initialize(root);
accumulate(root);
accumulateCount(root);
layout(root);
display(root);
function initialize(root) {
root.x = root.y = 0;
root.dx = width;
root.dy = height;
root.depth = 0;
}
// Aggregate the values for internal nodes. This is normally done by the
// treemap layout, but not here because of our custom implementation.
// We also take a snapshot of the original children (_children) to avoid
// the children being overwritten when when layout is computed.
function accumulate(d) {
return (d._children = d.children)
? (d.value = d.children.reduce(function(p, v) {
return p + accumulate(v);
}, 0))
: d.value;
}
function accumulateCount(d) {
return (d._children = d.children)
? (d.count = d.children.reduce(function(p, v) {
return p + accumulateCount(v);
}, 0))
: d.count;
}
function layout(d) {
if (d._children) {
treemap.nodes({ _children: d._children });
d._children.forEach(function(c) {
c.x = d.x + c.x * d.dx;
c.y = d.y + c.y * d.dy;
c.dx *= d.dx;
c.dy *= d.dy;
c.parent = d;
layout(c);
});
}
}
function display(d) {
// console.log(d);
grandparent
.datum(d.parent)
.on("click", transition)
.select("text")
.text(name(d));
var g1 = svg
.insert("g", ".grandparent")
.datum(d)
.attr("class", "depth");
var g = g1
.selectAll("g")
.data(d._children)
.enter()
.append("g");
g.filter(function(d) {
return d._children;
})
.classed("children", true)
.on("click", transition);
g.selectAll(".child")
.data(function(d) {
return d._children || [d];
})
.enter()
.append("rect")
.attr("class", "child")
.call(rect);
g.append("rect")
.attr("class", "parent")
.call(rect)
.on("click", function(d) {
if (!d._children) {
window.open(d.url);
}
})
.append("title")
.text(function(d) {
return `${d.name} (${d.count})`;
});
g.append("text")
.attr("dx", "1rem")
.attr("dy", "2rem")
.text(function(d) {
return `${d.name}`;
})
.call(text);
function transition(d) {
self.props.onClickSegment(d.metricsValue);
if (transitioning || !d) return;
transitioning = true;
var g2 = display(d),
t1 = g1.transition().duration(750),
t2 = g2.transition().duration(750);
// Update the domain only after entering new elements.
x.domain([d.x, d.x + d.dx]);
y.domain([d.y, d.y + d.dy]);
// Enable anti-aliasing during the transition.
svg.style("shape-rendering", null);
// Draw child nodes on top of parent nodes.
svg.selectAll(".depth").sort(function(a, b) {
return a.depth - b.depth;
});
// Fade-in entering text.
g2.selectAll("text").style("fill-opacity", 0);
// Transition to the new view.
t1.selectAll("text")
.call(text)
.style("fill-opacity", 0);
t2.selectAll("text")
.call(text)
.style("fill-opacity", 1);
t1.selectAll("rect").call(rect);
t2.selectAll("rect").call(rect);
// Remove the old node when the transition is finished.
t1.remove().each("end", function() {
svg.style("shape-rendering", "crispEdges");
transitioning = false;
});
}
return g;
}
function text(text) {
text
.attr("x", function(d) {
return x(d.x) + 6;
})
.attr("y", function(d) {
return y(d.y) + 6;
});
}
function rect(rect) {
rect
.attr("x", function(d) {
return x(d.x);
})
.attr("y", function(d) {
return y(d.y);
})
.attr("width", function(d) {
return x(d.x + d.dx) - x(d.x);
})
.attr("height", function(d) {
return y(d.y + d.dy) - y(d.y);
});
}
function name(d) {
return d.parent ? name(d.parent) + " / " + d.name : d.name;
}
}
dataMap(dataObj);
}
handleClick = d => {
// this.props.onClickSegment(d.metricsValue);
console.log("The text", d.metricsValue);
};
render() {
return <p id="chart" />;
}
}