Giter Club home page Giter Club logo

hpcc-js-wasm's Introduction

@hpcc-js/wasm - Version 2

Tests Coverage Status

Note: @hpcc-js/wasm is now an ESM by default package - this is a good thing, but does require some breaking changes.

This repository contains a collection of useful c++ libraries compiled to WASM for (re)use in Node JS, Web Browsers and JavaScript Libraries:

Built with:

Homepage and Documents

Quick Start

import { Base91, Graphviz, Zstd } from "@hpcc-js/wasm";

// Graphviz  ---
async function dot2svg() {
    const graphviz = await Graphviz.load();
    console.log("svg:  ", graphviz.dot('digraph G { Hello -> World }'));
}

dot2svg();

// Base91 + Zstd ---
const text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi.  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi.";
const data = new TextEncoder().encode(text);

async function compressDecompress() {
    const zstd = await Zstd.load();
    const compressed_data = zstd.compress(data);
    const base91 = await Base91.load();
    const base91Str = base91.encode(compressed_data);

    const compressed_data2 = base91.decode(base91Str);
    const data2 = zstd.decompress(compressed_data2);
    const text2 = new TextDecoder().decode(data2);

    console.log("Text Length:  ", text.length);
    console.log("Compressed Length:  ", compressed_data.length);
    console.log("Base91 Length:  ", base91Str.length);
    console.log("Passed:  ", text === text2);
}

compressDecompress();

Quick Migration from v1

v1.x.x

import { graphviz, wasmFolder } from "@hpcc-js/wasm";

wasmFolder("https://cdn.jsdelivr.net/npm/@hpcc-js/wasm/dist");

const dot = "digraph G { Hello -> World }";

graphviz.dot(dot).then(svg => {
    const div = document.getElementById("placeholder");
    div.innerHTML = svg;    
});

graphvizVersion.then(version => console.log(version));

v2.x.x

import { Graphviz } from "@hpcc-js/wasm";

const dot = "digraph G { Hello -> World }";

Graphviz.load().then(graphviz => {
    const svg = graphviz.dot(dot);
    const div = document.getElementById("placeholder");
    div.innerHTML = svg;    

    console.log(graphviz.version());
});

Notes:

  • wasmFolder is no longer needed
  • All wasm libraries have the same asynchronous load pattern
    • const instance = await <Wasm>.load();

hpcc-js-wasm's People

Contributors

akbo avatar dependabot[bot] avatar gordonsmith avatar inokawa avatar magjac avatar sreejitstrob avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hpcc-js-wasm's Issues

A question about your project structure

Hi,

I am working on creating a wasm library which user is able to load in node, vanila js and react! So far the build environment is working however I have a couple of issues which I came across your project here and it seems your project solved those issues. I have a few questions I appreciate your help about them!

Once we compile our project with emscripten it generates a wasm and js file. I was wondering how are you loading wasm files into different environments? I see there is a loader interface available but it is a bit unclear to me where and how wasm files are loaded. Can you please give me some ideas about structure of the loading process?

Thanks!

Is it possible to pass options to the layout engine ?

Hi,

I need to pass the -n2 option to neato.
I tried something like

$ dot-wasm -K neato -n2 pack.dot > out.svg
But I don't have the right result.

With graphviz I have this command :

$ neato -n2 pack.dot -Tsvg > out.svg

that gives :
out

If I don't pass the n2 option I have the wrong result ( same as dot-wasm -K neato -n2 pack.dot > out.svg)
$ neato pack.dot -Tsvg > out.svg
without-n2

the input file:
pack.txt

thanks

Second API to set WASM URLs

I'm compiling my application using vite.

It offers several options to get the final URL of a code file. However, it does not offer the possibility to get the path to an unprocessed folder (except public/).

WASM can be directly imported:
https://vitejs.dev/guide/features.html#webassembly=

And there are multiple options on referencing single files:
https://vitejs.dev/guide/assets.html

The file name of graphvizlib.wasm might change during bundling (it appends a hash, so that browsers can make better use of caching in case of updates).
However, this causes hpcc-js to not finding the graphvizlib.

Is there any chance we get an API to provide the path to the WASM file directly (instead of the folder)?
For example, something like this would fit the bill:

import graphvizLibUrl from "@hpcc-js/wasm/dist/graphvizlib.wasm?url";
import expatlibUrl from "@hpcc-js/wasm/dist/expatlib.wasm?url";
import { provideWasmUrls } from "@hpcc-js/wasm";

provideWasmUrls({
	"graphvizlib": graphvizLibUrl,
	"expatlib": expatlibUrl,
});

Maybe this could be used to set some URLs explicitly, using wasmFolder as a fallback in case the library was not found on the object.

IMG tag inside HTML-like table breaks engine (node definition does not appear in graph)

When I use an IMG tag inside a HTML-like label then the whole label seems to be ignored by the hpcc-wasm engine.

The same structure of DOT code is working well with native dot binary. Currently I am in the process of porting a visualization system from Bash with native dot to ECMAscript. What am I doing wrong?

Here is a screenshot of my reproducer:
image

Here is the HTML sourcecode of my reproducer:

<!-- Content-Type: application/xhtml+xml -->
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" >
<body>
    <div id="1">1</div> 1. proves that these images are working with hpcc-wasm
    <hr />
    <div id="2">2</div> 2. shows the desired structure (HTML-like labels, here with 'x' and 'y' instead of IMG tags)
    <hr />
    <div id="3">3</div> 3. demonstrates the problem with hpcc-wasm, where the IMG tags (the only difference to case 2.) seem to break the engine and make the nodes appear as if they had not been defined. The images sources used here are exactly those from case 1. The DOT source from 3. works fine with GraphViz's native dot binary if the image paths are translated to local (filesystem) paths.
    <hr />
    <div id="4">4</div> 4. a desparate attempts to see whether an image is supported inside a record-based label, which is not the case
    <script type="module">

const dot_sample_img=`digraph G { node[shape=box]
x[label="" image="https://knowhere.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10316" ]
y[label="" image="https://knowhere.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/11502" ]
x -> y
}`;

const dot_record_img=`digraph G { node[shape=record]
x[label="image='https://knowhere.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10316'|y" ]
}`;

const dot_no_images = `digraph Map { node[shape=box]
<META-2> [ label=
<<TABLE BORDER="0" CELLSPACING="0">
 <TR>
  <TD WIDTH="18" HEIGHT="18" FIXEDSIZE="TRUE" CELLPADDING="0" VALIGN="TOP" HREF="https://knowhere.atlassian.net/issues/?jql=type=5+ORDER+BY+summary">
  x
  </TD>
  <TD COLSPAN='3'><B>Unteraufgabe</B></TD>
 </TR>
 <TR>
  <TD HREF="https://knowhere.atlassian.net/issues/?jql=type=5+ORDER+BY+summary" COLSPAN="2" SIDES="LBR" ALIGN="LEFT"><I><FONT POINT-SIZE='8'>Sub-task</FONT></I></TD>
  <TD><FONT POINT-SIZE='8'>besteht</FONT></TD>
  <TD ALIGN='RIGHT'><FONT POINT-SIZE='8'>META-2</FONT></TD>
</TR>
</TABLE>> URL="https://knowhere.atlassian.net/browse/META-2" ]
<META-1> [ label=
<<TABLE BORDER="0" CELLSPACING="0">
 <TR>
  <TD WIDTH="18" HEIGHT="18" FIXEDSIZE="TRUE" CELLPADDING="0" VALIGN="TOP" HREF="https://knowhere.atlassian.net/issues/?jql=type=10627+ORDER+BY+summary">
  y
  </TD>
  <TD COLSPAN='3'><B>Ding</B></TD>
 </TR>
 <TR>
  <TD HREF="https://knowhere.atlassian.net/issues/?jql=type=10627+ORDER+BY+summary" COLSPAN="2" SIDES="LBR" ALIGN="LEFT"><I><FONT POINT-SIZE='8'>Ding</FONT></I></TD>
  <TD><FONT POINT-SIZE='8'>besteht</FONT></TD>
  <TD ALIGN='RIGHT'><FONT POINT-SIZE='8'>META-1</FONT></TD>
</TR>
</TABLE>> URL="https://knowhere.atlassian.net/browse/META-1" ]
<META-2> -> <META-1>
}`;
const dot_yes_images = `digraph Map { node[shape=box]
<META-2> [ label=
<<TABLE BORDER="0" CELLSPACING="0">
 <TR>
  <TD WIDTH="18" HEIGHT="18" FIXEDSIZE="TRUE" CELLPADDING="0" VALIGN="TOP" HREF="https://knowhere.atlassian.net/issues/?jql=type=5+ORDER+BY+summary">
   <IMG SRC="https://knowhere.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10316" />
  </TD>
  <TD COLSPAN='3'><B>Unteraufgabe</B></TD>
 </TR>
 <TR>
  <TD HREF="https://knowhere.atlassian.net/issues/?jql=type=5+ORDER+BY+summary" COLSPAN="2" SIDES="LBR" ALIGN="LEFT"><I><FONT POINT-SIZE='8'>Sub-task</FONT></I></TD>
  <TD><FONT POINT-SIZE='8'>besteht</FONT></TD>
  <TD ALIGN='RIGHT'><FONT POINT-SIZE='8'>META-2</FONT></TD>
</TR>
</TABLE>> URL="https://knowhere.atlassian.net/browse/META-2" ]
<META-1> [ label=
<<TABLE BORDER="0" CELLSPACING="0">
 <TR>
  <TD WIDTH="18" HEIGHT="18" FIXEDSIZE="TRUE" CELLPADDING="0" VALIGN="TOP" HREF="https://knowhere.atlassian.net/issues/?jql=type=10627+ORDER+BY+summary">
   <IMG SRC="https://knowhere.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/11502" />
  </TD>
  <TD COLSPAN='3'><B>Ding</B></TD>
 </TR>
 <TR>
  <TD HREF="https://knowhere.atlassian.net/issues/?jql=type=10627+ORDER+BY+summary" COLSPAN="2" SIDES="LBR" ALIGN="LEFT"><I><FONT POINT-SIZE='8'>Ding</FONT></I></TD>
  <TD><FONT POINT-SIZE='8'>besteht</FONT></TD>
  <TD ALIGN='RIGHT'><FONT POINT-SIZE='8'>META-1</FONT></TD>
</TR>
</TABLE>> URL="https://knowhere.atlassian.net/browse/META-1" ]
<META-2> -> <META-1>
}`;

	const images=[	{ path:
  "https://knowhere.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10316"
				, width: "32px", height: "32px" }
			 ,
			{ path:
  "https://knowhere.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/11502"
			    	, width: "32px", height: "32px" }
		    ]

        import { Graphviz } from "https://cdn.jsdelivr.net/npm/@hpcc-js/wasm/dist/index.js";
        const graphviz = await Graphviz.load();
        layout (	dot_sample_img,	"1" );
	layout (	dot_no_images,	"2" );
        layout (	dot_yes_images,	"3" );
        layout (	dot_record_img,	"4" );

function layout( dot, domId )
{
    document.getElementById(domId).innerHTML =  graphviz.dot (	dot,	"svg", {   images: images });
}

</script>
</body>
</html>

Graphviz Library does not scale to meet layout w/ 1000 nodes +

I wanted to use the wasm implementation of graphviz instead of the deprecated dagre.js in order to generate a dot layout for 1000+ node graph (the idea being that graphviz is far more universal than dagre, and could be pre-computed in a variety of backends). After a few seconds of processing the layout I get the following:

graphviz.ts:153 Uncaught (in promise) Error: Maximum call stack size exceeded
    at Q.layout (graphviz.ts:153:19)

It's clear from the below layout function that this is due to graphviz calling it's layout function recursively:

layout(dotSource: string, outputFormat: Format = "svg", layoutEngine: Engine = "dot", options?: Options): string {
        if (!dotSource) return "";
        const graphViz = new this._module.Graphviz(options?.yInvert ? 1 : 0, options?.nop ? options?.nop : 0);
        let retVal = "";
        let errorMsg = "";
        try {
            createFiles(graphViz, options);
            try {
                retVal = graphViz.layout(dotSource, outputFormat, layoutEngine);
            } catch (e: any) {
                errorMsg = e.message;
            };
            errorMsg = graphViz.lastError() || errorMsg;
        } finally {
            this._module.destroy(graphViz);
        }
        if (!retVal && errorMsg) {
            Graphviz.unload();
            throw new Error(errorMsg);
        }
        return retVal;
    }

There is not really a reason to use wasm if it is not more performant in the browser than it's sibling js implementations! Just something to keep in mind while building this project.

Demo with graphvizSync not working

The following demo has JS errors:
https://raw.githack.com/hpcc-systems/hpcc-js-wasm/trunk/hw-graphviz.html

I'm not sure if the demo is linked, so it may not matter, but I bring it up since my own website had the same issues, and perhaps I originally got the code from that demo or a similar one.

Here's the commit I made to fix my site:
pamelafox/recursive-visualizations@446a8b6

A similar change could be made to that demo, or it could be deleted. I'm not sure what changed, I think it must have been a fairly recent change.

Thanks!

Adding `gvpack`

Heya, is it much work to add gvpack as a WASM library?

It's a standalone binary:

Which I suppose means the parts of the code that aren't main / arg parsing would have to be split into a library before it can be compiled to WASM.

Shouldn't the enums and interfaces be exported?

Discussed in #91

Originally posted by Vithanco February 5, 2022
My code cannot fully use these declarations as they are not exported:

declare type Format = "svg" | "dot" | "json" | "dot_json" | "xdot_json" | "plain" | "plain-ext";
declare type Engine = "circo" | "dot" | "fdp" | "sfdp" | "neato" | "osage" | "patchwork" | "twopi";
interface Image {
    path: string;
    width: string;
    height: string;
}
interface File {
    path: string;
    data: string;
}
interface Ext {
    images?: Image[];
    files?: File[];
    wasmFolder?: string;
    wasmBinary?: Uint8Array;
    yInvert?: boolean;
    nop?: number;
}

Is that an oversight or do I not understand how to use the library? Background: I am creating a wrapper for your Wasm that will fit my needs (based on JSON output) and I realised that I cannot create a wrapper with the same types as these types aren't exported.

Import fails

Importing the minified distribution fails.

index.min.js:1 Uncaught (in promise) RuntimeError: abort(LinkError: WebAssembly.instantiate(): Import #45 module="a" function="T" error: function import requires a callable). Build with -s ASSERTIONS=1 for more info.
    at L (https://cdn.jsdelivr.net/npm/@hpcc-js/wasm/dist/index.min.js:1:54376)
    at https://cdn.jsdelivr.net/npm/@hpcc-js/wasm/dist/index.min.js:1:104280

Steps to reproduce:

  1. Copy HTML from https://github.com/hpcc-systems/hpcc-js-wasm#hello-world
  2. Save to file
  3. Open file in a browser

Output PNG?

Can this be extended to include PNG Graphviz output? Would be nice to enable that for an offline environment.

Import error in TypeScript

When trying to import zstd this way:

import { Zstd } from '@hpcc-js/wasm/zstd';

I am getting:

src/shared/S3Bucket.ts:1:22 - error TS1479: The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'. Consider writing a dynamic 'import("@hpcc-js/wasm/zstd")' call instead.
  To convert this file to an ECMAScript module, change its file extension to '.mts', or add the field `"type": "module"` to '/Users/aleksander/Documents/GitRepos/ais-s3-compactor/package.json'.

Things I tried:

  • change type to module in my package.json as the error suggets but then I get bazillion errors related to all my imports,
  • use const Zstd = import('@hpcc-js/wasm/zstd'); as the error suggets but then I get Zstd.load is not a function,
  • try different package versions: 2.5.0 and 2.1.1.

Things I know:

  • I read TypeScript notes in the readme and I updated "moduleResolution": "Node16".

Specs:

  • Mac M1,
  • Node v19.6.0,
  • @hpcc-js/wasm 2.8.0,
  • ts 4.8.4.

Graphviz Feature "HTML Like Tables" on Ubuntu 22.04 and Android

The Graphviz feature "HTML Like Tables" doesn't work correctly with the preinstalled version of Firefox (the snap version) of the actual LTS (22.04) of Ubuntu. For boxes with text, the text is too large and partly misplaced outside the boxes (scrrenshot).

To reproduce, take a fresh install of Ubuntu 22.04 (or boot it from an installation media), go to https://observablehq.com/@gordonsmith/graphviz and scroll down to "HTML Like Tables".

The problem doesn't occur with the tarball version, the repo-version (ppa:mozillateam/ppa) or the flatpack version of Firefox and I coudn't find any other browser on Windows or Ubuntu where this problem occurs.

But I also tested it on two Android phones (Nexus 5X Android 8.1 with Firefox and Chrome and Mi A3 with Opera and Chrome) and on Pixel 5 API 30 emulator of Android Studio with Webview Browser Tester, there this problem also occurs (with all tested browsers).

Auswahl_001

trailing commas issue with Graphviz json output

When only have subgraph with fdp layout with cause the trailing commas issue.

  1. here is Graphviz source code
digraph TicketBooking {
  component=true;layout=fdp;
  node [shape=box style=filled];
  cluster_reservation -> cluster_cinema;
  cluster_reservation -> cluster_movie;
  cluster_reservation -> cluster_user;

  subgraph cluster_cinema {
    label="Cinema(Context)";
  }

  subgraph cluster_movie {
    label="Movie(Context)";
  }

  subgraph cluster_reservation {
    label="Reservation(Context)";
  }

  subgraph cluster_user {
    label="User(Context)";
  }
}
  1. test code:
let output = await graphvizSync().then(async (graph) => {
  return graph.layout(this.content, "json");
});

try {
  fs.writeFileSync("output.json", output);
  output = JSON.parse(output.trim());
} catch (e) {
  console.log(e);
}
  1. output error in edges:
      "_gvid": 3
    },

  ],
  "edges": [
    {
      "_gvid": 0,
      "tail": 0,
      "head": 1,
      "_draw_": 

the process random freezes on the graphviz

the process random freezes on the graphviz
call function
graphviz.dot(dot, "json", { images, yInvert: true });

empty log

I attach stably repeating freezes

digraph {
    graph [TBbalance=min,
        bgcolor=transparent,
        compound=true,
        fontname=Helvetica,
        fontsize=13,
        labeljust=l,
        labelloc=t,
        layout=dot,
        margin=33.21,
        nodesep=1.25,
        outputorder=nodesfirst,
        pack=90,
        packmode=array_3,
        penwidth=1,
        rankdir=TB,
        ranksep=1.25,
        searchsize=50,
        splines=spline
    ];
    node [color="#2563eb",
        fillcolor="#3b82f6",
        fontcolor="#eff6ff",
        fontname=Helvetica,
        fontsize=20,
        height=2.5,
        margin=0.362,
        penwidth=0,
        shape=rect,
        style=filled,
        width=4.445
    ];
    edge [color="#6E6E6E",
        fontcolor="#C6C6C6",
        fontname=Helvetica,
        fontsize=13,
        penwidth=2,
        style=""
    ];
    subgraph cluster_pf {
        graph [color="#1b3d88",
            fillcolor="#194b9e",
            fontcolor="#bfdbfeb3",
            label=<<B>PF</B>>,
            likec4_depth=1,
            likec4_id="dm.pf",
            likec4_level=0,
            margin=32,
            style=filled
        ];
        lpf [label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="25"><FONT POINT-SIZE="20" COLOR="#eff6ff">platform</FONT></TD></TR></TABLE>>,
            likec4_id="dm.pf.lpf",
            likec4_level=1];
    }
    subgraph cluster_qwer {
        graph [color="#0b3c57",
            fillcolor="#0d4b6c",
            fontcolor="#b6ecf7b3",
            label=<<B>qwer</B>>,
            likec4_depth=1,
            likec4_id=qwer,
            likec4_level=0,
            margin=32,
            style=filled
        ];
        abservice [fillcolor="#0284c7",
            label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="25"><FONT POINT-SIZE="20" COLOR="#f0f9ff">IAP</FONT></TD></TR></TABLE>>,
            likec4_id="qwer.abservice",
            likec4_level=1];
    }
    subgraph cluster_uMs {
        graph [color="#1b3d88",
            fillcolor="#194b9e",
            fontcolor="#bfdbfeb3",
            label=<<B>XXXXXXX AY</B>>,
            likec4_depth=1,
            likec4_id="dm.uMs",
            likec4_level=0,
            margin=32,
            style=filled
        ];
        poiuuMs [label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="5"><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="25"><FONT POINT-SIZE="20" COLOR="#eff6ff">poiu-uMs</FONT></TD></TR></TABLE></TD></TR><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="16"><FONT POINT-SIZE="14" COLOR="#bfdbfe">text</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
            likec4_id="dm.uMs.poiuuMs",
            likec4_level=1];
    }
    subgraph cluster_tyu {
        graph [color="#1b3d88",
            fillcolor="#194b9e",
            fontcolor="#bfdbfeb3",
            label=<<B>tyu</B>>,
            likec4_depth=1,
            likec4_id="dm.tyu",
            likec4_level=0,
            margin=32,
            style=filled
        ];
        poiutyuAuth [group="dm.tyu",
            label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="5"><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="25"><FONT POINT-SIZE="20" COLOR="#eff6ff">poiu-tyu-Auth</FONT></TD></TR></TABLE></TD></TR><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD><FONT POINT-SIZE="12" COLOR="#bfdbfe">Java, Spring Boot</FONT></TD></TR></TABLE></TD></TR><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="16"><FONT POINT-SIZE="14" COLOR="#bfdbfe">service</FONT></TD></TR>,<TR><TD VALIGN="BOTTOM" HEIGHT="16"><FONT POINT-SIZE="14" COLOR="#bfdbfe">update</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
            likec4_id="dm.tyu.poiutyuAuth",
            likec4_level=1];
        poiutyustate [group="dm.tyu",
            label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="5"><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="25"><FONT POINT-SIZE="20" COLOR="#eff6ff">poiu-tyu-state</FONT></TD></TR></TABLE></TD></TR><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD><FONT POINT-SIZE="12" COLOR="#bfdbfe">Java, Spring Boot</FONT></TD></TR></TABLE></TD></TR><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="16"><FONT POINT-SIZE="14" COLOR="#bfdbfe">service</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
            likec4_id="dm.tyu.poiutyuState",
            likec4_level=1];
        poiutyuAuth -> poiutyustate [likec4_id="dm.tyu.poiutyuAuth:dm.tyu.poiutyuState",
            style=dashed];
        poiutyucancel [group="dm.tyu",
            label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="5"><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="25"><FONT POINT-SIZE="20" COLOR="#eff6ff">poiu-tyu-cancel</FONT></TD></TR></TABLE></TD></TR><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD><FONT POINT-SIZE="12" COLOR="#bfdbfe">Java, Spring Boot</FONT></TD></TR></TABLE></TD></TR><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="16"><FONT POINT-SIZE="14" COLOR="#bfdbfe">service</FONT></TD></TR>,<TR><TD VALIGN="BOTTOM" HEIGHT="16"><FONT POINT-SIZE="14" COLOR="#bfdbfe">xxx</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
            likec4_id="dm.tyu.poiutyuCancel",
            likec4_level=1];
        poiutyucancel -> poiutyustate [likec4_id="dm.tyu.poiutyuCancel:dm.tyu.poiutyuState",
            style=dashed];
        poiutyustatedb [group="dm.tyu",
            imagescale=true,
            label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="5"><TR><TD ALIGN="CENTER" HEIGHT="32"><IMG SRC="https://poiu.org/img/cassandra.svg" SCALE="TRUE"/></TD></TR><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="25"><FONT POINT-SIZE="20" COLOR="#eff6ff">State Cassandra DB</FONT></TD></TR></TABLE></TD></TR><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="16"><FONT POINT-SIZE="14" COLOR="#bfdbfe">DB tyu</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
            likec4_id="dm.tyu.poiutyuStateDb",
            likec4_level=1,
            margin="0.362,0.417",
            penwidth=2,
            shape=cylinder];
        poiutyustate -> poiutyustatedb [label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="4"><TR><TD WIDTH="2"></TD><TD><TABLE ALIGN="LEFT" BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">read</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
            likec4_id="dm.tyu.poiutyuState:dm.tyu.poiutyuStateDb",
            minlen=1,
            style=dashed];
        poiuyytttyuAuthfallbackraw [group="dm.tyu",
            height=2.223,
            label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="5"><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="25"><FONT POINT-SIZE="20" COLOR="#eff6ff">poiu.yytt.tyu-Auth.fallback.raw</FONT></TD></TR></TABLE></TD></TR><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD><FONT POINT-SIZE="12" COLOR="#bfdbfe">Kafka</FONT></TD></TR></TABLE></TD></TR><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="16"><FONT POINT-SIZE="14" COLOR="#bfdbfe">Queue</FONT></TD></TR>,<TR><TD VALIGN="BOTTOM" HEIGHT="16"><FONT POINT-SIZE="14" COLOR="#bfdbfe">items</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
            likec4_id="dm.tyu.poiuyytttyuAuthFallbackRaw",
            likec4_level=1,
            margin="0.417,0.362"];
        poiutyustate -> poiuyytttyuAuthfallbackraw [label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="4"><TR><TD WIDTH="2"></TD><TD><TABLE ALIGN="LEFT" BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">retry</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
            likec4_id="dm.tyu.poiutyuState:dm.tyu.poiuyytttyuAuthFallbackRaw",
            minlen=1,
            style=dashed];
        poiuyytttyuAuthfallbackretryraw [group="dm.tyu",
            height=2.223,
            label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="5"><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="25"><FONT POINT-SIZE="20" COLOR="#eff6ff">poiu.yytt.tyu-Auth.fallback.retry.raw</FONT></TD></TR></TABLE></TD></TR><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD><FONT POINT-SIZE="12" COLOR="#bfdbfe">Kafka</FONT></TD></TR></TABLE></TD></TR><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="16"><FONT POINT-SIZE="14" COLOR="#bfdbfe">retry</FONT></TD></TR>,<TR><TD VALIGN="BOTTOM" HEIGHT="16"><FONT POINT-SIZE="14" COLOR="#bfdbfe">state</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
            likec4_id="dm.tyu.poiuyytttyuAuthFallbackRetryRaw",
            likec4_level=1,
            margin="0.417,0.362"];
        poiutyustate -> poiuyytttyuAuthfallbackretryraw [label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="4"><TR><TD WIDTH="2"></TD><TD><TABLE ALIGN="LEFT" BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">read</FONT></TD></TR>,<TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">xxxxxxxxxxx</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
            likec4_id="dm.tyu.poiutyuState:dm.tyu.poiuyytttyuAuthFallbackRetryRaw",
            minlen=1,
            style=dashed];
    }
    subgraph cluster_yytt {
        graph [color="#1b3d88",
            fillcolor="#194b9e",
            fontcolor="#bfdbfeb3",
            label=<<B>yytt</B>>,
            likec4_depth=1,
            likec4_id="dm.yytt",
            likec4_level=0,
            margin=32,
            style=filled
        ];
        poiuyytt [label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="5"><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="25"><FONT POINT-SIZE="20" COLOR="#eff6ff">poiu-yytt</FONT></TD></TR></TABLE></TD></TR><TR><TD><TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="16"><FONT POINT-SIZE="14" COLOR="#bfdbfe">Platform</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
            likec4_id="dm.yytt.poiuyytt",
            likec4_level=1];
        poiuyyttretry [height=2.223,
            label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD VALIGN="BOTTOM" HEIGHT="25"><FONT POINT-SIZE="20" COLOR="#eff6ff">poiu.yytt.retry</FONT></TD></TR></TABLE>>,
            likec4_id="dm.yytt.poiuyyttRetry",
            likec4_level=1,
            margin="0.417,0.362"];
    }
    lpf -> poiutyuAuth [label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="4"><TR><TD WIDTH="2"></TD><TD><TABLE ALIGN="LEFT" BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">read</FONT></TD></TR>,<TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">xxxxxxxxxxxxxxx</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
        likec4_id="dm.pf.lpf:dm.tyu.poiutyuAuth",
        style=dashed];
    lpf -> poiutyustate [label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="4"><TR><TD WIDTH="2"></TD><TD><TABLE ALIGN="LEFT" BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">read</FONT></TD></TR>,<TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">xxxxxxx</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
        likec4_id="dm.pf.lpf:dm.tyu.poiutyuState",
        style=dashed];
    abservice -> poiutyuAuth [likec4_id="qwer.abservice:dm.tyu.poiutyuAuth",
        style=dashed];
    abservice -> poiutyucancel [likec4_id="qwer.abservice:dm.tyu.poiutyuCancel",
        style=dashed];
    abservice -> poiutyustate [label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="4"><TR><TD WIDTH="2"></TD><TD><TABLE ALIGN="LEFT" BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">init.</FONT></TD></TR>,<TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
        likec4_id="qwer.abservice:dm.tyu.poiutyuState",
        style=dashed];
    poiuuMs -> poiutyuAuth [label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="4"><TR><TD WIDTH="2"></TD><TD><TABLE ALIGN="LEFT" BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">write</FONT></TD></TR>,<TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">xxxxxxxxxxxxxxxxxxxxx</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
        likec4_id="dm.uMs.poiuuMs:dm.tyu.poiutyuAuth",
        style=dashed];
    poiuuMs -> poiutyustate [label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="4"><TR><TD WIDTH="2"></TD><TD><TABLE ALIGN="LEFT" BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">read uMs</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
        likec4_id="dm.uMs.poiuuMs:dm.tyu.poiutyuState",
        style=dashed];
    poiuuMs -> poiuyytt [lhead=cluster_yytt,
        minlen=1,
        style=invis];
    poiutyuAuth -> abservice [label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="4"><TR><TD WIDTH="2"></TD><TD><TABLE ALIGN="LEFT" BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">read ppoo</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
        likec4_id="dm.tyu.poiutyuAuth:qwer.abservice",
        style=dashed];
    poiutyuAuth -> poiuuMs [label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="4"><TR><TD WIDTH="2"></TD><TD><TABLE ALIGN="LEFT" BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">Init uMs</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
        likec4_id="dm.tyu.poiutyuAuth:dm.uMs.poiuuMs",
        style=dashed];
    poiutyucancel -> abservice [likec4_id="dm.tyu.poiutyuCancel:qwer.abservice",
        style=dashed];
    poiutyustate -> poiuyytt [label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="4"><TR><TD WIDTH="2"></TD><TD><TABLE ALIGN="LEFT" BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">read</FONT></TD></TR>,<TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">xxxxxxxxxxxxx</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
        likec4_id="dm.tyu.poiutyuState:dm.yytt.poiuyytt",
        style=dashed];
    poiutyustate -> poiuyyttretry [label=<<TABLE BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="4"><TR><TD WIDTH="2"></TD><TD><TABLE ALIGN="LEFT" BORDER="0" CELLBORDER="0" CELLPADDING="0" CELLSPACING="0"><TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">write</FONT></TD></TR>,<TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</FONT></TD></TR>,<TR><TD ALIGN="LEFT" VALIGN="BOTTOM" HEIGHT="15"><FONT POINT-SIZE="13">xxxxxxxxx</FONT></TD></TR></TABLE></TD></TR></TABLE>>,
        likec4_id="dm.tyu.poiutyuState:dm.yytt.poiuyyttRetry",
        minlen=1,
        style=dashed];
    poiuyytt -> poiuuMs [lhead=cluster_uMs,
        minlen=1,
        style=invis];
}

Font metrics

Apparently, Graphviz doesn't have access to font metrics other than Courier, Times, Helvetica, and Arial. Is there a way to fix this?

Deploying the wasm through webpack

The docs mention that:

Bundlers (RollupJS / WebPack) will ignore the WASM files, so you will need to manually ensure they are present in your final distribution (typically they are placed in the same folder as the bundled JS)

Is there some official guidelines for what needs to happen with webpack, for example to get the file pushed all the way from node_modules down to some static directory?

angular8 error

core.js:4002 ERROR Error: Uncaught (in promise): RuntimeError: abort(CompileError: WebAssembly.instantiate(): expected magic word 00 61 73 6d, found 2e 2e 2f 2e @+0). Build with -s ASSERTIONS=1 for more info.
RuntimeError: abort(CompileError: WebAssembly.instantiate(): expected magic word 00 61 73 6d, found 2e 2e 2f 2e @+0). Build with -s ASSERTIONS=1 for more info.
at abort (index.es6.js:150)
at index.es6.js:150
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:391)
at Object.onInvoke (core.js:26256)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:390)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.run (zone.js:150)
at zone.js:889
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
at Object.onInvokeTask (core.js:26247)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)
at resolvePromise (zone.js:831)
at zone.js:896
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
at Object.onInvokeTask (core.js:26247)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:195)
at drainMicroTaskQueue (zone.js:601)
defaultErrorLogger @ core.js:4002
client:52 [WDS] Live Reloading enabled.

When I try to laod this in vscode webview I cannot fine the value "@hpcc-js/wasm"

I am trying to use you library in an extension for .NET Interactive notebook.
But when executing the code:

loadHpccWasm_ce83f9987ab8408ab9e5f83540f06609 = () => {
    let container = document.getElementById('ce83f9987ab8408ab9e5f83540f06609');
    const dot = `graph ethane {
    C_0 -- H_0 [type=s];
    C_0 -- H_1 [type=s];
    C_0 -- H_2 [type=s];
    C_0 -- C_1 [type=s];
    C_1 -- H_3 [type=s];
    C_1 -- H_4 [type=s];
    C_1 -- H_5 [type=s];
}`;
            
    let hpccWasm = window['@hpcc-js/wasm'];
    hpccWasm.graphviz.layout(dot, "svg", "dot").then(svg => { container.innerHTML = svg; });
}

if (window["@hpcc-js/wasm"]) {
    loadHpccWasm_ce83f9987ab8408ab9e5f83540f06609();
    } else {
    let hpccWasm_script = document.createElement('script');
    hpccWasm_script.setAttribute('src', 'https://cdn.jsdelivr.net/npm/@hpcc-js/[email protected]/dist/index.min.js');
    hpccWasm_script.setAttribute('type', 'text/javascript');
    hpccWasm_script.setAttribute('defer', 'true');
    hpccWasm_script.onload = () => { loadHpccWasm_ce83f9987ab8408ab9e5f83540f06609(); };
    document.getElementsByTagName('head')[0].appendChild(hpccWasm_script);
}

I get this output
image

the js code is downlaoded but can't invoke api to make this work.

this is the PR I am working on colombod/dotnet-interactive-extension-lab#15.

Anyone can help?

vite failed to load graphvizlib.wasm

// package.json
dependencies: {
"d3-graphviz": "^4.1.1",
}

// my code in vite
graphviz('#flowDiagram', {
useWorker: false,
})
.options({
height: container.offsetHeight,
width: container.offsetWidth,
})
.fit(true)
.renderDot(content);

// throw error: failed to load graphvizlib.wasm
// i have add base vue-route path

How to host .wasm file for client-side application in V2?

Hello!

I'm using @hpcc-js/wasm to generate DOT layouts in my React application. As for V1 i used wasmFolder() with custom URL to load wasm file, but there is not such function in V2, i have to await Graphviz.load() withour specifying URL.

What is preferred way to self-host wasm files in V2?

Provide Unflatten Graphviz Command

I am also interested in an Ecmascript (wasm?) port of Graphviz's unflatten tool.

Here is an example transformation:

graph {
	a -- 1;
	a -- 2;
	a -- 3;
	a -- 4;
	b;
	c;
	d;
	e;
}

unflatten -l 2 -c 1 unflatten-1-before.dot > unflatten-2-after.dot

graph {
	a -- 1	[minlen=1];
	a -- 2	[minlen=2];
	a -- 3	[minlen=1];
	a -- 4	[minlen=2];
	b -- c	[style=invis];
	d -- e	[style=invis];
}

... which looks something like this (styling added), before:

unflatten-1-before
... and after:
unflatten-2-after

Discussed in #71

Originally posted by saulshanabrook June 18, 2021
Does this library support the unflatten graphviz command that is useful for graphs with multiple unconnected parts? For example, it is provided by the a Python wrapper around Graphviz.

Memory access out of bounds error for graphviz layout

Hi All, we are using Graphviz for creating graph layouts on an Angular application.

We've run into the issue that using the .layout() function leads to the error: Error: memory access out of bounds

It seems to appear after running a number of layout queries in a row, but it only seems to fail for json output.

I created a small test environment where it can be reproduced here: https://stackblitz.com/edit/wasm-memory-error . For the error click the button 4 times.

This is the code I'm running:

const graphviz = await Graphviz.load();
const response = graphviz.layout(dotQuery, 'json', 'dot');

Any insights/help/fix would be very welcome!

RangeError when handling large graphs

Hi, I'd like to use this for a project at work and so far it works like a charm, except for one thing.
When handling rather large graphs (>10K nodes) I run into the following error:

RangeError: Maximum call stack size exceeded
    at graphvizlib.wasm:0x40f63
    at graphvizlib.wasm:0x415da
    at graphvizlib.wasm:0x415f4
    at graphvizlib.wasm:0x415f4
    at graphvizlib.wasm:0x415f4
    at graphvizlib.wasm:0x415f4
    at graphvizlib.wasm:0x415f4
    at graphvizlib.wasm:0x415f4
    at graphvizlib.wasm:0x415f4
    at graphvizlib.wasm:0x415f4
    at graphvizlib.wasm:0x415f4
    at graphvizlib.wasm:0x415f4
    at graphvizlib.wasm:0x415f4
    at graphvizlib.wasm:0x415f4
    at graphvizlib.wasm:0x415f4
    at graphvizlib.wasm:0x415f4
    at graphvizlib.wasm:0x415f4
    at graphvizlib.wasm:0x415f4
    at graphvizlib.wasm:0x415f4
    at graphvizlib.wasm:0x415f4

The layout still finishes but only returns part of the graph, rendering the result useless.
I'm currently using Chrome Version 97.0.4692.99 and the graph is a directed acyclic graph.

Is there a way to fix this? I'd look into it myself, but I don't know much about WASM.

Incompatible with content-security-policy without unsafe-eval

Hi! Thanks for maintaining this - I've been using both at work and for personal projects. Great to be able to quickly put together useful graphs.

Recently, I'm using this in an Electron app, which by default has a strict content security policy, blocking eval unless unsafe-eval is explicitly specified, which I wouldn't want to enable for security reasons.

Unfortunately, this line violates the policy, since the Function() constructor is effectively eval.

const globalNS: any = new Function("return this;")();

Perhaps we could use globalThis to get a reference to the global object, no matter the environment, which has decent browser support at this point (aside from IE)? WASM doesn't work in IE11 anyways so we wouldn't be losing much. Not sure if there is much node usage of this module but globalThis was introduced in node 12. The previous node release, 10, is being end-of-lifed on 2021-04-30.


Let me know and I could make a PR for it!

SyntaxError: Named export 'graphviz' not found.

After having adopted type=module for d3-graphviz like D3 version 7 has, I get the following error when trying to npm run test for d3-graphviz using hpcc-js/wasm version 1.15.5 or later:

file:///home/magjac/d3-graphviz/src/dot.js:1
import { graphviz } from "@hpcc-js/wasm";
         ^^^^^^^^
SyntaxError: Named export 'graphviz' not found. The requested module '@hpcc-js/wasm' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from '@hpcc-js/wasm';
const { graphviz } = pkg;

    at ModuleJob._instantiate (node:internal/modules/esm/module_job:123:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:189:5)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:533:24)
    at async importModuleDynamicallyWrapper (node:internal/vm/module:438:15)
    at async formattedImport (/home/magjac/d3-graphviz/node_modules/mocha/lib/nodejs/esm-utils.js:7:14)
    at async Object.exports.requireOrImport (/home/magjac/d3-graphviz/node_modules/mocha/lib/nodejs/esm-utils.js:38:28)
    at async Object.exports.loadFilesAsync (/home/magjac/d3-graphviz/node_modules/mocha/lib/nodejs/esm-utils.js:91:20)
    at async singleRun (/home/magjac/d3-graphviz/node_modules/mocha/lib/cli/run-helpers.js:125:3)
    at async Object.exports.handler (/home/magjac/d3-graphviz/node_modules/mocha/lib/cli/run.js:370:5)

Am I importing this incorrectly?

It works fine with version 1.15.4.

For background and details of the D3 change, see d3/d3#3469 and d3/d3#3501.

npm run build works without problems.

My system:

$ npm --version
8.15.0
$ node --version
v16.17.1
$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 22.04.1 LTS
Release:	22.04
Codename:	jammy

See magjac/d3-graphviz#242 for details.

Module not found: Can't resolve 'fs/promises'

Hello,

I try to use the latest version (1.15.4) in a next.js project but if I try to create a build then I get this error:

./node_modules/@hpcc-js/wasm/dist/index.js
Module not found: Can't resolve 'fs/promises' in 'node_modules/@hpcc-js/wasm/dist'

Using the workaround from vercel/next.js#7755 doesn't work because, even if it compiles then, the browser tries to use the fs package which doesn't exist obviously.

I don't know which version introduced this bug because I upgraded from 1.12.8

Runtime error on firefox when opening local html files relying on hpcc-js/wasm

The "official" hello world example doesn't work itself when it's loaded from the local file system.

The web developer console logs:

- Uncaught (in promise) RuntimeError: abort(LinkError: import object field 'Q' is not a Function). Build with -s ASSERTIONS=1 for more info.
    L https://cdn.jsdelivr.net/npm/@hpcc-js/wasm/dist/index.min.js:1
    i https://cdn.jsdelivr.net/npm/@hpcc-js/wasm/dist/index.min.js:1

Error returned when rendering invalid graph is sometimes unreadable

Most of the time, the error returned from the layout methods is the somewhat useful syntax error in line N near '...'.

But I've noticed in this library, for some cases it seems to return somewhat random string results. For example:

// hello
digraph G {
  a->b;
  ->c;
}

When run through this library, the result will be random characters / tofu and not an actual error message.

See for example the attached, which is a modification of the hello world from the README:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>GraphViz WASM</title>
    <script src="https://cdn.jsdelivr.net/npm/@hpcc-js/wasm/dist/index.min.js"></script>
    <script>
        var hpccWasm = window["@hpcc-js/wasm"];
    </script>
</head>
<body>
    <div id="placeholder"></div>
    <div id="placeholder2"></div>
    <script>
        const dot = `// hello
digraph G {
  a->b;
  ->c;
}`;
        // Asynchronous call to layout
        hpccWasm.graphviz.layout(dot, "svg", "dot").then(svg => {
            const div = document.getElementById("placeholder");
            div.innerHTML = svg;
        }).catch(e => {
            console.log('error from async', e);
        });
        hpccWasm.graphvizSync().then(graphviz => {
            const div = document.getElementById("placeholder2");
            // Synchronous call to layout
            div.innerHTML = graphviz.layout(dot, "svg", "dot");
        }).catch(e => {
            console.log('error from sync', e);
        });
    </script>
</body>
</html>

To verify that GraphViz itself isn't the cause of this problem, I just built the latest graphviz from source and ran that same graph through and it doesn't seem to have a problem with showing an error there.

> dot bad-graph.dot 
Error: bad-graph.dot: syntax error in line 4 near '->'
> dot -v
dot - graphviz version 2.47.1~dev.20210316.0544 (20210316.0544)

Any ideas? It seems that wasm.Main.prototype.lastError() is not set and returning random bytes, but I don't really understand how that part works quite yet

Use hpcc-js-wasm with client-side React based on create-react-app

Hi,

thanks for this package - comes in handy for using graphviz in the browser.

I am using it with React and I have run into trouble to find a clean way to give the web-packed React-app a URL from whare it can load the .wasm file. As others, I ended up to manually copy the file into the public/js folder, from where it gets loaded.

I am wondering whether anybody might have an idea how to access the file from where it originally sits - in the node-modules hierarchy.

Best,
Andreas

'ps.h' file not found

Hi, do you know where could I get this ps.h? I guess it's a header of postscript. It was from a clean docker container ubuntu:18.04.

docker run -it --rm --name js -v "$PWD:/opt/work" -w "/opt/work" -p 8080:8080 ubuntu:18.04 bash

And couple instructions.

apt update
./scripts/cpp-install-prerequisites.sh
npm ci
npm run install-build-deps
npm run build
[ 97%] Building C object graphviz/plugin/core/CMakeFiles/gvplugin_core.dir/opt/work/src-graphviz/plugin/core/gvrender_core_tk.c.o
[ 98%] Building C object graphviz/plugin/core/CMakeFiles/gvplugin_core.dir/opt/work/src-graphviz/plugin/core/gvrender_core_vml.c.o
/opt/work/src-graphviz/plugin/core/gvrender_core_ps.c:24:10: fatal error: 'ps.h' file not found
#include "ps.h"
         ^~~~~~
1 error generated.
shared:ERROR: '/opt/work/emsdk/upstream/bin/clang -target wasm32-unknown-emscripten -D__EMSCRIPTEN_major__=1 -D__EMSCRIPTEN_minor__=39 -D__EMSCRIPTEN_tiny__=8 -D_LIBCPP_ABI_VERSION=2 -Dunix -D__unix -D__unix__ -Werror=implicit-function-declaration -Xclang -nostdsysteminc -Xclang -isystem/opt/work/emsdk/upstream/emscripten/system/include/libcxx -Xclang -isystem/opt/work/emsdk/upstream/emscripten/system/lib/libcxxabi/include -Xclang -isystem/opt/work/emsdk/upstream/emscripten/system/include/compat -Xclang -isystem/opt/work/emsdk/upstream/emscripten/system/include -Xclang -isystem/opt/work/emsdk/upstream/emscripten/system/include/libc -Xclang -isystem/opt/work/emsdk/upstream/emscripten/system/lib/libc/musl/arch/emscripten -Xclang -isystem/opt/work/emsdk/upstream/emscripten/system/local/include -Xclang -isystem/root/.emscripten_cache/wasm-obj/include -I/opt/work/cpp/graphviz -I/opt/work/cpp/../src-graphviz/build/plugin/core -I/opt/work/cpp/../src-graphviz/plugin/core -I/opt/work/cpp/../src-graphviz/lib/vpsc -I/opt/work/cpp/../src-graphviz/lib/twopigen -I/opt/work/cpp/../src-graphviz/lib/sparse -I/opt/work/cpp/../src-graphviz/lib/sfdpgen -I/opt/work/cpp/../src-graphviz/lib/pathplan -I/opt/work/cpp/../src-graphviz/lib/common -I/opt/work/cpp/../src-graphviz/lib/gvc -I/opt/work/cpp/../src-graphviz/lib/cdt -I/opt/work/cpp/../src-graphviz/lib/cgraph -I/opt/work/cpp/../src-graphviz/lib/xdot -DNDEBUG -Os -c -DEMSCRIPTEN /opt/work/src-graphviz/plugin/core/gvrender_core_ps.c -fno-inline-functions -Xclang -isystem/opt/work/emsdk/upstream/emscripten/system/include/SDL -c -o CMakeFiles/gvplugin_core.dir/opt/work/src-graphviz/plugin/core/gvrender_core_ps.c.o -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr' failed (1)
graphviz/plugin/core/CMakeFiles/gvplugin_core.dir/build.make:238: recipe for target 'graphviz/plugin/core/CMakeFiles/gvplugin_core.dir/opt/work/src-graphviz/plugin/core/gvrender_core_ps.c.o' failed
make[2]: *** [graphviz/plugin/core/CMakeFiles/gvplugin_core.dir/opt/work/src-graphviz/plugin/core/gvrender_core_ps.c.o] Error 1
make[2]: *** Waiting for unfinished jobs....
CMakeFiles/Makefile2:1333: recipe for target 'graphviz/plugin/core/CMakeFiles/gvplugin_core.dir/all' failed
make[1]: *** [graphviz/plugin/core/CMakeFiles/gvplugin_core.dir/all] Error 2
Makefile:129: recipe for target 'all' failed
make: *** [all] Error 2

Sometimes I get a node without label (demo on viz-js.com)

In the current version of hpcc/graphviz, I regularly get nodes without label in the generated SVG. I can easily reproduce the problem in viz-js.com; Please see the reproduction in this video clip: https://youtu.be/M-mhesrSm7w
In the video the initial generation run is ok, but as soon as I start changing a label, the issue appears. Sometimes the problem is already there in the first run.
In the picture below, the bottom node should have a label.

I have attached the DOT file.

sample.dot.txt
image

Add support for synchronous layout

The @hpcc-js/wasm graphviz.layout function is asynchronous and returns a promise. In some situations it would be beneficial to be able to do the layout synchronously and obtain the layout directly.

This is an enhancement proposal to implement such a function that returns the layout directly.

Here are two cases where the now archived Viz.js v1.x is used synchronously:

Since d3-graphviz is currently in the process of being ported from Viz.js to @hpcc-js/wasm it would simply things a lot if @hpcc-js/wasm also had a function for performing the layout synchronously.

Build instructions

I would like to build a wasm plugin for a different project and I'm curious how you were able to get graphviz 8.1.0 compiled to wasm. I would like to do something similar but I don't see any details for building that part. I was looking at some of the cmake files and the docker file but I don't think I see how it was done quite yet and I would really like to be able to duplicate your work.

If you could add some details on how to build the expat/graphviz dependencies components that would be really helpful.

Error "h() is undefined" when calling layout.

I am trying render a graphviz diagram given by the user but am getting the error h() is undefined when I call the layout function. I am using writing in Typescript and am unsure what is going wrong. It is my understanding that I need to call layout with the code to render, the output type and the layout method and then I can retrieve the output svg with a callback.

Here is a snippet of code from my project which contains what I currently have.

import wasm from '@hpcc-js/wasm';
...
const obj = $('#selector'); // Get specific element from webpage which holds valid graphviz code
const graphText = obj.innerText; // Valid Graphviz from the user

wasm.graphviz.layout(graphText, "svg", "dot").then((svgCode: string) => { 
  obj.innerHTML = svgCode;
});

Edit: This is using Firefox 98.0.2 on macOS 11.4.

2.15 not compiling with Typescript

Repro steps (from empty directory):

npm init
npm install @hpcc-js/wasm
npm install typescript
node_modules/.bin/tsc --init # Create the tsconfig.json
# Configure "moduleResolution": "Node16" in tsconfig.json as per instructions in homepage.

Then write the following test.ts:

import { Graphviz } from "@hpcc-js/wasm/graphviz";

async function render() {
  const graphviz = await Graphviz.load();
  console.log(graphviz.dot('digraph G { Hello -> World }'));
}

render();

And now run it:

$ node_modules/.bin/tsc test.ts 
test.ts:1:26 - error TS2307: Cannot find module '@hpcc-js/wasm/graphviz' or its corresponding type declarations.

1 import { Graphviz } from "@hpcc-js/wasm/graphviz";
                           ~~~~~~~~~~~~~~~~~~~~~~~~

I'm using npm 9.6.7 and node v18.17.1.
npm installed typescript 5.3.2 and @hpcc-js/wasm 2.15.0.

Error handling using GraphvizSync() layout

I'm not at all sure that this is a bug in hpcc-js/wasm, but I have indications that the error handling when using GraphvizSync() does not work. I'm getting an error saying "full function or function signature mismatch" instead of the expected "syntax error in line 1 near 'bad'".

I haven't yet had time to boil this down to a minimal test case, so for now this is mainly a question if you have tested this. Error handling using the asynchronous Graphviz() seems to work as expected.

More details can be found at https://github.com/magjac/d3-graphviz/actions/runs/3372738896/jobs/5596518645

If this seems to work for you I will try to carve out some time to create a minimal test case.

TypeScript definitions for (parsed) JSON layout output format

Hi, my question is not directly related to this library so apologies if this is the wrong place to ask.

Do you know if there's a TypeScript definition for the result of parsing the json output of the dot command?

I've googled around and had a look on npm but can't find anything.

Option to provide the .wasm file's ArrayBuffer instead of library fetching it

First of all, thank you for your great library, I love it! Great job maintaining it and keeping it up to date I'm relying on it heavily.
So hats off!

I was wondering if you can add an option where I could pass in a pre-fetched ArrayBuffer of wasm file and pass that instead of the folder where the wasm file is located.

My use case: I'm using the library to process multiple graphviz source files and get output in parallel (using web workers). And this has decreased my code's runtime from 4 seconds to 1 second on my machine's localhost.

The issue is that if I have 4 cores, each worker will download the wasm file separately and spend ~400ms redoing a work that can be easily done just once for all of them, and that is on localhost. This number will be much higher in production and waste a lot of resources.

So if you add an option for passing typed array or ArrayBuffer that can be avoided.
I also have to mention it's impossible to pass around all kinds of objects between worker and master processes and they have to be clonable which is why I would need to pass an ArrayBuffer or a data type like that and passing library's objects around wouldn't work.

Pretty sure being able to fetch the wasm file's data and reuse them whenever needed could be useful in some other cases too.

Thanks again!

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.