Javascript d3 graphviz:如果使用相同的graphviz渲染器多次绘制稍有不同的图形,则渲染不正确

Javascript d3 graphviz:如果使用相同的graphviz渲染器多次绘制稍有不同的图形,则渲染不正确,javascript,d3.js,graphviz,Javascript,D3.js,Graphviz,我使用d3 graphviz绘制交互式图形。我发现,不知何故,使用在开始时创建的相同graphviz渲染器重新绘制新的/更新的图形会导致错误的布局。例如,如果我执行以下步骤,它将出错: 创建index.html,包括我们需要使用的d3、d3图形和viz 将renderDot()函数与特定回调一起使用 再次调用renderDot()以绘制另一个带有多行粗体字体标签的渲染器 使用renderDot()再次渲染,以生成与步骤2中相同的图形 我应该在最后再说一遍: 但是,最后一步(步骤4)会导致错误的

我使用d3 graphviz绘制交互式图形。我发现,不知何故,使用在开始时创建的相同graphviz渲染器重新绘制新的/更新的图形会导致错误的布局。例如,如果我执行以下步骤,它将出错:

  • 创建index.html,包括我们需要使用的d3、d3图形和viz
  • 将renderDot()函数与特定回调一起使用
  • 再次调用renderDot()以绘制另一个带有多行粗体字体标签的渲染器
  • 使用renderDot()再次渲染,以生成与步骤2中相同的图形
  • 我应该在最后再说一遍:

    但是,最后一步(步骤4)会导致错误的布局图。节点和边将不会放置在正确的位置:

    还要注意,在第3步之后,如果我单击svg,它会向上移动(一个方向),这也很奇怪。我们点击它后,它看起来像这样:

    以下是源代码:

    index.html:

    
    
    render.js:

    
    //请一步一步地运行下面的代码
    //创建渲染器
    x=d3.选择(“#图形”).graphviz()
    //第一次渲染
    x、 伦德多(`
    有向图{
    节点[style=“filled”]
    0[id=“0”label=“本田::车型”]
    1[id=“1”label=“hidden”]
    2[id=“2”label=“hidden”]
    0->1[id=“0->1”标签=”“]
    0->2[id=“0->2”label=”“]
    }
    `,函数(){
    d3.选择全部('text')。_组[0]。forEach(函数(e){
    if(ans=/(.+?\:).+/.exec(e.innerHTML)){
    e、 innerHTML=ans[0]。替换(ans[1],
    “+ans[1]+”;
    }
    })
    });
    //第二次渲染(粗体和多行文字标签)
    x、 伦德多(`
    有向图{
    节点[style=“filled”]
    0[id=“0”label=“本田::车型”]
    1[id=“1”label=“name:fit\\linventory id:007”]
    2[id=“2”label=“hidden”]
    0->1[id=“0->1”标签=”“]
    0->2[id=“0->2”label=”“]
    }
    `,函数(){
    d3.选择全部('text')。_组[0]。forEach(函数(e){
    if(ans=/(.+?\:).+/.exec(e.innerHTML)){
    e、 innerHTML=ans[0]。替换(ans[1],
    “+ans[1]+”;
    }
    })
    });
    //第三次渲染
    x、 伦德多(`
    有向图{
    节点[style=“filled”]
    0[id=“0”label=“本田::车型”]
    1[id=“1”label=“hidden”]
    2[id=“2”label=“hidden”]
    0->1[id=“0->1”标签=”“]
    0->2[id=“0->2”label=”“]
    }
    `,函数(){
    d3.选择全部('text')。_组[0]。forEach(函数(e){
    if(ans=/(.+?\:).+/.exec(e.innerHTML)){
    e、 innerHTML=ans[0]。替换(ans[1],
    “+ans[1]+”;
    }
    })
    });
    
    您可以通过创建index.html,然后逐步在javascript中运行代码来复制它

    注意:我把回调函数放在那里了,如果它在每一行中看到“text:xxx”模式,就会更新字体。在“隐藏”的情况下没有区别

    谢谢

  • 您需要在回调中进行后续渲染
  • 为了获得粗体字体而对DOM的操作会把事情搞砸。改为使用纯属性设置
  • 我在下面的代码中做了这些更改,还添加了一个转换,这样您就可以清楚地看到发生了什么,而无需一步一步地运行代码

    该代码表示如果代码正确,我认为您的代码会执行的操作。如果您真的想要设置粗体字体,请参阅我在代码中关于最初设置粗体字体的注释

    
    //创建渲染器
    x=d3.选择(“#图形”).graphviz()
    .transition(函数(){return d3.transition().duration(2000)})
    //如果您希望从一开始就使用粗体字体,请将下面的字体重量设置替换为该设置
    //.on(“transitionStart”,function(){d3.selectAll('text').attr(“font-weight”,“bold”);});
    //第一次渲染
    x、 伦德多(`
    有向图{
    节点[style=“filled”]
    0[id=“0”label=“本田::车型”]
    1[id=“1”label=“hidden”]
    2[id=“2”label=“hidden”]
    0->1[id=“0->1”标签=”“]
    0->2[id=“0->2”label=”“]
    }
    `,函数(){
    d3.选择全部(“文本”).attr(“字体重量”、“粗体”);
    //第二次渲染(粗体和多行文字标签)
    x、 伦德多(`
    有向图{
    节点[style=“filled”]
    0[id=“0”label=“本田::车型”]
    1[id=“1”label=“name:fit\\linventory id:007”]
    2[id=“2”label=“hidden”]
    0->1[id=“0->1”标签=”“]
    0->2[id=“0->2”label=”“]
    }
    `,函数(){
    d3.选择全部(“文本”).attr(“字体重量”、“粗体”);
    //第三次渲染
    x、 伦德多(`
    有向图{
    节点[style=“filled”]
    0[id=“0”label=“本田::车型”]
    1[id=“1”label=“hidden”]
    2[id=“2”label=“hidden”]
    0->1[id=“0->1”标签=”“]
    0->2[id=“0->2”label=”“]
    }
    `,函数(){
    d3.选择全部(“文本”).attr(“字体重量”、“粗体”);
    });
    });
    });
    
    谢谢你的回答!3个问题:1)当您提到我操纵DOM以获得粗体字体时,所有的html源代码似乎都很好。那你怎么知道是因为这个?2) 我之所以使用,是因为我需要在“粗体”之前加上一个词:“有时我们有多行(您的sol无法解决此问题)。3) 我用点击事件来扩展它,以触发那些后续的渲染。我看到了如何完美地将一个嵌入另一个(使用回调)。当我需要添加“.on('click',…)”事件时,我想我会遇到同样的问题?仅仅因为我的用例或上面提到的所需功能,我必须使用,同时添加click事件侦听器。到底有没有效果很好的。只是因为我移除了它,然后它工作了。d3 graphviz在图中的每个元素上附加数据,这些元素在一个层次结构中是相关的,我认为它被搞砸了,因为你打破了这个层次结构,但这只是一个推测。我还没有调查
    <!-- language: lang-html -->
    
    <!DOCTYPE html>
    <meta charset="utf-8">
    <body>
    <script src=https://d3js.org/d3.v5.min.js></script>
    <script src=https://unpkg.com/viz.js@1.8.0/viz.js></script>
    <script src=https://unpkg.com/d3-graphviz@1.5.0/build/d3-graphviz.min.js></script>
    
    <!-- Main Graph -->
    <div id="graph" style="text-align: center;" height=3200px width=3200px></div>
    
    </body>
    
    <!-- language: typescript -->
    
    // please run below code step by step
    
    // create renderer
    x = d3.select('#graph').graphviz()
    
    // 1st rendering
    x.renderDot(`
    digraph {
        node [style="filled"]
        0 [id="0" label="honda::models"]
        1 [id="1" label="hidden"]
        2 [id="2" label="hidden"]
        0 -> 1 [id="0->1" label=""]
        0 -> 2 [id="0->2" label=""]
    }
    `, function() {
        d3.selectAll('text')._groups[0].forEach(function(e) {
            if (ans=/(.+?\: ).+/.exec(e.innerHTML)) {
                e.innerHTML = ans[0].replace(ans[1],
                    "<tspan font-weight=bold>" + ans[1] + "</tspan>");
            }
        })
    });
    
    // 2nd rendering (bold and multi-line text label)
    x.renderDot(`
    digraph {
        node [style="filled"]
        0 [id="0" label="honda::models"]
        1 [id="1" label="name: fit\\linventory id: 007"]
        2 [id="2" label="hidden"]
        0 -> 1 [id="0->1" label=""]
        0 -> 2 [id="0->2" label=""]
    }
    `, function() {
        d3.selectAll('text')._groups[0].forEach(function(e) {
            if (ans=/(.+?\: ).+/.exec(e.innerHTML)) {
                e.innerHTML = ans[0].replace(ans[1],
                    "<tspan font-weight=bold>" + ans[1] + "</tspan>");
            }
        })
    });
    
    // 3rd rendering
    x.renderDot(`
    digraph {
        node [style="filled"]
        0 [id="0" label="honda::models"]
        1 [id="1" label="hidden"]
        2 [id="2" label="hidden"]
        0 -> 1 [id="0->1" label=""]
        0 -> 2 [id="0->2" label=""]
    }
    `, function() {
        d3.selectAll('text')._groups[0].forEach(function(e) {
            if (ans=/(.+?\: ).+/.exec(e.innerHTML)) {
                e.innerHTML = ans[0].replace(ans[1],
                    "<tspan font-weight=bold>" + ans[1] + "</tspan>");
            }
        })
    });