【问题标题】:d3-graphviz: incorrect rendering if I use same graphviz renderer to draw slightly different graph multiple timesd3-graphviz:如果我使用相同的 graphviz 渲染器多次绘制略有不同的图形,则渲染不正确
【发布时间】:2018-05-01 14:01:52
【问题描述】:

我使用 d3-graphviz 来绘制交互式图表。我发现,以某种方式使用开始时创建的相同 graphviz 渲染器来重新绘制新/更新的图形会导致错误的布局。例如,如果我执行以下步骤,就会出错:

  1. 创建index.html,包括我们需要使用的d3、d3-graphviz和viz。
  2. 使用带有特定回调的 renderDot() 函数。
  3. 再次调用 renderDot() 绘制另一个,带有多行粗体标签
  4. 使用 renderDot() 再次渲染以生成与第 2 步相同的图形

我应该再次到达最后:

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

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

这里是源代码:

index.html:

<!-- 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>

render.js:

<!-- 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>");
        }
    })
});

您可以通过创建 index.html 来复制它,然后在 javascript 中逐步运行代码。

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

谢谢!

【问题讨论】:

    标签: javascript d3.js graphviz


    【解决方案1】:
    1. 您需要在回调中进行后续渲染。
    2. 为获得粗体字体而对 DOM 进行的操作会使事情变得混乱。改为使用纯属性设置。

    我在下面的代码中进行了这些更改,还添加了一个过渡,这样您就可以清楚地看到发生了什么,而无需逐步运行代码。

    代码代表我认为您的代码在正确的情况下会执行的操作。如果那是你真正想要的,请参阅代码中关于最初设置粗体字体的我的 cmets。

    <!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>
    
    <script>
      // create renderer
    x = d3.select('#graph').graphviz()
      .transition(function () {return d3.transition().duration(2000)})
    // replace the font-weight settings below with this if you want a bold font already from the start
    //  .on("transitionStart", function() {d3.selectAll('text').attr("font-weight", "bold");});
    
      // 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').attr("font-weight", "bold");
    
        // 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').attr("font-weight", "bold");
            // 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').attr("font-weight", "bold");
    
            });
        });
    });
    
    </script>
    
    </body>

    【讨论】:

    • 感谢您的回答! 3 个问题: 1) 当您提到我对 DOM 的操作以获取粗体字体时,所有的 html 源代码似乎都很好。那你怎么能说是因为这个呢? 2)我使用 因为我需要将“:”之前的单词加粗,有时我们有多行(你的 sol 不能解决这个问题)。 3)我已经用点击事件扩展了它来触发那些后续的渲染。我看到你如何完美地将一个嵌入另一个(使用回调)。当我需要添加“.on('click', ...)”事件时,我想我会遇到同样的问题?
    • 并且仅仅因为我的用例或上面提到的所需功能,我必须使用 ,以及添加点击事件侦听器。反正有什么效果很好吗?
    • 1.仅仅因为我删除了然后它起作用了。 d3-graphviz 将数据附加在图表中与层次结构相关的每个元素上,我认为它搞砸了,因为您破坏了该层次结构,但这只是一种猜测。我没有仔细调查过。 2. 你的问题是什么?我的解决方案应该影响 all 文本元素。 “:”有什么特别之处吗?我必须尝试自己,但我现在没有时间。 3. 我不明白。给我一个例子。
    • 关于你的最后一个问题,我不明白。给我一个例子。
    猜你喜欢
    • 1970-01-01
    • 2020-01-03
    • 2014-11-03
    • 2022-08-23
    • 2021-10-04
    • 1970-01-01
    • 1970-01-01
    • 2020-12-20
    • 2021-04-10
    相关资源
    最近更新 更多