[英]How to render a large graph smoothly as a react.js component?
I want to visualize large graphs, but the UI freezes and the V8 engine throws out-of-memory errors after about 25 seconds.我想可视化大图,但 UI 冻结并且 V8 引擎在大约 25 秒后抛出内存不足错误。
Ideally, I want the graph rendering will be smooth and non-blocking.理想情况下,我希望图形渲染流畅且无阻塞。
My Graph.js
file below assigns the graph dot string to the src
variable when the "Set" button is pressed and attempts to display the graph when the "Render" button is pressed.我的
Graph.js
文件在按下“设置”按钮时将图形点字符串分配给src
变量,并在按下“渲染”按钮时尝试显示图形。
import React, { useRef, useState } from 'react';
import Viz from 'viz.js';
import { Module, render } from 'viz.js/full.render.js';
const largegraph = "digraph { " + Array.from(Array(1000).keys()).map(i => "a" + i + " [label=" + i + "];").join(" ") + Array.from(Array(10000).keys()).map(i => "a" + Math.floor(Math.random() * 1000) + " -> " + "a" + Math.floor(Math.random() * 1000) + ";").join(" ") + " }";
function GraphvizGraph(props) {
const container = useRef(null);
const [src, setSrc] = useState(props.src);
const renderGraph = (src) => {
const viz = new Viz({ Module, render });
viz.renderSVGElement(src)
.then(function (element) {
container.current.innerHTML = "";
container.current.appendChild(element);
});
}
console.log(largegraph)
return (
<div>
<button onClick={() => setSrc(largegraph)}>Set</button>
<button onClick={() => renderGraph(src)}>Render</button>
<div ref={container} />
</div>
);
}
export default GraphvizGraph;
After setting up the large graph, clicking the "Render" button fails to display anything and causes the UI to freeze.设置大图后,点击“Render”按钮无法显示任何内容并导致UI卡顿。 After a few seconds, Chrome throws an exception.
几秒钟后,Chrome 抛出异常。 Is there a way to fix this issue and successfully visualize smoothly the graph?
有没有办法解决这个问题并成功地平滑地可视化图形?
full.render.js:24 Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value 16777216, (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime but prevents some optimizations, (3) set Module.TOTAL_MEMORY to a higher value before the program runs, or (4) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0
abort @ full.render.js:24
react-dom.development.js:4161 [Violation] 'click' handler took 23773ms
[Violation] 'click' handler took 23773ms
Uncaught (in promise) abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value 16777216, (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime but prevents some optimizations, (3) set Module.TOTAL_MEMORY to a higher value before the program runs, or (4) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 "). Build with -s ASSERTIONS=1 for more info.
There are a few ways to go about improving the graph rendering performance. go 关于提高图形渲染性能有几种方法。 The first is to tune graph attributes like
nslimit
, maxiter
, and splines
.第一个是调整图形属性,如
nslimit
、 maxiter
和splines
。 Adjusting them to be less complex can offer significant speed-ups in exchange for "attractiveness".将它们调整得不那么复杂可以提供显着的加速以换取“吸引力”。
Another way is to use a different layout engine.另一种方法是使用不同的布局引擎。
viz.renderSVGElement()
by default uses the dot
layout engine, which isn't particularly fast. viz.renderSVGElement()
默认使用dot
布局引擎,速度不是特别快。 osage
and twopi
are typically a lot faster, but they also trade it for "attractiveness". osage
和twopi
通常要快得多,但他们也会用它来换取“吸引力”。 In order to specify which layout engine to use,viz.renderSVGElement(src, renderOptions)
takes a second parameter which is a Render Options object, in which you can set {engine: "osage"}
.为了指定要使用的布局引擎,
viz.renderSVGElement(src, renderOptions)
采用第二个参数,即渲染选项object,您可以在其中设置{engine: "osage"}
。
Other Notes :其他注意事项:
overlap=false;
overlap=false;
to your graph attributes to ensure nodes don't overlap and remain somewhat readable.dangerouslySetInnerHTML
to render it.dangerouslySetInnerHTML
来渲染它。function GraphvizGraph(props) {
const [src, setSrc] = useState(props.src);
const [svgStr, setSvgStr] = useState("");
const renderGraph = (src) => {
const viz = new Viz({ Module, render });
viz.renderSVGElement(src, {engine: "osage"})
.then((svg) => setSvgStr(svg.outerHTML));
}
console.log(largegraph)
return (
<div>
<button onClick={() => setSrc(largegraph)}>Set</button>
<button onClick={() => renderGraph(src)}>Render</button>
<div dangerouslySetInnerHTML={{__html: svgStr}} />
</div>
);
}
I did something similar to what was suggested earlier on , just using hpcc-js/wasm/graphviz which seems a more established solution that viz.js
mentioned by OP.我做了一些类似于之前建议的事情,只是使用hpcc-js/wasm/graphviz ,这似乎是 OP 提到的
viz.js
更成熟的解决方案。
import './App.css';
import { Graphviz } from "@hpcc-js/wasm/graphviz";
import React from 'react';
function Graph(props) {
const [svg, setSvg] = React.useState(null);
React.useEffect(() => {
async function name(params) {
const graphviz = await Graphviz.load();
const dot = `digraph G5 {
edge [fontcolor=black fontsize="10" fontname=Arial];
subgraph referenceNodes {
node [style="filled" fontcolor=white fontsize="12" fontname=Arial];
subgraph person {
node [fillcolor="blue"];
person_JaneDoe [label="<person>\nJane Doe"];
person_WendyDoe [label="<person>\nWendy Doe"];
person_StacyDoe [label="<person>\nStacy Doe"];
}
subgraph profession {
node [fillcolor="darkGreen"];
profession_Programmer [label="<profession>\nProgrammer"];
profession_Writer [label="<profession>\nWriter"];
}
subgraph vehicle {
node [fillcolor="purple"];
vehicle_Subaru [label="<vehicle>\nSubaru"];
vehicle_Ford [label="<vehicle>\nFord"];
}
}
subgraph dataNodes {
node [shape=box style="filled" fillcolor=yellow fontcolor=black fontsize="12" fontname=Arial];
value_age24_1 [label="<integer>\n24";];
value_age24_2 [label="<integer>\n24";];
value_age21_1 [label="<integer>\n21";];
}
subgraph JaneDoe {
person_JaneDoe -> person_WendyDoe [label=" has sister" dir=both];
person_JaneDoe -> person_StacyDoe [label=" has sister" dir=both];
person_JaneDoe -> profession_Programmer [label=" is a"];
person_JaneDoe -> vehicle_Subaru [label=" owns a"];
person_JaneDoe -> value_age24_1 [label="has age"];
}
subgraph WendyDoe {
person_WendyDoe -> profession_Writer [label=" is a"];
person_WendyDoe -> vehicle_Subaru [label=" owns a"];
person_WendyDoe -> value_age24_2 [label="has age"];
person_WendyDoe -> person_StacyDoe [label=" has sister" dir=both];
}
subgraph StacyDoe {
person_StacyDoe -> profession_Writer [label="is a"]
person_StacyDoe -> vehicle_Ford [label="owns a"]
person_StacyDoe -> value_age21_1 [label="has age"];
}
}`;
const svg_tmp = graphviz.dot(dot);
setSvg(svg_tmp);
console.log(graphviz.version(), svg_tmp);
} name();
}, [])
return <div>
<div dangerouslySetInnerHTML={{ __html: svg }} />
</div>
}
function App() {
return (
<div className="App">
<Graph />
</div>
);
}
export default App;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.