Skip to content

Commit

Permalink
feat(Images): Add Image Support
Browse files Browse the repository at this point in the history
Signed-off-by: Gordon Smith <[email protected]>
  • Loading branch information
GordonSmith committed Mar 1, 2020
1 parent 74b6fa7 commit b9c3015
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 44 deletions.
47 changes: 39 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ The _GraphViz_ library comes in **two** flavours

#### GraphViz API

<a name="layout" href="#layout">#</a> **layout**(_dotSource_[, _outputFormat_][, _layoutEngine_]) · [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/master/src/graphviz.ts "Source")
<a name="layout" href="#layout">#</a> **layout**(_dotSource_[, _outputFormat_][, _layoutEngine_][, _ext_]) · [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/master/src/graphviz.ts "Source")

Performs layout for the supplied _dotSource_, see [The DOT Language](https://graphviz.gitlab.io/_pages/doc/info/lang.html) for specification.

Expand All @@ -142,31 +142,62 @@ _layoutEngine_ supports the following options:

See [Layout manual pages](https://www.graphviz.org/documentation/) for more information.

<a name="circo" href="#circo">#</a> **circo**(_dotSource_[, _outputFormat_]) · [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/master/src/graphviz.ts "Source")
_ext_ optional "extra params":

* _images_: An optional array of
```JavaScript
{
path: string; // The path for the image.
width: string; // Width of Image
height: string; // Height of Image
}
```
* _files_: An optional array of
```JavaScript
{
path: string; // The path for the file.
data: string; // The data for the file.
}
```

For example passing a web hosted Image to GraphViz:
```JavaScript
hpccWasm.graphviz.layout('digraph { a[image="https://.../image.png"]; }', "svg", "dot", {
images: [{
path: "https://.../image.png",
width: "272px",
height: "92px"
}]
}).then(svg => {
document.getElementById("placeholder").innerHTML = svg;
}).catch(err => console.error(err.message));
```

<a name="circo" href="#circo">#</a> **circo**(_dotSource_[, _outputFormat_][, _ext_]) · [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/master/src/graphviz.ts "Source")

Convenience function that performs **circo** layout, is equivalent to `layout(dotSource, outputFormat, "circo");`.

<a name="dot" href="#dot">#</a> **dot**(_dotSource_[, _outputFormat_]) · [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/master/src/graphviz.ts "Source")
<a name="dot" href="#dot">#</a> **dot**(_dotSource_[, _outputFormat_][, _ext_]) · [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/master/src/graphviz.ts "Source")

Convenience function that performs **dot** layout, is equivalent to `layout(dotSource, outputFormat, "dot");`.

<a name="fdp" href="#fdp">#</a> **fdp**(_dotSource_[, _outputFormat_]) · [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/master/src/graphviz.ts "Source")
<a name="fdp" href="#fdp">#</a> **fdp**(_dotSource_[, _outputFormat_][, _ext_]) · [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/master/src/graphviz.ts "Source")

Convenience function that performs **circo** layout, is equivalent to `layout(dotSource, outputFormat, "fdp");`.

<a name="neato" href="#neato">#</a> **neato**(_dotSource_[, _outputFormat_]) · [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/master/src/graphviz.ts "Source")
<a name="neato" href="#neato">#</a> **neato**(_dotSource_[, _outputFormat_][, _ext_]) · [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/master/src/graphviz.ts "Source")

Convenience function that performs **neato** layout, is equivalent to `layout(dotSource, outputFormat, "neato");`.

<a name="osage" href="#osage">#</a> **osage**(_dotSource_[, _outputFormat_]) · [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/master/src/graphviz.ts "Source")
<a name="osage" href="#osage">#</a> **osage**(_dotSource_[, _outputFormat_][, _ext_]) · [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/master/src/graphviz.ts "Source")

Convenience function that performs **osage** layout, is equivalent to `layout(dotSource, outputFormat, "osage");`.

<a name="patchwork" href="#patchwork">#</a> **patchwork**(_dotSource_[, _outputFormat_]) · [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/master/src/graphviz.ts "Source")
<a name="patchwork" href="#patchwork">#</a> **patchwork**(_dotSource_[, _outputFormat_][, _ext_]) · [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/master/src/graphviz.ts "Source")

Convenience function that performs **patchwork** layout, is equivalent to `layout(dotSource, outputFormat, "patchwork");`.

<a name="twopi" href="#twopi">#</a> **twopi**(_dotSource_[, _outputFormat_]) · [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/master/src/graphviz.ts "Source")
<a name="twopi" href="#twopi">#</a> **twopi**(_dotSource_[, _outputFormat_][, _ext_]) · [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/master/src/graphviz.ts "Source")

Convenience function that performs **twopi** layout, is equivalent to `layout(dotSource, outputFormat, "twopi");`.

Expand Down
3 changes: 2 additions & 1 deletion cpp/graphviz/graphvizlib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
PROJECT(graphvizlib)

SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s WASM=1 -s NO_FILESYSTEM=0 -s INVOKE_RUN=0 -s ENVIRONMENT=web -s ALLOW_MEMORY_GROWTH=1")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s WASM=1 -s INVOKE_RUN=0 -s ENVIRONMENT=web -s ALLOW_MEMORY_GROWTH=1")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s MODULARIZE=1 -s EXPORT_NAME='${CMAKE_PROJECT_NAME}'")

# Generate Glue from IDL file ---
Expand All @@ -15,6 +15,7 @@ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --post-js ${CMAKE_CURRENT_BINARY_DIR}/ma

SET(SRCS
main.cpp
fs.cpp
)

INCLUDE_DIRECTORIES(
Expand Down
15 changes: 15 additions & 0 deletions cpp/graphviz/graphvizlib/fs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include "main.hpp"

#include <emscripten.h>

void Main::createFile(const char *path, const char *data)
{
EM_ASM_({
var path = UTF8ToString($0);
var data = UTF8ToString($1);

FS.createPath("/", PATH.dirname(path));
FS.writeFile(PATH.join("/", path), data);
},
path, data);
}
1 change: 1 addition & 0 deletions cpp/graphviz/graphvizlib/main.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ class Main
public:
static const char *layout(const char *dot, const char *format, const char *engine);
static const char *lastError();
static void createFile(const char *path, const char *data);
};
2 changes: 2 additions & 0 deletions cpp/graphviz/graphvizlib/main.idl
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
interface Main {
[Const] static DOMString layout([Const] DOMString dot, [Const] DOMString format, [Const] DOMString engine);
[Const] static DOMString lastError();
void createFile([Const] DOMString file, [Const] DOMString data);
};

2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ <h3>End</h3>
div.innerHTML = svg;
}).catch(err => console.error(err.message));

hpccWasm.graphviz.layout(dot, "svg", "dot").then(svg => {
hpccWasm.graphviz.layout('digraph { a[image="https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"]; }', "svg", "dot", { images: [{ path: "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", width: "272px", height: "92px" }] }).then(svg => {
const div = document.getElementById("placeholder2");
div.innerHTML = svg;
}).catch(err => console.error(err.message));
Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"run-script-os": "^1.0.7",
"standard-version": "^7.1.0",
"terser": "^4.6.4",
"tslib": "^1.11.0",
"tslib": "^1.11.1",
"tslint": "^5.20.1",
"typescript": "~3.6.5"
},
Expand Down
100 changes: 70 additions & 30 deletions src/graphviz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,76 @@ import { loadWasm } from "./util";
type Format = "svg" | "dot" | "json" | "dot_json" | "xdot_json";
type Engine = "circo" | "dot" | "fdp" | "neato" | "osage" | "patchwork" | "twopi";

interface Image {
path: string;
width: string;
height: string;
}

interface File {
path: string;
data: string;
}

interface Ext {
images?: Image[];
files?: File[];
}

function imageToFile(image: Image): File {
return {
path: image.path,
data: `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="${image.width}" height="${image.height}"></svg>`
};
}

function imagesToFiles(images: Image[]) {
return images.map(imageToFile);
}

function createFiles(wasm: any, _ext?: Ext) {
const ext = {
images: [],
files: [],
..._ext
};
[...ext.files, ...imagesToFiles(ext.images)].forEach(file => wasm.Main.prototype.createFile(file.path, file.data));
}

export const graphviz = {
layout(dotSource: string, outputFormat: Format = "svg", layoutEngine: Engine = "dot"): Promise<string> {
layout(dotSource: string, outputFormat: Format = "svg", layoutEngine: Engine = "dot", ext?: Ext): Promise<string> {
if (!dotSource) return Promise.resolve("");
return loadWasm(graphvizlib).then(wasm => {
createFiles(wasm, ext);
const retVal = wasm.Main.prototype.layout(dotSource, outputFormat, layoutEngine);
if (!retVal) {
throw new Error(wasm.Main.prototype.lastError());
}
return retVal;
});
},
circo(dotSource: string, outputFormat: Format = "svg"): Promise<string> {
return this.layout(dotSource, outputFormat, "circo");
circo(dotSource: string, outputFormat: Format = "svg", ext?: Ext): Promise<string> {
return this.layout(dotSource, outputFormat, "circo", ext);
},
dot(dotSource: string, outputFormat: Format = "svg"): Promise<string> {
return this.layout(dotSource, outputFormat, "dot");
dot(dotSource: string, outputFormat: Format = "svg", ext?: Ext): Promise<string> {
return this.layout(dotSource, outputFormat, "dot", ext);
},
fdp(dotSource: string, outputFormat: Format = "svg"): Promise<string> {
return this.layout(dotSource, outputFormat, "fdp");
fdp(dotSource: string, outputFormat: Format = "svg", ext?: Ext): Promise<string> {
return this.layout(dotSource, outputFormat, "fdp", ext);
},
neato(dotSource: string, outputFormat: Format = "svg"): Promise<string> {
return this.layout(dotSource, outputFormat, "neato");
neato(dotSource: string, outputFormat: Format = "svg", ext?: Ext): Promise<string> {
return this.layout(dotSource, outputFormat, "neato", ext);
},
osage(dotSource: string, outputFormat: Format = "svg"): Promise<string> {
return this.layout(dotSource, outputFormat, "osage");
osage(dotSource: string, outputFormat: Format = "svg", ext?: Ext): Promise<string> {
return this.layout(dotSource, outputFormat, "osage", ext);
},
patchwork(dotSource: string, outputFormat: Format = "svg"): Promise<string> {
return this.layout(dotSource, outputFormat, "patchwork");
patchwork(dotSource: string, outputFormat: Format = "svg", ext?: Ext): Promise<string> {
return this.layout(dotSource, outputFormat, "patchwork", ext);
},
twopi(dotSource: string, outputFormat: Format = "svg"): Promise<string> {
return this.layout(dotSource, outputFormat, "twopi");
twopi(dotSource: string, outputFormat: Format = "svg", ext?: Ext): Promise<string> {
return this.layout(dotSource, outputFormat, "twopi", ext);
}
};

Expand All @@ -44,41 +83,42 @@ class GraphvizSync {
constructor(private _wasm: any) {
}

layout(dotSource: string, outputFormat: Format = "svg", layoutEngine: Engine = "dot"): string {
layout(dotSource: string, outputFormat: Format = "svg", layoutEngine: Engine = "dot", ext?: Ext): string {
if (!dotSource) return "";
createFiles(this._wasm, ext);
const retVal = this._wasm.Main.prototype.layout(dotSource, outputFormat, layoutEngine);
if (!retVal) {
throw new Error(this._wasm.Main.prototype.lastError());
}
return retVal;
}

circo(dotSource: string, outputFormat: Format = "svg"): string {
return this.layout(dotSource, outputFormat, "circo");
circo(dotSource: string, outputFormat: Format = "svg", ext?: Ext): string {
return this.layout(dotSource, outputFormat, "circo", ext);
}

dot(dotSource: string, outputFormat: Format = "svg"): string {
return this.layout(dotSource, outputFormat, "dot");
dot(dotSource: string, outputFormat: Format = "svg", ext?: Ext): string {
return this.layout(dotSource, outputFormat, "dot", ext);
}

fdp(dotSource: string, outputFormat: Format = "svg"): string {
return this.layout(dotSource, outputFormat, "fdp");
fdp(dotSource: string, outputFormat: Format = "svg", ext?: Ext): string {
return this.layout(dotSource, outputFormat, "fdp", ext);
}

neato(dotSource: string, outputFormat: Format = "svg"): string {
return this.layout(dotSource, outputFormat, "neato");
neato(dotSource: string, outputFormat: Format = "svg", ext?: Ext): string {
return this.layout(dotSource, outputFormat, "neato", ext);
}

osage(dotSource: string, outputFormat: Format = "svg"): string {
return this.layout(dotSource, outputFormat, "osage");
osage(dotSource: string, outputFormat: Format = "svg", ext?: Ext): string {
return this.layout(dotSource, outputFormat, "osage", ext);
}

patchwork(dotSource: string, outputFormat: Format = "svg"): string {
return this.layout(dotSource, outputFormat, "patchwork");
patchwork(dotSource: string, outputFormat: Format = "svg", ext?: Ext): string {
return this.layout(dotSource, outputFormat, "patchwork", ext);
}

twopi(dotSource: string, outputFormat: Format = "svg"): string {
return this.layout(dotSource, outputFormat, "twopi");
twopi(dotSource: string, outputFormat: Format = "svg", ext?: Ext): string {
return this.layout(dotSource, outputFormat, "twopi", ext);
}
}

Expand Down

0 comments on commit b9c3015

Please sign in to comment.