GithubHelp home page GithubHelp logo

fleipold / viz.js Goto Github PK

View Code? Open in Web Editor NEW

This project forked from aduh95/viz.js

0.0 1.0 0.0 13.76 MB

A hack to put Graphviz on the web.

Home Page: http://aduh95.github.io/viz.js-playground/

License: MIT License

JavaScript 41.11% HTML 1.19% Makefile 26.16% C++ 3.92% TypeScript 27.62%

viz.js's Introduction

Viz.js

CI NPM version License MIT

This project builds Graphviz with Emscripten and provides a simple wrapper for using it in the browser.

See Also

Have a look at Dagre, which is not a hack.

Usage

Getting Viz.js

Node.js

N.B.: This library has been fully tested with Node.js 12 LTS and Node.js 13.2+. If you need support for older versions of Node.js (E.G.: 10.x), you should restrict the use of viz.js to the synchronous API only.

import Viz from "@aduh95/viz.js";
import getWorker from "@aduh95/viz.js/worker";

const worker = getWorker();
const viz = new Viz({ worker });

viz
  .renderString("digraph{1 -> 2 }")
  .then((svgString) => {
    console.log(svgString);
  })
  .catch((error) => {
    console.error(error);
  })
  .finally(
    () =>
      // You can either terminate explicitly:
      viz.terminateWorker()
    // or let it be auto-closed at the end of the process
  );

If you want to use it from a CommonJS script, you can use the @aduh95/viz.js/async wrapper shortcut:

const dot2svg = require("@aduh95/viz.js/async");

dot2svg("digraph{1 -> 2 }")
  .then((svgString) => {
    console.log(svgString);
  })
  .catch((error) => {
    console.error(error);
  });

Note: If you want to your lib to be web-ready, it is recommended to build up from the first code example rather than the CommonJS one.

Synchronous API

There is a synchronous version of renderString method available:

const vizRenderStringSync = require("@aduh95/viz.js/sync");

console.log(vizRenderStringSync("digraph{1 -> 2 }"));

Key differences with async API:

  • It compiles Graphviz to JavaScript instead of WebAssembly, this should come with a performance hit and a bigger bundled file size (brotli size is 27% bigger).
  • It is a CommonJS module, while the rest of the API is written as standard ECMAScript modules. The upside is this syntax is supported on a wider Node.js version array.

Note: Using the sync API on the browser main thread is not recommended, it might degrade the overall user experience of the web page. It is strongly recommended to use web workers โ€“ with the sync or the async API.

Browsers

Using a bundler

You can either use the worker or the workerURL on the constructor. Note that when using workerURL, Viz constructor will try to spawn a webworker using type=module. If you don't want a module worker, you should provide a worker instead.

The Worker module exports a function that takes an Emscripten Module object. You can use that to tweak the defaults, the only requirement is to define a locateFile method that returns the URL of the WASM file.

// worker.js
import initWASM from "@aduh95/viz.js/worker";
// If you are not using a bundler that supports package.json#exports
// use "./node_modules/@aduh95/viz.js/dist/render.browser.js" instead.

// You need to configure your bundler to treat `.wasm` file as file to return a URL.
import wasmURL from "@aduh95/viz.js/wasm";
// With Rollup, use the `@rollup/plugin-url` plugin and add `**/*.wasm` to the
// `include` list in the plugin config.
// With Webpack, use the `file-loader` plugin: "file-loader!@aduh95/viz.js/wasm"

// If you are not using a bundler that supports package.json#exports
// or doesn't have a file-loader plugin to get URL of the asset:
// const wasmURL =
//   new URL("./node_modules/@aduh95/viz.js/dist/render.wasm", import.meta.url);

initWASM({
  locateFile() {
    return wasmURL;
  },
});

And give feed that module to the main thread:

//main.js
import Viz from "@aduh95/viz.js";
// If you are not using a bundler that supports package.json#exports:
// import Viz from "./node_modules/@aduh95/viz.js/dist/index.mjs";

// If you are using Rollup, use `@surma/rollup-plugin-off-main-thread` plugin.
// If you are using Webpack, use the `worker-loader` plugin and add this import:
// import VizWorker from "worker-loader!./worker.js";

let viz;
async function dot2svg(dot, options) {
  if (viz === undefined) {
    // No-bundler / auto-bundling version:
    viz = new Viz({
      worker: new Worker(new URL("./worker.js", import.meta.url), {
        type: "module",
      }),
    });
    // or if you are using Webpack:
    // viz = new Viz({ worker: new VizWorker() });
  }
  return viz.renderString(dot, options);
}

Using a CDN

If you are using a CDN and don't want a separate file for the worker module, there is a workaround:

import Viz from "https://unpkg.com/@aduh95/viz.js";

const locateFile = (fileName) =>
  "https://unpkg.com/@aduh95/viz.js/dist/" + fileName;
const onmessage = async function (event) {
  if (this.messageHandler === undefined) {
    // Lazy loading actual handler
    const { default: init, onmessage } = await import(
      Module.locateFile("render.browser.js")
    );
    // Removing default MessageEvent handler
    removeEventListener("message", onmessage);
    await init(Module);
    this.messageHandler = onmessage;
  }
  return this.messageHandler(event);
};
const vizOptions = {
  workerURL: URL.createObjectURL(
    new Blob(
      [
        "const Module = { locateFile:",
        locateFile.toString(),
        "};",
        "onmessage=",
        onmessage.toString(),
      ],
      { type: "application/javascript" }
    )
  ),
};

async function dot2svg(dot, options) {
  const viz = new Viz(vizOptions);

  return viz.renderString(dot, options);
}

If you want to support browsers that do not support loading webworker as module, or want a custom message handling, you can use dynamic imports to help you:

// worker.js
/**
 * Lazy-loads Viz.js message handler
 * @returns {(event: MessageEvent) => Promise<any>}
 */
function getVizMessageHandler() {
  if (this._messageHandler === undefined) {
    const vizDistFolder = "https://unpkg.com/@aduh95/viz.js/dist";
    const Module = {
      // locateFile is used by render module to locate WASM file.
      locateFile: (fileName) => `${vizDistFolder}/${fileName}`,
    };
    this._messageHandler = import(Module.locateFile("render.browser.js")).then(
      ({ default: init, onmessage }) => {
        // to avoid conflicts, disable viz.js message handler
        self.removeEventListener("message", onmessage);

        return init(Module).then(() => onmessage);
      }
    );
  }
  return this._messageHandler;
}

self.addEventListener("message", (event) => {
  if (event.data.id) {
    // handling event sent by viz.js
    getVizMessageHandler()
      .then((onmessage) => onmessage(event))
      .catch((error) => {
        // handle dynamic import error here
        console.error(error);

        // Note: If an error is emitted by Viz.js internals (dot syntax error,
        // WASM file initialization error, etc.), the error is catch and sent
        // directly through postMessage.
        // If you think this behavior is not ideal, please open an issue.
      });
  } else {
    // handle other messages
  }
});

Deno

The support is experimental. You would probably need to monkey-patch the unimplemented web APIs. Please check the test folder for an example of implementation.

As Deno aims to expose all the web API, you can use the browser implementation.

Building From Source

To build from source, first install the Emscripten SDK. You'll also need Node.js 13+ and Deno to run the tests.

Using Homebrew (macOS or GNU/Linux):

brew install automake bison libtool node pkg-config

Note: Emscripten version number is pinned in the Makefile. If you are willing to use a different version, you'd need to change the Makefile variable to match the version you are using.

You will certainly need to tweak config files to make sure your system knows where it should find each binary.

The build process for Viz.js is split into two parts: building the Graphviz and Expat dependencies, and building the rendering script files and API.

EMCONFIGURE=emconfigure make deps
emmake make all -j4
emmake make test

viz.js's People

Contributors

mdaines avatar aduh95 avatar ivangoncharov avatar fliegendewurst avatar gordonwoodhull avatar jed avatar ryepup avatar cyshi avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.