javascript - d3-graphviz:如果我使用相同的 graphviz 渲染器多次绘制略有不同的图形,则渲染不正确
问题描述
我正在使用 d3-graphviz 来绘制交互式图表。我发现,以某种方式使用开始时创建的相同 graphviz 渲染器重新绘制新的/更新的图形会导致错误的布局。例如,如果我执行以下步骤,就会出错:
- 创建 index.html,包括我们需要使用的 d3、d3-graphviz 和 viz。
- 使用带有特定回调的 renderDot() 函数。
- 再次调用 renderDot() 绘制另一个,带有多行粗体标签
- 使用 renderDot() 再次渲染以生成与步骤 2 中相同的图形
我应该再次到达最后:
但是最后一步(第 4 步)会导致错误的布局图。节点和边不会放置在正确的位置:
另请注意,在第 3 步之后,如果我单击 svg,它会向上(一个方向)移动一点,这也很奇怪。我们点击后,它看起来是这样的:
以下是源代码:
索引.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>
渲染.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”,它会更新字体。在“隐藏”的情况下没有区别。
谢谢!
解决方案
- 您需要在回调中进行后续渲染。
- 为获得粗体字体而对 DOM 进行的操作会使事情变得混乱。改为使用纯属性设置。
我在下面的代码中进行了这些更改,还添加了一个转换,这样您就可以清楚地看到发生了什么,而无需逐步运行代码。
该代码代表我认为您的代码在正确的情况下会执行的操作。如果那是您真正想要的,请参阅我在代码中关于最初设置粗体字体的评论。
<!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>
推荐阅读
- c++ - variable_name的多个定义,这里先定义
- haskell - Haskell - 递归循环中的分支执行除所选分支之外的所有先前访问过的分支
- javascript - React-Navigation:按图像导航
- pytorch - 如何对两个 PyTorch 量化张量进行矩阵相乘?
- java - 如何导入 sun.audio?
- wordpress - Dart Flutter - 使用 Chopper 获取 WordPress 自定义帖子类型
- bash - 无法将 fil 中的两个参数提供给 bash 脚本:找不到命令
- excel - Excel,每第 N 行累积求和,但 N 的随机长度
- azure - 当 signInAudience = AzureADMyOrg 或 AzureADMultipleOrgs 时 Azure AD B2C 应用程序不可用
- php - CURLOPT_STDERR 总是被执行?