viz.jsをReactを利用する

累計閲覧数 323 PV

viz.jsとは

GraphVizemscriptenでビルドしたブラウザ用のwrapperライブラリ。

GitHubのリポジトリはArchiveされてしまっているが、npm(https://www.npmjs.com/package/viz.js)の方にはライブラリが存在するので、いまもインストールできる。

Install

yarn add viz.js

使い方

API(https://github.com/mdaines/viz.js/wiki/API)に大体書いてあるけれど、Interface化したものをここに残しておく。

// types/viz.js/index.d.ts
declare module "viz.js" {
  interface VizOption {
    workerURL?: string;
    worker?: any;
    Module?: Function;
    render?: Function;
  }
  interface Image {
    path: string;
    width: string;
    height: string;
  }
  interface File {
    path: string;
    data: string;
  }
  interface RenderOption {
    engine?: string;
    format: "svg", "dot", "xdot", "plain", "plain-ext", "ps", "ps2", "json", "json0";
    yInvert?: boolean;
    images?: Image[];
    files?: File[];
    nop?: number;
  }
  interface RenderImageElementOption {
    scale?: number;
    mimeType?: string;
    quality?: number;
  }
  declare class Viz {
      constructor(option: VizOption);
      renderString(src: string, option?: RenderOption): Promise<string>;
      renderSVGElement(src: string, option?: RenderOption): Promise<HTMLElement>;
      renderImageElement(src: string, option?: RenderImageElementOption): Promise<string>;
      renderJSONObject(src: string, option?: RenderImageElementOption): Promise<Object>;
  }
  export default Viz;
}

declare module "viz.js/full.render.js" {
  export declare function Module () {};
  export declare function render () {};
}

tsconfig.jsoncompilerOptions.typeRootsに追加することで、型定義が有効になる。

Reactでviz.jsを利用する

renderSVGElementを利用したくなるが、Reactが監視できないので、renderStringを変わりに利用する。 ただのHTMLのstringとしてdangerouslySetInnerHTMLにわたすことでrenderingを実現できる。

import React from "react";
import Viz from "viz.js";
import { Module, render } from "viz.js/full.render.js";

export const AppRouter = () => {
  const viz = new Viz({ Module, render });
  const [element, updateElement] = React.useState("");
  React.useEffect(() => {
    const f = async () => {
      const elem: string = await viz.renderString("digraph { a -> b }");
      updateElement(elem);
    };
    f().catch(console.error);
  });
  return (
    <div
      dangerouslySetInnerHTML={{
        __html: element,
      }}
    ></div>
  );
};