【问题标题】:How to create a decision tree / flow chart in D3/dagre-D3/javascript?如何在 D3/dagre-D3/javascript 中创建决策树/流程图?
【发布时间】:2019-05-03 16:10:16
【问题描述】:

所以我想创建一个问题流程图,如下所示: 不知道最好的起点是……这是有向图吗? 其中一些最终被隔开,看起来不太适合像这样的“流动”:https://observablehq.com/@d3/force-directed-graph

我见过的最好的例子是一个非 D3 库(yworks),但它似乎要花费 15000 美元: 这是我见过的唯一一个相关的 StackOverflow,它只引用了 yworks: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({});

我想添加一些很酷的可选内容:

*我还希望能够控制 Circles 上的 css,比如根据该节点的数据,在某些情况下,有些会变绿或变红。

*每个边缘箭头我还想添加 onHovers 事件,所以会出现一个工具提示来显示实际规则,例如“if(Question1 == A || B)”

*使节点/边缘可拖动或“有弹性”(如果被拖动,它们会弹回原始位置)。听起来很花哨,但有时如果规则过于拥挤(因为智能自动布局),用户可能会使用此功能,并且他们想拖动内容以查看箭头指向的位置。

【问题讨论】:

    标签: d3.js dagre-d3 dagre


    【解决方案1】:

    我想我是用 dagre-d3 搞定的。 这是我最初的jsfiddle: http://jsfiddle.net/armyofda12mnkeys/4gv90qhx/2/

    这里也是同样的例子,弹出窗口也在边缘(虽然我不喜欢节点弹出窗口的实现) http://jsfiddle.net/armyofda12mnkeys/4gv90qhx/37/

    这是我在项目中如何使用糖尿病问卷的完整示例(我将代码升级到最新的 d3.v5+dagre,并使节点+边缘可拖动...大量初始 JSON 解析代码进入我实际上可以循环的格式,抱歉): https://jsfiddle.net/armyofda12mnkeys/1burht5j/44/ 注意:如果我使用的“cors-anywhere”网站已关闭,则最后一个链接可能无效。那就试试下载吧。

    // 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);
    

    【讨论】:

      猜你喜欢
      • 2015-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多