简体   繁体   English

如何将大图平滑渲染为 react.js 组件?

[英]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 .第一个是调整图形属性,如nslimitmaxitersplines 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". osagetwopi通常要快得多,但他们也会用它来换取“吸引力”。 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 :其他注意事项

  • You should probably add overlap=false;您可能应该添加overlap=false; to your graph attributes to ensure nodes don't overlap and remain somewhat readable.到您的图形属性,以确保节点不重叠并保持一定的可读性。
  • For the most idiomatic React code and to prevent potential bugs from rerenders, save the SVG string to the component state, and use dangerouslySetInnerHTML to render it.对于最惯用的 React 代码并防止潜在的错误重新渲染,将 SVG 字符串保存到组件 state,并使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM