简体   繁体   English

如何在 D3/dagre-D3/javascript 中创建决策树/流程图?

[英]How to create a decision tree / flow chart in D3/dagre-D3/javascript?

So I would like to create a question flowchart like below:所以我想创建一个如下的问题流程图: “问题流程”图表示例 Not sure where the best place to start is... Is this a Directed Graph?不确定从哪里开始最好......这是有向图吗? Some of those end up being really spaced out and not looking great for 'flows' like so: https://observablehq.com/@d3/force-directed-graph其中一些最终真的被隔开并且看起来不太适合像这样的“流”: https : //observablehq.com/@d3/force-directed-graph

The best example I've seen is a non-D3 library (yworks) but it seems to cost $15k:我见过的最好的例子是一个非 D3 库(yworks),但它似乎要花费 1.5 万美元: yworks示例 This is the only related StackOverflow I've seen which just references yworks: Can I create a flow chart (no tree chart) using D3.js Maybe this dagre-d3 example as well: http://jsfiddle.net/armyofda12mnkeys/9L50of2c/2/这是我见过的唯一一个仅引用 yworks 的相关 StackOverflow: Can I create a flow chart (no tree chart) using D3.js也许这个 dagre-d3 示例也是: http : //jsfiddle.net/armyofda12mnkeys/9L50of2c /2/

var g = new dagreD3.graphlib.Graph().setGraph({});

Some cool optional stuff I'd like to add:我想添加一些很酷的可选内容:

*I also want to be able to control the css on the Circles, like some will green some red in certain circumstances based on that node's data. *我还希望能够控制 Circles 上的 css,就像在某些情况下根据该节点的数据,有些人会变成绿色有些红色。

*Each Edge arrow I'd also like to add onHovers events, so a tooltip comes up to show the actual rule like 'if(Question1 == A || B)' *每个边缘箭头我还想添加 onHovers 事件,因此会出现一个工具提示以显示实际规则,例如“if(Question1 == A || B)”

*Make the nodes/edges draggable or 'bouncy' (where they pop back to orig location if dragged). *使节点/边缘可拖动或“有弹性”(如果拖动,它们会弹回原点位置)。 Sounds gimmicky, but sometimes users may use this feature if the rules get too cramped together (because of the smart auto-layout) and they wanna drag stuff to see what arrows point where.听起来很花哨,但有时用户可能会在规则过于拥挤时使用此功能(因为智能自动布局)并且他们想拖动东西以查看箭头指向的位置。

I think I got it with dagre-d3.我想我是用 dagre-d3 搞定的。 Here is my initial jsfiddle: http://jsfiddle.net/armyofda12mnkeys/4gv90qhx/2/这是我最初的 jsfiddle: http : //jsfiddle.net/armyofda12mnkeys/4gv90qhx/2/

Also here is the same example with popups also on the edges (although I don't like the implementation as much as the node popups) http://jsfiddle.net/armyofda12mnkeys/4gv90qhx/37/这里也是同样的例子,边缘也有弹出窗口(虽然我不喜欢节点弹出窗口的实现) http://jsfiddle.net/armyofda12mnkeys/4gv90qhx/37/

and here is a full example of how I'm using in my project for a Diabetes Questionnaire (I upgraded the code to latest d3.v5+dagre, and made the nodes+edges draggable... lots of initial JSON parsing code to get into a format I can actually loop over, sorry bout that): https://jsfiddle.net/armyofda12mnkeys/1burht5j/44/ Note: this last link may not work if 'cors-anywhere' website Im using is down.这是我如何在我的糖尿病问卷项目中使用的完整示例(我将代码升级到最新的 d3.v5+dagre,并使节点+边缘可拖动......许多初始 JSON 解析代码以获得转换成我实际上可以循环的格式,抱歉): https ://jsfiddle.net/armyofda12mnkeys/1burht5j/44/ 注意:如果我使用的“cors-anywhere”网站关闭,最后一个链接可能无法工作。 Try downloading it then.那就试试下载吧。

// Create a new directed graph
var g = new dagreD3.graphlib.Graph().setGraph({});

var nodes = [ 
{'qs_code':"QS1", 'hovertext': 'This is QS1', 'proto_logic_type': 'none' },
{'qs_code':"QS2", 'hovertext': 'This is QS2', 'proto_logic_type': 'disqualify'},
{'qs_code':"QS3", 'hovertext': 'This is QS3', 'proto_logic_type': 'qualify'},
{'qs_code':"QS4", 'hovertext': 'This is QS4', 'proto_logic_type': 'both'},
{'qs_code':"QS5", 'hovertext': 'This is QS5', 'proto_logic_type': 'none'},
{'qs_code':"QS6", 'hovertext': 'This is QS6', 'proto_logic_type': 'none'}
];

// Automatically label each of the nodes
nodes.forEach(function(node) {
    g.setNode(node.qs_code, { label: node.qs_code, shape: "circle", class: [node.proto_logic_type], hovertext: node.hovertext  });  //style: 'fill: red' 
});

// Set up the edges
g.setEdge("QS1", "QS2", { label: "<u onmouseover='(function(){ return $(\"#tooltip_template\").css(\"visibility\", \"visible\"); })()' onmouseout='(function(){ return $(\"#tooltip_template\").css(\"visibility\", \"hidden\"); })()' onmousemove='(function(){ $(\"#tooltip_template\").html(\"AAA&amp;gt;BBB\").css(\"top\", (event.pageY-10)+\"px\").css(\"left\",(event.pageX+10)+\"px\"); })()'>Rule1</u>", hovertext:"A>B", labelType: "html" });
g.setEdge("QS1", "QS3", { label: "<u onmouseover='(function(){ return $(\"#tooltip_template\").css(\"visibility\", \"visible\"); })()' onmouseout='(function(){ return $(\"#tooltip_template\").css(\"visibility\", \"hidden\"); })()' onmousemove='(function(){ $(\"#tooltip_template\").html(\"AAA&amp;lt;BBB\").css(\"top\", (event.pageY-10)+\"px\").css(\"left\",(event.pageX+10)+\"px\"); })()'>Rule2</u>", hovertext:"A<B", labelType: "html" });
g.setEdge("QS1", "QS4", { label: "<u onmouseover='(function(){ return $(\"#tooltip_template\").css(\"visibility\", \"visible\"); })()' onmouseout='(function(){ return $(\"#tooltip_template\").css(\"visibility\", \"hidden\"); })()' onmousemove='(function(){ $(\"#tooltip_template\").html(\"AAA==BBB\").css(\"top\", (event.pageY-10)+\"px\").css(\"left\",(event.pageX+10)+\"px\"); })()'>Rule3</u>", hovertext:"A==B", labelType: "html" });

g.setEdge("QS2", "QS5", { label: "Rule1", arrowhead: "vee", hovertext:"(A+B)>1" });

g.setEdge("QS3", "QS5", { label: "Rule1", hovertext:"(A-B)<2" });
g.setEdge("QS3", "QS6", { label: "Rule2", hovertext:"(A*B)>=3" });

g.setEdge("QS4", "QS6", { label: "Rule2", arrowhead: "vee", hovertext:"(A>10)||(B<20)" });


var svg = d3.select("svg"),
    inner = svg.select("g");

// Set the rankdir
g.graph().rankdir = 'TB';//'LR';
g.graph().nodesep = 50;

// Set up zoom support
var zoom = d3.behavior.zoom().on("zoom", function() {
      inner.attr("transform", "translate(" + d3.event.translate + ")" +
                                  "scale(" + d3.event.scale + ")");
    });
svg.call(zoom);

// Create the renderer
var render = new dagreD3.render();


// Run the renderer. This is what draws the final graph.
render(inner, g);


var tooltip = d3.select("body")
    .append("div")
  .attr('id', 'tooltip_template')
    .style("position", "absolute")
    .style("background-color", "white")
  .style("border", "solid")
  .style("border-width", "2px")
  .style("border-radius", "5px")  
  .style("padding", "5px")
    .style("z-index", "10")
    .style("visibility", "hidden")
    .text("Simple Tooltip...");

inner.selectAll('g.node')
  .attr("data-hovertext", function(v) { 
        return g.node(v).hovertext
    })
    .on("mouseover", function(){return tooltip.style("visibility", "visible");})
    .on("mousemove", function(){ 
    tooltip.text( this.dataset.hovertext)   
        .style("top", (event.pageY-10)+"px")
        .style("left",(event.pageX+10)+"px");
  })
    .on("mouseout", function(){return tooltip.style("visibility", "hidden");});

inner.selectAll('g.edgePath')
//inner.selectAll('path')
.append('title').text('This is a line.');

// Center the graph
var initialScale = 0.75;
zoom
  .translate([(svg.attr("width") - g.graph().width * initialScale) / 2, 20])
  .scale(initialScale)
  .event(svg);
svg.attr('height', g.graph().height * initialScale + 40);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM