D3.js-添加新节点并进行迁移后,旧链接不会被删除 [英] D3.js - old links not getting deleted after adding a new node and trasitioning
问题描述
我正在努力使Treeview与某些条件逻辑一起使用。我目前有以下工作提琴:
添加子节点后:-
如您所见,有一些悬挂的链接/节点,它们并没有被删除。
var margin = {
顶部:20,
右侧:120,
底部:20,
左:120
},
宽度= 960-margin.right-margin.left,
高度= 800-margin.top-margin 。底部;
函数generateEmptyDecisionBox(condition){
return condition ==='False'吗? [{{
name: newDecision,
id: newId,
type: decision,
value: notSure,
condition:`$ {condition}`,
},{}]:[{},{
name: newDecision,
id: newId,
type:决定,
value: notSure,
condition:`$ {condition}`,
}];
}
var selectedNode;
var selectedLink;
var root = {
name: Root,
type: decision,
children:[{
名称:分析,
条件:假,
类型:决策,
值: a + b,
孩子:[{
名称:区别,
类型:动作,
条件:真实,
value: 5,
},{
name: nonDistinction,
type: action,
condition: false ,
value: 4,
children:[],
}],
},
{
condition: True,
名称:部门,
类型:决策,
值: ab,
孩子:{
name: analytics,
condition: False,
type: decision,
value: a + b,
孩子:[{
名称:区别,
类型:动作,
条件: T rue,
value: 5,
},{
name: nonDistinction,
type: decision,
condition: false,
value: 4,
children:{
name: analytics,
condition: False,
类型:决定,
值: a + b,
子项:[{
name: distincction ,
type: action,
condition: True,
value: 5,
},{
name : nonDistinction,
type: action,
condition: false,
value: 4
}],
},
}],
},
}
]
};
var i = 0,
持续时间= 500,
rectW = 120,
rectH = 60;
var tree = d3.layout.tree()。nodeSize([150,90]);
//链接功能为草稿链接
var linkFunc = function(d){
console.log( linkFunc,d);
var source = {
x:d.source.x + rectW / 2,
y:d.source.y +(rectH / 2)
};
var target = {
x:d.target.x +(rectW / 2),
y:d.target.y + 3,
};
//这是直线弯曲
的地方var inflection = {
x:target.x,
y:source.y
};
var radius = 5;
var结果= M + source.x +’,’+ source.y;
if(source.x< target.x&&& d.target.type){
//子项位于父项
结果的右侧+ = 'H'+(inflection.x-半径);
}否则,如果(d.target.type){
结果+ =‘H’+(inflection.x +半径);
}否则{返回
;
}
//在弯曲处稍微弯曲直线
结果+ ='Q'+ inflection.x +','+ inflection.y +''+弯曲。 x +','+(inflection.y +半径);
结果+ ='V'+ target.y;
的返回结果;
}
//链接功能结束//
var对角线= d3.svg.diagonal()
.projection( function(d){
return [dx + rectW / 2,dy + rectH / 2];
});
//绘制树//
var svg = d3.select(。tree-diagram)。append( svg)。attr( width,1000).attr ( height,1000)
.call(zm = d3.behavior.zoom()。scaleExtent([1,3])。on( zoom,redraw))。append( g)
.attr( transform, translate( + 350 +, + 20 +));
//将箭头添加到下一个决策点。
svg.append( svg:defs)。selectAll( marker)
.data([ end])//可以在此处定义不同的链接/路径类型
.enter()。append( svg:marker)//此部分添加了箭头
.attr( id,字符串)
.attr( viewBox, 0 -5 10 10)
.attr( refX,15)
.attr( refY,0.5)
.attr( markerWidth,4)
。 attr( markerHeight,4)
.attr( orient, auto)
.append( svg:path)
.attr( d, M0, -5L10,0L0,5);
//必要,以便zoom知道从
进行缩放的位置zm.translate([350,20]);
root.x0 = 0;
root.y0 = 0;
更新(根);
d3.select(。tree-diagram)。style( height, 1000px);
//绘制树的结尾//
函数update(source){
//计算新的树布局。
var个节点= tree.nodes(root).reverse(),
个link = tree.links(nodes);
//归一化为固定深度。
个node.forEach(function(d){
d.y = d.depth * 90;
});
//更新节点…
var node = svg.selectAll( g.node)
.data(nodes,function(d){
return d.id ||(d.id = ++ i);
});
//在父级的先前位置输入任何新节点。
var nodeEnter = node.enter()。append( g)
.attr('transform','translate('+ source.x0 +','+ source.y0 +')' )
.attr( class, node)
.on( click,click)
// .on( blur,onNodeBlur);
nodeEnter.append('path')
.attr( d,function(d){
if(d.type ==='decision'){
返回'M 60 0 120 30 60 60 0 30 Z';
}否则if(d.type ==='action'){
返回'M 0 0 120 0 120 60 0 60 Z';
}否则{
返回'M -100 -10 -10 -10 -10 -10 -10 -10Z'
}
})。attr( stroke-width,1)
.attr('class','myPaths')
.style( fill,function(d){
return lightsteelblue;
});
nodeEnter.append( text)
.attr( x,rectW / 2)
.attr( y,rectH / 2)
.attr( dy, .35em)
.attr( text-anchor, middle)
.text(function(d){
return d.name;
});
var nodeUpdate = node.transition()
.duration(duration)
.attr( transform,function(d){
return translate( +(dx)+, +(dy)+);
});
var nodeExit = node.exit()。transition()
.duration(duration)
.attr( transform,function(d){
return translate( + source.x +, + source.y +);
})
.remove();
nodeExit.select( path)
.attr( d,function(d){
if(d.type ==='decision'){
返回'M 60 0 120 30 60 60 0 30 Z';
}否则if(d.type ==='action'){
返回'M 0 0 120 0 120 60 0 60 Z';
}否则{
返回'M -100 -10 -10 -10 -10 -10 -10 -10Z'
}
})。attr( stroke-width,1)
.attr('class','myPaths')
.style( fill,function(d){
return lightsteelblue;
});
nodeExit.select( text);
//更新链接…
var link = svg.selectAll( path.link)
.data(links,function(d){
返回d.target.id;
})。classed('link1',true);
//在父母的上一个位置输入任何新链接。
var linkEnter = link.enter()。insert( g, g)
.attr( class, link);
linkEnter.append('path')
.attr( d,linkFunc)
.on('click',function(d,i) {
selectedLink = d;
//使用本地SVG接口将边界框移至
// //计算路径的中心
var bbox = this.getBBox();
var x;
var y;
if(d.source.x< d.target.x){
//子级位于父级的右侧
x = bbox.x + bbox.width;
y = bbox.y;
plusButton
.attr('transform',' translate('+ x +','+ y +')')
.classed('hide',false);
} else {
x = bbox.x;
y = bbox.y;
plusButton
.attr('transform','translate('+ x +','+ y +')')
.classed(' hide',false);
}
})
.on('blur',function(d,i){
plusButton
.classed('hide' ,true);
})。attr( marker- end, url(#end));
//添加链接文本。
linkEnter.append('text')
.text(function(d,i){
if(d.source.x< d.target .x){
返回'True';
} else {
返回'False';
}
})。attr('transform',function(d ){
console.log(d);
/ * var bbox = this.getBBox();
x = bbox.x + bbox.width;
y = bbox.y; * /
if(d.source.x< d.target.x&& d.target.type){
console.log(在此处输入源<目标) ;
返回'translate('+(d.source.x + rectW)+','+(d.source.y + rectH)+')';
}否则if(d.target .type){
return'translate('+(d.source.x-rectW / 2)+','+(d.source.y + rectH)+')';
} else {
return;
}
});
//过渡到其新职位的链接。
link.transition()
.duration(duration)
.attr( d,linkFunc);
//过渡到其新职位的链接。
//将退出节点过渡到父级的新位置。
link.exit()。transition()
.duration(duration)
.attr( d,linkFunc)
.remove();
//存放旧的过渡职位。
个node.forEach(function(d){
d.x0 = d.x;
d.y0 = d.y;
});
}
//点选
函数click(d){
if(d.type ==='动作'){返回
;
}
selectedNode = d;
var m = d.x;
var h = d.y;
var m = d.x + 110;
var h = d.y + 35;
diamondImage
.attr('transform','translate('+ m +','+ h +')')
.classed('hide',false) ;
var m = d.x + 110;
var h = d.y;
矩形Shape
.attr('transform','translate('+ m +','+ h +')')
.classed('hide',false) ;
var m = d.x-20;
var h = d.y + 35;
diamondImageFalse
.attr('transform','translate('+ m +','+ h +')')
.classed('hide',false) ;
var m = d.x-20;
var h = d.y;
angleShapeFalse
.attr('transform','translate('+ m +','+ h +')')
.classed('hide',false) ;
}
/ *函数onNodeBlur(){
diamondImage
.classed('hide',true);
rectangleShape
.classed('hide',true);
diamondImageFalse
.classed('hide',true);
angleShapeFalse
.classed('hide',true);
}
* /
//重绘缩放
函数redraw(){
//console.log(\"here,d3.event.translate,d3 .event.scale);
svg.attr( transform,
translate( + d3.event.translate +) +
scale( + d3.event.scale +)) ;
}
// o通话
函数addElement(d,真){
console.log(d );
d.children =空;
d.children = generateEmptyDecisionBox(truthy);
update(root);
}
//绘制元素//
函数drawDiamond(centroid){
//从顶部
console.log开始(形心);
console.log( rectH,rectH,rectW)
//从顶部
开始var result ='M'+ centroid.x +','+(centroid.y- rectH / 2);
//向右移动
结果+ =‘L’+(centroid.x + rectW / 2)+’,’+ centroid.y;
//底部
结果+ =‘L’+ centroid.x +’,’+(centroid.y + rectH / 2);
//左
结果+ =‘L’+(centroid.x-rectW / 2)+’,’+ centroid.y;
//关闭形状
结果+ ='Z';
返回结果;
}
function drawRect(centroid){
//从左上方开始
console.log(centroid);
var result ='M'+(centroid.x-rectW / 2)+’,’+(centroid.y-rectH / 2);
//向右移
结果+ =‘h’+ rectW;
//向下
结果+ =‘v’+ rectH;
//左
结果+ =‘h-’+ rectW;
//关闭形状
结果+ ='Z';
console.log(结果);
的返回结果;
}
var plusButton = svg
.append('g')
.classed('button',true)
.classed('hide ',true)
.on('click',function(){
console.log( hello);
/ * addElement(selectedLink.source); * /
console.log(点击钻石);
console.log(将隐藏设置为true);
removeAllButtonElements();
});
plusButton
.append('rect')
.attr('transform','translate(-8,-8)')//将按钮居中于` g`
.attr('width',16)
.attr('height',16)
.attr('rx',2);
plusButton
.append('path')
.attr('d','M-6 0 H6 M0 -6 V6');
varangleShape = svg.append('g')
.classed('conditionImage',true)
.classed('hide',true)
。 on('click',function(){
removeAllButtonElements();
})
矩形形状
.append('rect')
.attr ('width',30)
.attr('height',20)
.style('fill','orange');
var diamondImage = svg.append('g')
.classed('conditionSvg',true)
.classed('hide',true)
.classed('scale',true)
.on('click',function(){
console.log(点击钻石);
console.log( 将隐藏设置为true);
addElement(selectedNode,'True');
removeAllButtonElements();
});
diamondImage
.append('path')
.attr('d','M 15 0 30 15 15 30 0 15 Z')
.style (填充,橙色);
varangleShapeFalse = svg.append('g')
.classed('conditionImage',true)
.classed('hide',true)
.on('click',function(){
console.log( rectangle clicked);
removeAllButtonElements();
})
radiusShapeFalse
.append('rect')
.attr('width',30)
.attr('height',20)
.style('fill','橙子');
var diamondImageFalse = svg.append('g')
.classed('conditionImage',true)
.classed('hide',true)
。 classed('scale',true)
.on('click',function(){
console.log(点击钻石);
console.log(设置为true);
addElement(selectedNode,'False');
removeAllButtonElements();
});
diamondImageFalse
.append('path')
.attr('d','M 15 0 30 15 15 30 0 15 Z')
.style (填充,橙色);
函数removeAllButtonElements(){
plusButton.classed('hide',true);
diamondImage.classed('hide',true);
angleShape.classed('hide',true);
diamondImageFalse.classed('hide',true);
angleShapeFalse.classed('hide',true);
}
//绘制元素结束..
.node {
光标:指针;
大纲:无!重要;
}
.node文本{
字体:10px sans-serif;
}
.button> path {
stroke:blue;
笔划宽度:1.5;
/ *大纲:无; * /
}
.button> rect {
fill:#ddd;
中风:灰色;
笔划宽度:1px;
}
.conditionalSvg {
轮廓:无;
显示:无;
}
.hide {
display:none;
opacity:0!important;
指针事件:无;
}
.link:hover {
ouline:none!important;
cursor:指针;
笔划宽度:3px;
}
.link path {
outline:none!important;
fill:无;
中风:深灰色;
stroke-width:2px;
}
.link path:hover {
cursor:指针;
stroke-width:4px;
}
.link text {
font:10px sans-serif;
}
.colorBlue {
background-color:blue;
}
< script src = https ://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js< / script>
< div class = tree-diagram>< / div>
尽管正在添加新节点,而旧节点正在过渡到最新位置,但旧节点/链接不会被删除。
请注意,您的节点运行良好,只是链接运行不正常。这是因为您使用 path.link
找到了它们,但是实际结构是 g.link path
添加具有类 link
的 g
元素,然后添加 path
。您可以通过将 path.link
更改为 g.link
来解决此问题,但随后需要选择路径
和文本
。
我通过调用来解决此问题。 .attr('d',linkFunc)
在所有所有链接上,而不仅仅是新链接,并调用 .text()
和 .attr('transform'
在所有文本上。
最后,我将文本转换更改为使用 x
目标,因为目标确定线的垂直位置,而不是源。
var margin = {
顶部:20,
右:120,
底部:20,
左:120
},
宽度= 960-margin.right-margin.left,
高度= 800-margin.top-margin.bottom;
函数generateEmptyDecisionBox(condition){
返回条件ition === False? [{{
name: newDecision,
id: newId,
type: decision,
value: notSure,
condition:`$ {condition}`,
},{}]:[{},{
name: newDecision,
id: newId,
type:决定,
value: notSure,
condition:`$ {condition}`,
}];
}
var selectedNode;
var selectedLink;
var root = {
name: Root,
type: decision,
children:[{
名称:分析,
条件:假,
类型:决策,
值: a + b,
孩子:[{
名称:区别,
类型:动作,
条件:真实,
value: 5,
},{
name: nonDistinction,
type: action,
condition: false ,
value: 4,
children:[],
}],
},
{
condition: True,
名称:部门,
类型:决策,
值: ab,
孩子:{
name: analytics,
condition: False,
type: decision,
value: a + b,
孩子:[{
名称:区别,
类型:动作,
条件: T rue,
value: 5,
},{
name: nonDistinction,
type: decision,
condition: false,
value: 4,
children:{
name: analytics,
condition: False,
类型:决定,
值: a + b,
子项:[{
name: distincction ,
type: action,
condition: True,
value: 5,
},{
name : nonDistinction,
type: action,
condition: false,
value: 4
}],
},
}],
},
}
]
};
var i = 0,
持续时间= 500,
rectW = 120,
rectH = 60;
var tree = d3.layout.tree()。nodeSize([150,90]);
//链接功能为草稿链接
var linkFunc = function(d){
console.log( linkFunc,d);
var source = {
x:d.source.x + rectW / 2,
y:d.source.y +(rectH / 2)
};
var target = {
x:d.target.x +(rectW / 2),
y:d.target.y + 3,
};
//这是直线弯曲
的地方var inflection = {
x:target.x,
y:source.y
};
var radius = 5;
var结果= M + source.x +’,’+ source.y;
if(source.x< target.x&&& d.target.type){
//子项位于父项
结果的右侧+ = 'H'+(inflection.x-半径);
}否则,如果(d.target.type){
结果+ =‘H’+(inflection.x +半径);
}否则{返回
;
}
//在弯曲处稍微弯曲直线
结果+ ='Q'+ inflection.x +','+ inflection.y +''+弯曲。 x +','+(inflection.y +半径);
结果+ ='V'+ target.y;
的返回结果;
}
//链接功能结束//
var对角线= d3.svg.diagonal()
.projection( function(d){
return [dx + rectW / 2,dy + rectH / 2];
});
//绘制树//
var svg = d3.select(。tree-diagram)。append( svg)。attr( width,1000).attr ( height,1000)
.call(zm = d3.behavior.zoom()。scaleExtent([1,3])。on( zoom,redraw))。append( g)
.attr( transform, translate( + 350 +, + 20 +));
//将箭头添加到下一个决策点。
svg.append( svg:defs)。selectAll( marker)
.data([ end])//可以在此处定义不同的链接/路径类型
.enter()。append( svg:marker)//此部分添加了箭头
.attr( id,字符串)
.attr( viewBox, 0 -5 10 10)
.attr( refX,15)
.attr( refY,0.5)
.attr( markerWidth,4)
。 attr( markerHeight,4)
.attr( orient, auto)
.append( svg:path)
.attr( d, M0, -5L10,0L0,5);
//必要,以便zoom知道从
进行缩放的位置zm.translate([350,20]);
root.x0 = 0;
root.y0 = 0;
更新(根);
d3.select(。tree-diagram)。style( height, 1000px);
//绘制树的结尾//
函数update(source){
//计算新的树布局。
var个节点= tree.nodes(root).reverse(),
个link = tree.links(nodes);
//归一化为固定深度。
个node.forEach(function(d){
d.y = d.depth * 90;
});
//更新节点…
var node = svg.selectAll( g.node)
.data(nodes,function(d){
return d.id ||(d.id = ++ i);
});
//在父级的先前位置输入任何新节点。
var nodeEnter = node.enter()。append( g)
.attr('transform','translate('+ source.x0 +','+ source.y0 +')' )
.attr( class, node)
.on( click,click)
// .on( blur,onNodeBlur);
nodeEnter.append('path')
.attr( d,function(d){
if(d.type ==='decision'){
返回'M 60 0 120 30 60 60 0 30 Z';
}否则if(d.type ==='action'){
返回'M 0 0 120 0 120 60 0 60 Z';
}否则{
返回'M -100 -10 -10 -10 -10 -10 -10 -10Z'
}
})。attr( stroke-width,1)
.attr('class','myPaths')
.style( fill,function(d){
return lightsteelblue;
});
nodeEnter.append( text)
.attr( x,rectW / 2)
.attr( y,rectH / 2)
.attr( dy, .35em)
.attr( text-anchor, middle)
.text(function(d){
return d.name;
});
var nodeUpdate = node.transition()
.duration(duration)
.attr( transform,function(d){
return translate( +(dx)+, +(dy)+);
});
var nodeExit = node.exit()。transition()
.duration(duration)
.attr( transform,function(d){
return translate( + source.x +, + source.y +);
})
.remove();
nodeExit.select( path)
.attr( d,function(d){
if(d.type ==='decision'){
返回'M 60 0 120 30 60 60 0 30 Z';
}否则if(d.type ==='action'){
返回'M 0 0 120 0 120 60 0 60 Z';
}否则{
返回'M -100 -10 -10 -10 -10 -10 -10 -10Z'
}
})。attr( stroke-width,1)
.attr('class','myPaths')
.style( fill,function(d){
return lightsteelblue;
});
nodeExit.select( text);
//更新链接…
var link = svg.selectAll(。link)
.data(links,function(d){
return d .target.id;
})。classed('link1',true);
//在父母的上一个位置输入任何新链接。
var linkEnter = link.enter()
.insert( g, g)
.attr( class, link);
linkEnter.append('path')
.on('click',function(d,i){
selectedLink = d;
//使用原生SVG接口,以将边界框移至
//计算路径的中心
var bbox = this.getBBox();
var x;
var y;
if(d.source.x< d.target.x){
//子级位于父级的右边
x = bbox .x + bbox.width;
y = bbox.y;
plusButton
.attr('transform','translate('+ x +','+ y +')')
.classed('hide',false);
} else {
x = bbox.x;
y = bbox.y;
plusButton
.attr('transform','translate('+ x +','+ y +')')
.classed('hide',false);
}
})
.on('blur',function(d,i){
plusButton
.classed('hide',true);
})。attr( marker-end , url(#end));
//添加链接文本。
linkEnter.append(‘text’);
link.select(’path')
.attr( d,linkFunc);
link.select('text')
.text(function(d,i){
if(d.source.x< d.target.x){
返回'True';
} else {
返回'False';
}
})
.attr('transform',function(d ){
console.log(d);
if(d.source.x< d.target.x&& d.target.type){
console.log( 出现在这里以获取源<目标);
返回'translate('+(d.target.x + rectW / 2)+','+(d.source.y + rectH)+') ';
}否则if(d.target.type){
返回'translate('+(d.target.x + rectW / 2)+','+(d.source.y + rectH)+')';
} else {
return;
}
});
//过渡到其新职位的链接。
link.transition()
.duration(duration)
.attr( d,linkFunc);
//过渡到其新职位的链接。
//将退出节点过渡到父级的新位置。
link.exit()。transition()
.duration(duration)
.attr( d,linkFunc)
.remove();
//存放旧的过渡职位。
个node.forEach(function(d){
d.x0 = d.x;
d.y0 = d.y;
});
}
//点选
函数click(d){
if(d.type ==='动作'){返回
;
}
selectedNode = d;
var m = d.x;
var h = d.y;
var m = d.x + 110;
var h = d.y + 35;
diamondImage
.attr('transform','translate('+ m +','+ h +')')
.classed('hide',false) ;
var m = d.x + 110;
var h = d.y;
矩形Shape
.attr('transform','translate('+ m +','+ h +')')
.classed('hide',false) ;
var m = d.x-20;
var h = d.y + 35;
diamondImageFalse
.attr('transform','translate('+ m +','+ h +')')
.classed('hide',false) ;
var m = d.x-20;
var h = d.y;
angleShapeFalse
.attr('transform','translate('+ m +','+ h +')')
.classed('hide',false) ;
}
/ *函数onNodeBlur(){
diamondImage
.classed('hide',true);
rectangleShape
.classed('hide',true);
diamondImageFalse
.classed('hide',true);
angleShapeFalse
.classed('hide',true);
}
* /
//重绘缩放
函数redraw(){
//console.log(\"here,d3.event.translate,d3 .event.scale);
svg.attr( transform,
translate( + d3.event.translate +) +
scale( + d3.event.scale +)) ;
}
// o通话
函数addElement(d,真){
console.log(d );
d.children =空;
d.children = generateEmptyDecisionBox(truthy);
update(root);
}
//绘制元素//
函数drawDiamond(centroid){
//从顶部
console.log开始(形心);
console.log( rectH,rectH,rectW)
//从顶部
开始var result ='M'+ centroid.x +','+(centroid.y- rectH / 2);
//向右移动
结果+ =‘L’+(centroid.x + rectW / 2)+’,’+ centroid.y;
//底部
结果+ =‘L’+ centroid.x +’,’+(centroid.y + rectH / 2);
//左
结果+ =‘L’+(centroid.x-rectW / 2)+’,’+ centroid.y;
//关闭形状
结果+ ='Z';
返回结果;
}
function drawRect(centroid){
//从左上方开始
console.log(centroid);
var result ='M'+(centroid.x-rectW / 2)+’,’+(centroid.y-rectH / 2);
//向右移
结果+ =‘h’+ rectW;
//向下
结果+ =‘v’+ rectH;
//左
结果+ =‘h-’+ rectW;
//关闭形状
结果+ ='Z';
console.log(结果);
的返回结果;
}
var plusButton = svg
.append('g')
.classed('button',true)
.classed('hide ',true)
.on('click',function(){
console.log( hello);
/ * addElement(selectedLink.source); * /
console.log(点击钻石);
console.log(将隐藏设置为true);
removeAllButtonElements();
});
plusButton
.append('rect')
.attr('transform','translate(-8,-8)')//将按钮居中于` g`
.attr('width',16)
.attr('height',16)
.attr('rx',2);
plusButton
.append('path')
.attr('d','M-6 0 H6 M0 -6 V6');
varangleShape = svg.append('g')
.classed('conditionImage',true)
.classed('hide',true)
。 on('click',function(){
removeAllButtonElements();
})
矩形形状
.append('rect')
.attr ('width',30)
.attr('height',20)
.style('fill','orange');
var diamondImage = svg.append('g')
.classed('conditionSvg',true)
.classed('hide',true)
.classed('scale',true)
.on('click',function(){
console.log(点击钻石);
console.log( 将隐藏设置为true);
addElement(selectedNode,'True');
removeAllButtonElements();
});
diamondImage
.append('path')
.attr('d','M 15 0 30 15 15 30 0 15 Z')
.style (填充,橙色);
varangleShapeFalse = svg.append('g')
.classed('conditionImage',true)
.classed('hide',true)
.on('click',function(){
console.log( rectangle clicked);
removeAllButtonElements();
})
radiusShapeFalse
.append('rect')
.attr('width',30)
.attr('height',20)
.style('fill','橙子');
var diamondImageFalse = svg.append('g')
.classed('conditionImage',true)
.classed('hide',true)
。 classed('scale',true)
.on('click',function(){
console.log(点击钻石);
console.log(设置为true);
addElement(selectedNode,'False');
removeAllButtonElements();
});
diamondImageFalse
.append('path')
.attr('d','M 15 0 30 15 15 30 0 15 Z')
.style (填充,橙色);
函数removeAllButtonElements(){
plusButton.classed('hide',true);
diamondImage.classed('hide',true);
angleShape.classed('hide',true);
diamondImageFalse.classed('hide',true);
angleShapeFalse.classed('hide',true);
}
//绘制元素结束..
.node {
光标:指针;
大纲:无!重要;
}
.node文本{
字体:10px sans-serif;
}
.button> path {
stroke:blue;
笔划宽度:1.5;
/ *大纲:无; * /
}
.button> rect {
fill:#ddd;
中风:灰色;
笔划宽度:1px;
}
.conditionalSvg {
轮廓:无;
显示:无;
}
.hide {
display:none;
opacity:0!important;
指针事件:无;
}
.link:hover {
ouline:none!important;
cursor:指针;
笔划宽度:3px;
}
.link path {
outline:none!important;
fill:无;
中风:深灰色;
stroke-width:2px;
}
.link path:hover {
cursor:指针;
stroke-width:4px;
}
.link text {
font:10px sans-serif;
}
.colorBlue {
background-color:blue;
}
< script src = https ://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js< / script>
< div class = tree-diagram>< / div>
I am working on getting a treeview working with some conditional logics. I currently have the following working fiddle: https://jsfiddle.net/zgv9ajn4/4/
From the jsfiddle you can see the below image. On selecting the node with the name "division" I am showing certain orange svgs, and on click of the right-bottom svg I am adding a new child node to the "division" node.
Before Adding child Node and on clicking of the node "division":
After Adding the Child Node:-
As you can see there are some hanging links/nodes and they are not getting removed.
var margin = {
top: 20,
right: 120,
bottom: 20,
left: 120
},
width = 960 - margin.right - margin.left,
height = 800 - margin.top - margin.bottom;
function generateEmptyDecisionBox(condition) {
return condition === 'False' ? [{
"name": "newDecision",
"id": "newId",
"type": "decision",
"value": "notSure",
"condition": `${condition}`,
}, {}] : [{}, {
"name": "newDecision",
"id": "newId",
"type": "decision",
"value": "notSure",
"condition": `${condition}`,
}];
}
var selectedNode;
var selectedLink;
var root = {
"name": "Root",
"type": "decision",
"children": [{
"name": "analytics",
"condition": "False",
"type": "decision",
"value": "a+b",
"children": [{
"name": "distinction",
"type": "action",
"condition": "True",
"value": "5",
}, {
"name": "nonDistinction",
"type": "action",
"condition": "false",
"value": "4",
"children": [],
}],
},
{
"condition": "True",
"name": "division",
"type": "decision",
"value": "a-b",
"children": {
"name": "analytics",
"condition": "False",
"type": "decision",
"value": "a+b",
"children": [{
"name": "distinction",
"type": "action",
"condition": "True",
"value": "5",
}, {
"name": "nonDistinction",
"type": "decision",
"condition": "false",
"value": "4",
"children": {
"name": "analytics",
"condition": "False",
"type": "decision",
"value": "a+b",
"children": [{
"name": "distinction",
"type": "action",
"condition": "True",
"value": "5",
}, {
"name": "nonDistinction",
"type": "action",
"condition": "false",
"value": "4"
}],
},
}],
},
}
]
};
var i = 0,
duration = 500,
rectW = 120,
rectH = 60;
var tree = d3.layout.tree().nodeSize([150, 90]);
//LINK FUNCTION TO DRAW LINKS
var linkFunc = function(d) {
console.log("linkFunc", d);
var source = {
x: d.source.x + rectW / 2,
y: d.source.y + (rectH / 2)
};
var target = {
x: d.target.x + (rectW / 2),
y: d.target.y + 3,
};
// This is where the line bends
var inflection = {
x: target.x,
y: source.y
};
var radius = 5;
var result = "M" + source.x + ',' + source.y;
if (source.x < target.x && d.target.type) {
// Child is to the right of the parent
result += ' H' + (inflection.x - radius);
} else if (d.target.type) {
result += ' H' + (inflection.x + radius);
} else {
return;
}
// Curve the line at the bend slightly
result += ' Q' + inflection.x + ',' + inflection.y + ' ' + inflection.x + ',' + (inflection.y + radius);
result += 'V' + target.y;
return result;
}
// END OF LINK FUNC //
var diagonal = d3.svg.diagonal()
.projection(function(d) {
return [d.x + rectW / 2, d.y + rectH / 2];
});
// DRAW TREE //
var svg = d3.select(".tree-diagram").append("svg").attr("width", 1000).attr("height", 1000)
.call(zm = d3.behavior.zoom().scaleExtent([1, 3]).on("zoom", redraw)).append("g")
.attr("transform", "translate(" + 350 + "," + 20 + ")");
// ADD ARROW TO THE BOTTOM POINTING TO THE NEXT DECISION.
svg.append("svg:defs").selectAll("marker")
.data(["end"]) // Different link/path types can be defined here
.enter().append("svg:marker") // This section adds in the arrows
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", 0.5)
.attr("markerWidth", 4)
.attr("markerHeight", 4)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
//necessary so that zoom knows where to zoom and unzoom from
zm.translate([350, 20]);
root.x0 = 0;
root.y0 = 0;
update(root);
d3.select(".tree-diagram").style("height", "1000px");
// END OF DRAW TREEE //
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 * 90;
});
// 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('transform', 'translate(' + source.x0 + ', ' + source.y0 + ')')
.attr("class", "node")
.on("click", click)
// .on("blur", onNodeBlur);
nodeEnter.append('path')
.attr("d", function(d) {
if (d.type === 'decision') {
return 'M 60 0 120 30 60 60 0 30 Z';
} else if (d.type === 'action') {
return 'M 0 0 120 0 120 60 0 60 Z';
} else {
return 'M -100 -10 -10 -10 -10 -10 -10 -10Z'
}
}).attr("stroke-width", 1)
.attr('class', 'myPaths')
.style("fill", function(d) {
return "lightsteelblue";
});
nodeEnter.append("text")
.attr("x", rectW / 2)
.attr("y", rectH / 2)
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function(d) {
return d.name;
});
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + (d.x) + "," + (d.y) + ")";
});
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + source.x + "," + source.y + ")";
})
.remove();
nodeExit.select("path")
.attr("d", function(d) {
if (d.type === 'decision') {
return 'M 60 0 120 30 60 60 0 30 Z';
} else if (d.type === 'action') {
return 'M 0 0 120 0 120 60 0 60 Z';
} else {
return 'M -100 -10 -10 -10 -10 -10 -10 -10Z'
}
}).attr("stroke-width", 1)
.attr('class', 'myPaths')
.style("fill", function(d) {
return "lightsteelblue";
});
nodeExit.select("text");
// Update the links…
var link = svg.selectAll("path.link")
.data(links, function(d) {
return d.target.id;
}).classed('link1', true);
// Enter any new links at the parent's previous position.
var linkEnter = link.enter().insert("g", "g")
.attr("class", "link");
linkEnter.append('path')
.attr("d", linkFunc)
.on('click', function(d, i) {
selectedLink = d;
// Use the native SVG interface to get the bounding box to
// calculate the center of the path
var bbox = this.getBBox();
var x;
var y;
if (d.source.x < d.target.x) {
// Child is to the right of the parent
x = bbox.x + bbox.width;
y = bbox.y;
plusButton
.attr('transform', 'translate(' + x + ', ' + y + ')')
.classed('hide', false);
} else {
x = bbox.x;
y = bbox.y;
plusButton
.attr('transform', 'translate(' + x + ', ' + y + ')')
.classed('hide', false);
}
})
.on('blur', function(d, i) {
plusButton
.classed('hide', true);
}).attr("marker-end", "url(#end)");
// Add Link Texts.
linkEnter.append('text')
.text(function(d, i) {
if (d.source.x < d.target.x) {
return 'True';
} else {
return 'False';
}
}).attr('transform', function(d) {
console.log(d);
/* var bbox = this.getBBox();
x= bbox.x + bbox.width;
y= bbox.y; */
if (d.source.x < d.target.x && d.target.type) {
console.log("comes in here for source < target");
return 'translate(' + (d.source.x + rectW) + ',' + (d.source.y + rectH) + ')';
} else if (d.target.type) {
return 'translate(' + (d.source.x - rectW / 2) + ',' + (d.source.y + rectH) + ')';
} else {
return;
}
});
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", linkFunc);
// Transition links to their new position.
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", linkFunc)
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
// ON CLICK OF NODES
function click(d) {
if (d.type === 'action') {
return;
}
selectedNode = d;
var m = d.x;
var h = d.y;
var m = d.x + 110;
var h = d.y + 35;
diamondImage
.attr('transform', 'translate(' + m + ', ' + h + ')')
.classed('hide', false);
var m = d.x + 110;
var h = d.y;
rectangleShape
.attr('transform', 'translate(' + m + ', ' + h + ')')
.classed('hide', false);
var m = d.x - 20;
var h = d.y + 35;
diamondImageFalse
.attr('transform', 'translate(' + m + ', ' + h + ')')
.classed('hide', false);
var m = d.x - 20;
var h = d.y;
rectangleShapeFalse
.attr('transform', 'translate(' + m + ', ' + h + ')')
.classed('hide', false);
}
/* function onNodeBlur(){
diamondImage
.classed('hide', true);
rectangleShape
.classed('hide', true);
diamondImageFalse
.classed('hide',true);
rectangleShapeFalse
.classed('hide',true);
}
*/
//Redraw for zoom
function redraw() {
//console.log("here", d3.event.translate, d3.event.scale);
svg.attr("transform",
"translate(" + d3.event.translate + ")" +
" scale(" + d3.event.scale + ")");
}
// oN CALL
function addElement(d, truthy) {
console.log(d);
d.children = null;
d.children = generateEmptyDecisionBox(truthy);
update(root);
}
// draw elements //
function drawDiamond(centroid) {
// Start at the top
console.log(centroid);
console.log("rectH", rectH, rectW)
// Start at the top
var result = 'M' + centroid.x + ',' + (centroid.y - rectH / 2);
// Go right
result += 'L' + (centroid.x + rectW / 2) + ',' + centroid.y;
// Bottom
result += 'L' + centroid.x + ',' + (centroid.y + rectH / 2);
// Left
result += 'L' + (centroid.x - rectW / 2) + ',' + centroid.y;
// Close the shape
result += 'Z';
return result;
}
function drawRect(centroid) {
// Start at the top left
console.log(centroid);
var result = 'M' + (centroid.x - rectW / 2) + ',' + (centroid.y - rectH / 2);
// Go right
result += 'h' + rectW;
// Go down
result += 'v' + rectH;
// Left
result += 'h-' + rectW;
// Close the shape
result += 'Z';
console.log(result);
return result;
}
var plusButton = svg
.append('g')
.classed('button', true)
.classed('hide', true)
.on('click', function() {
console.log("hello");
/* addElement(selectedLink.source); */
console.log("Clicked on Diamond");
console.log("set hide to true");
removeAllButtonElements();
});
plusButton
.append('rect')
.attr('transform', 'translate(-8, -8)') // center the button inside the `g`
.attr('width', 16)
.attr('height', 16)
.attr('rx', 2);
plusButton
.append('path')
.attr('d', 'M-6 0 H6 M0 -6 V6');
var rectangleShape = svg.append('g')
.classed('conditionImage', true)
.classed('hide', true)
.on('click', function() {
removeAllButtonElements();
})
rectangleShape
.append('rect')
.attr('width', 30)
.attr('height', 20)
.style('fill', 'orange');
var diamondImage = svg.append('g')
.classed('conditionSvg', true)
.classed('hide', true)
.classed('scale', true)
.on('click', function() {
console.log("Clicked on Diamond");
console.log("set hide to true");
addElement(selectedNode, 'True');
removeAllButtonElements();
});
diamondImage
.append('path')
.attr('d', 'M 15 0 30 15 15 30 0 15 Z')
.style("fill", 'orange');
var rectangleShapeFalse = svg.append('g')
.classed('conditionImage', true)
.classed('hide', true)
.on('click', function() {
console.log("rectangle clicked");
removeAllButtonElements();
})
rectangleShapeFalse
.append('rect')
.attr('width', 30)
.attr('height', 20)
.style('fill', 'orange');
var diamondImageFalse = svg.append('g')
.classed('conditionImage', true)
.classed('hide', true)
.classed('scale', true)
.on('click', function() {
console.log("Clicked on Diamond");
console.log("set hide to true");
addElement(selectedNode, 'False');
removeAllButtonElements();
});
diamondImageFalse
.append('path')
.attr('d', 'M 15 0 30 15 15 30 0 15 Z')
.style("fill", 'orange');
function removeAllButtonElements() {
plusButton.classed('hide', true);
diamondImage.classed('hide', true);
rectangleShape.classed('hide', true);
diamondImageFalse.classed('hide', true);
rectangleShapeFalse.classed('hide', true);
}
// draw elements end ..
.node {
cursor: pointer;
outline: none !important;
}
.node text {
font: 10px sans-serif;
}
.button>path {
stroke: blue;
stroke-width: 1.5;
/* outline: none; */
}
.button>rect {
fill: #ddd;
stroke: grey;
stroke-width: 1px;
}
.conditionalSvg {
outline: none;
display: none;
}
.hide {
display: none;
opacity: 0 !important;
pointer-events: none;
}
.link:hover {
ouline: none !important;
cursor: pointer;
stroke-width: 3px;
}
.link path {
outline: none !important;
fill: none;
stroke: darkgray;
stroke-width: 2px;
}
.link path:hover {
cursor: pointer;
stroke-width: 4px;
}
.link text {
font: 10px sans-serif;
}
.colorBlue {
background-color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<div class="tree-diagram"></div>
Although the new node is being added and the old nodes are being transitioned to the latest positions, the old nodes/links are not being removed.
Note that your nodes are moving fine, just the links are not. That is because you find them using path.link
, but the real structure is g.link path
, since you first add a g
element with class link
, and then a path
. You could fix that by changing path.link
to g.link
, but then you need to select the path
and text
separately.
I fixed this by calling .attr('d', linkFunc)
on all links, not just the new ones, and by calling .text()
and .attr('transform'
on all texts.
Finally, I changed the text transform to use the x
of the target, since a target determines where the line goes vertical, not the source.
var margin = {
top: 20,
right: 120,
bottom: 20,
left: 120
},
width = 960 - margin.right - margin.left,
height = 800 - margin.top - margin.bottom;
function generateEmptyDecisionBox(condition) {
return condition === 'False' ? [{
"name": "newDecision",
"id": "newId",
"type": "decision",
"value": "notSure",
"condition": `${condition}`,
}, {}] : [{}, {
"name": "newDecision",
"id": "newId",
"type": "decision",
"value": "notSure",
"condition": `${condition}`,
}];
}
var selectedNode;
var selectedLink;
var root = {
"name": "Root",
"type": "decision",
"children": [{
"name": "analytics",
"condition": "False",
"type": "decision",
"value": "a+b",
"children": [{
"name": "distinction",
"type": "action",
"condition": "True",
"value": "5",
}, {
"name": "nonDistinction",
"type": "action",
"condition": "false",
"value": "4",
"children": [],
}],
},
{
"condition": "True",
"name": "division",
"type": "decision",
"value": "a-b",
"children": {
"name": "analytics",
"condition": "False",
"type": "decision",
"value": "a+b",
"children": [{
"name": "distinction",
"type": "action",
"condition": "True",
"value": "5",
}, {
"name": "nonDistinction",
"type": "decision",
"condition": "false",
"value": "4",
"children": {
"name": "analytics",
"condition": "False",
"type": "decision",
"value": "a+b",
"children": [{
"name": "distinction",
"type": "action",
"condition": "True",
"value": "5",
}, {
"name": "nonDistinction",
"type": "action",
"condition": "false",
"value": "4"
}],
},
}],
},
}
]
};
var i = 0,
duration = 500,
rectW = 120,
rectH = 60;
var tree = d3.layout.tree().nodeSize([150, 90]);
//LINK FUNCTION TO DRAW LINKS
var linkFunc = function(d) {
console.log("linkFunc", d);
var source = {
x: d.source.x + rectW / 2,
y: d.source.y + (rectH / 2)
};
var target = {
x: d.target.x + (rectW / 2),
y: d.target.y + 3,
};
// This is where the line bends
var inflection = {
x: target.x,
y: source.y
};
var radius = 5;
var result = "M" + source.x + ',' + source.y;
if (source.x < target.x && d.target.type) {
// Child is to the right of the parent
result += ' H' + (inflection.x - radius);
} else if (d.target.type) {
result += ' H' + (inflection.x + radius);
} else {
return;
}
// Curve the line at the bend slightly
result += ' Q' + inflection.x + ',' + inflection.y + ' ' + inflection.x + ',' + (inflection.y + radius);
result += 'V' + target.y;
return result;
}
// END OF LINK FUNC //
var diagonal = d3.svg.diagonal()
.projection(function(d) {
return [d.x + rectW / 2, d.y + rectH / 2];
});
// DRAW TREE //
var svg = d3.select(".tree-diagram").append("svg").attr("width", 1000).attr("height", 1000)
.call(zm = d3.behavior.zoom().scaleExtent([1, 3]).on("zoom", redraw)).append("g")
.attr("transform", "translate(" + 350 + "," + 20 + ")");
// ADD ARROW TO THE BOTTOM POINTING TO THE NEXT DECISION.
svg.append("svg:defs").selectAll("marker")
.data(["end"]) // Different link/path types can be defined here
.enter().append("svg:marker") // This section adds in the arrows
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", 0.5)
.attr("markerWidth", 4)
.attr("markerHeight", 4)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
//necessary so that zoom knows where to zoom and unzoom from
zm.translate([350, 20]);
root.x0 = 0;
root.y0 = 0;
update(root);
d3.select(".tree-diagram").style("height", "1000px");
// END OF DRAW TREEE //
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 * 90;
});
// 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('transform', 'translate(' + source.x0 + ', ' + source.y0 + ')')
.attr("class", "node")
.on("click", click)
// .on("blur", onNodeBlur);
nodeEnter.append('path')
.attr("d", function(d) {
if (d.type === 'decision') {
return 'M 60 0 120 30 60 60 0 30 Z';
} else if (d.type === 'action') {
return 'M 0 0 120 0 120 60 0 60 Z';
} else {
return 'M -100 -10 -10 -10 -10 -10 -10 -10Z'
}
}).attr("stroke-width", 1)
.attr('class', 'myPaths')
.style("fill", function(d) {
return "lightsteelblue";
});
nodeEnter.append("text")
.attr("x", rectW / 2)
.attr("y", rectH / 2)
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function(d) {
return d.name;
});
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + (d.x) + "," + (d.y) + ")";
});
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + source.x + "," + source.y + ")";
})
.remove();
nodeExit.select("path")
.attr("d", function(d) {
if (d.type === 'decision') {
return 'M 60 0 120 30 60 60 0 30 Z';
} else if (d.type === 'action') {
return 'M 0 0 120 0 120 60 0 60 Z';
} else {
return 'M -100 -10 -10 -10 -10 -10 -10 -10Z'
}
}).attr("stroke-width", 1)
.attr('class', 'myPaths')
.style("fill", function(d) {
return "lightsteelblue";
});
nodeExit.select("text");
// Update the links…
var link = svg.selectAll(".link")
.data(links, function(d) {
return d.target.id;
}).classed('link1', true);
// Enter any new links at the parent's previous position.
var linkEnter = link.enter()
.insert("g", "g")
.attr("class", "link");
linkEnter.append('path')
.on('click', function(d, i) {
selectedLink = d;
// Use the native SVG interface to get the bounding box to
// calculate the center of the path
var bbox = this.getBBox();
var x;
var y;
if (d.source.x < d.target.x) {
// Child is to the right of the parent
x = bbox.x + bbox.width;
y = bbox.y;
plusButton
.attr('transform', 'translate(' + x + ', ' + y + ')')
.classed('hide', false);
} else {
x = bbox.x;
y = bbox.y;
plusButton
.attr('transform', 'translate(' + x + ', ' + y + ')')
.classed('hide', false);
}
})
.on('blur', function(d, i) {
plusButton
.classed('hide', true);
}).attr("marker-end", "url(#end)");
// Add Link Texts.
linkEnter.append('text');
link.select('path')
.attr("d", linkFunc);
link.select('text')
.text(function(d, i) {
if (d.source.x < d.target.x) {
return 'True';
} else {
return 'False';
}
})
.attr('transform', function(d) {
console.log(d);
if (d.source.x < d.target.x && d.target.type) {
console.log("comes in here for source < target");
return 'translate(' + (d.target.x + rectW / 2) + ',' + (d.source.y + rectH) + ')';
} else if (d.target.type) {
return 'translate(' + (d.target.x + rectW / 2) + ',' + (d.source.y + rectH) + ')';
} else {
return;
}
});
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", linkFunc);
// Transition links to their new position.
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", linkFunc)
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
// ON CLICK OF NODES
function click(d) {
if (d.type === 'action') {
return;
}
selectedNode = d;
var m = d.x;
var h = d.y;
var m = d.x + 110;
var h = d.y + 35;
diamondImage
.attr('transform', 'translate(' + m + ', ' + h + ')')
.classed('hide', false);
var m = d.x + 110;
var h = d.y;
rectangleShape
.attr('transform', 'translate(' + m + ', ' + h + ')')
.classed('hide', false);
var m = d.x - 20;
var h = d.y + 35;
diamondImageFalse
.attr('transform', 'translate(' + m + ', ' + h + ')')
.classed('hide', false);
var m = d.x - 20;
var h = d.y;
rectangleShapeFalse
.attr('transform', 'translate(' + m + ', ' + h + ')')
.classed('hide', false);
}
/* function onNodeBlur(){
diamondImage
.classed('hide', true);
rectangleShape
.classed('hide', true);
diamondImageFalse
.classed('hide',true);
rectangleShapeFalse
.classed('hide',true);
}
*/
//Redraw for zoom
function redraw() {
//console.log("here", d3.event.translate, d3.event.scale);
svg.attr("transform",
"translate(" + d3.event.translate + ")" +
" scale(" + d3.event.scale + ")");
}
// oN CALL
function addElement(d, truthy) {
console.log(d);
d.children = null;
d.children = generateEmptyDecisionBox(truthy);
update(root);
}
// draw elements //
function drawDiamond(centroid) {
// Start at the top
console.log(centroid);
console.log("rectH", rectH, rectW)
// Start at the top
var result = 'M' + centroid.x + ',' + (centroid.y - rectH / 2);
// Go right
result += 'L' + (centroid.x + rectW / 2) + ',' + centroid.y;
// Bottom
result += 'L' + centroid.x + ',' + (centroid.y + rectH / 2);
// Left
result += 'L' + (centroid.x - rectW / 2) + ',' + centroid.y;
// Close the shape
result += 'Z';
return result;
}
function drawRect(centroid) {
// Start at the top left
console.log(centroid);
var result = 'M' + (centroid.x - rectW / 2) + ',' + (centroid.y - rectH / 2);
// Go right
result += 'h' + rectW;
// Go down
result += 'v' + rectH;
// Left
result += 'h-' + rectW;
// Close the shape
result += 'Z';
console.log(result);
return result;
}
var plusButton = svg
.append('g')
.classed('button', true)
.classed('hide', true)
.on('click', function() {
console.log("hello");
/* addElement(selectedLink.source); */
console.log("Clicked on Diamond");
console.log("set hide to true");
removeAllButtonElements();
});
plusButton
.append('rect')
.attr('transform', 'translate(-8, -8)') // center the button inside the `g`
.attr('width', 16)
.attr('height', 16)
.attr('rx', 2);
plusButton
.append('path')
.attr('d', 'M-6 0 H6 M0 -6 V6');
var rectangleShape = svg.append('g')
.classed('conditionImage', true)
.classed('hide', true)
.on('click', function() {
removeAllButtonElements();
})
rectangleShape
.append('rect')
.attr('width', 30)
.attr('height', 20)
.style('fill', 'orange');
var diamondImage = svg.append('g')
.classed('conditionSvg', true)
.classed('hide', true)
.classed('scale', true)
.on('click', function() {
console.log("Clicked on Diamond");
console.log("set hide to true");
addElement(selectedNode, 'True');
removeAllButtonElements();
});
diamondImage
.append('path')
.attr('d', 'M 15 0 30 15 15 30 0 15 Z')
.style("fill", 'orange');
var rectangleShapeFalse = svg.append('g')
.classed('conditionImage', true)
.classed('hide', true)
.on('click', function() {
console.log("rectangle clicked");
removeAllButtonElements();
})
rectangleShapeFalse
.append('rect')
.attr('width', 30)
.attr('height', 20)
.style('fill', 'orange');
var diamondImageFalse = svg.append('g')
.classed('conditionImage', true)
.classed('hide', true)
.classed('scale', true)
.on('click', function() {
console.log("Clicked on Diamond");
console.log("set hide to true");
addElement(selectedNode, 'False');
removeAllButtonElements();
});
diamondImageFalse
.append('path')
.attr('d', 'M 15 0 30 15 15 30 0 15 Z')
.style("fill", 'orange');
function removeAllButtonElements() {
plusButton.classed('hide', true);
diamondImage.classed('hide', true);
rectangleShape.classed('hide', true);
diamondImageFalse.classed('hide', true);
rectangleShapeFalse.classed('hide', true);
}
// draw elements end ..
.node {
cursor: pointer;
outline: none !important;
}
.node text {
font: 10px sans-serif;
}
.button>path {
stroke: blue;
stroke-width: 1.5;
/* outline: none; */
}
.button>rect {
fill: #ddd;
stroke: grey;
stroke-width: 1px;
}
.conditionalSvg {
outline: none;
display: none;
}
.hide {
display: none;
opacity: 0 !important;
pointer-events: none;
}
.link:hover {
ouline: none !important;
cursor: pointer;
stroke-width: 3px;
}
.link path {
outline: none !important;
fill: none;
stroke: darkgray;
stroke-width: 2px;
}
.link path:hover {
cursor: pointer;
stroke-width: 4px;
}
.link text {
font: 10px sans-serif;
}
.colorBlue {
background-color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<div class="tree-diagram"></div>
这篇关于D3.js-添加新节点并进行迁移后,旧链接不会被删除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!