add support for d2-config layouts
This commit is contained in:
parent
49992148d7
commit
f6ec0247e1
6 changed files with 64 additions and 62 deletions
|
|
@ -154,6 +154,26 @@ func GetELKGraph(args []js.Value) (interface{}, error) {
|
||||||
return elk, nil
|
return elk, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func layoutResolver() func(engine string) (d2graph.LayoutGraph, error) {
|
||||||
|
cached := make(map[string]d2graph.LayoutGraph)
|
||||||
|
return func(engine string) (d2graph.LayoutGraph, error) {
|
||||||
|
if c, ok := cached[engine]; ok {
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
var layout d2graph.LayoutGraph
|
||||||
|
switch engine {
|
||||||
|
case "dagre":
|
||||||
|
layout = d2dagrelayout.DefaultLayout
|
||||||
|
case "elk":
|
||||||
|
layout = d2elklayout.DefaultLayout
|
||||||
|
default:
|
||||||
|
return nil, &WASMError{Message: fmt.Sprintf("layout option '%s' not recognized", engine), Code: 400}
|
||||||
|
}
|
||||||
|
cached[engine] = layout
|
||||||
|
return layout, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Compile(args []js.Value) (interface{}, error) {
|
func Compile(args []js.Value) (interface{}, error) {
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
return nil, &WASMError{Message: "missing JSON argument", Code: 400}
|
return nil, &WASMError{Message: "missing JSON argument", Code: 400}
|
||||||
|
|
@ -171,35 +191,29 @@ func Compile(args []js.Value) (interface{}, error) {
|
||||||
return nil, &WASMError{Message: "missing 'index' file in input fs", Code: 400}
|
return nil, &WASMError{Message: "missing 'index' file in input fs", Code: 400}
|
||||||
}
|
}
|
||||||
|
|
||||||
fs, err := memfs.New(input.FS)
|
compileOpts := &d2lib.CompileOptions{
|
||||||
|
UTF16Pos: true,
|
||||||
|
LayoutResolver: layoutResolver(),
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
compileOpts.FS, err = memfs.New(input.FS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &WASMError{Message: fmt.Sprintf("invalid fs input: %s", err.Error()), Code: 400}
|
return nil, &WASMError{Message: fmt.Sprintf("invalid fs input: %s", err.Error()), Code: 400}
|
||||||
}
|
}
|
||||||
|
|
||||||
ruler, err := textmeasure.NewRuler()
|
compileOpts.Ruler, err = textmeasure.NewRuler()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &WASMError{Message: fmt.Sprintf("text ruler cannot be initialized: %s", err.Error()), Code: 500}
|
return nil, &WASMError{Message: fmt.Sprintf("text ruler cannot be initialized: %s", err.Error()), Code: 500}
|
||||||
}
|
}
|
||||||
ctx := log.WithDefault(context.Background())
|
|
||||||
layoutFunc := d2dagrelayout.DefaultLayout
|
|
||||||
if input.Opts != nil && input.Opts.Layout != nil {
|
if input.Opts != nil && input.Opts.Layout != nil {
|
||||||
switch *input.Opts.Layout {
|
compileOpts.Layout = input.Opts.Layout
|
||||||
case "dagre":
|
|
||||||
layoutFunc = d2dagrelayout.DefaultLayout
|
|
||||||
case "elk":
|
|
||||||
layoutFunc = d2elklayout.DefaultLayout
|
|
||||||
default:
|
|
||||||
return nil, &WASMError{Message: fmt.Sprintf("layout option '%s' not recognized", *input.Opts.Layout), Code: 400}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layoutResolver := func(engine string) (d2graph.LayoutGraph, error) {
|
|
||||||
return layoutFunc, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderOpts := &d2svg.RenderOpts{}
|
renderOpts := &d2svg.RenderOpts{}
|
||||||
var fontFamily *d2fonts.FontFamily
|
|
||||||
if input.Opts != nil && input.Opts.Sketch != nil && *input.Opts.Sketch {
|
if input.Opts != nil && input.Opts.Sketch != nil && *input.Opts.Sketch {
|
||||||
fontFamily = go2.Pointer(d2fonts.HandDrawn)
|
compileOpts.FontFamily = go2.Pointer(d2fonts.HandDrawn)
|
||||||
renderOpts.Sketch = input.Opts.Sketch
|
renderOpts.Sketch = input.Opts.Sketch
|
||||||
}
|
}
|
||||||
if input.Opts != nil && input.Opts.Pad != nil {
|
if input.Opts != nil && input.Opts.Pad != nil {
|
||||||
|
|
@ -217,13 +231,9 @@ func Compile(args []js.Value) (interface{}, error) {
|
||||||
if input.Opts != nil && input.Opts.Scale != nil {
|
if input.Opts != nil && input.Opts.Scale != nil {
|
||||||
renderOpts.Scale = input.Opts.Scale
|
renderOpts.Scale = input.Opts.Scale
|
||||||
}
|
}
|
||||||
diagram, g, err := d2lib.Compile(ctx, input.FS["index"], &d2lib.CompileOptions{
|
|
||||||
UTF16Pos: true,
|
ctx := log.WithDefault(context.Background())
|
||||||
FS: fs,
|
diagram, g, err := d2lib.Compile(ctx, input.FS["index"], compileOpts, renderOpts)
|
||||||
Ruler: ruler,
|
|
||||||
LayoutResolver: layoutResolver,
|
|
||||||
FontFamily: fontFamily,
|
|
||||||
}, renderOpts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if pe, ok := err.(*d2parser.ParseError); ok {
|
if pe, ok := err.(*d2parser.ParseError); ok {
|
||||||
errs, _ := json.Marshal(pe.Errors)
|
errs, _ := json.Marshal(pe.Errors)
|
||||||
|
|
@ -232,23 +242,21 @@ func Compile(args []js.Value) (interface{}, error) {
|
||||||
return nil, &WASMError{Message: err.Error(), Code: 500}
|
return nil, &WASMError{Message: err.Error(), Code: 500}
|
||||||
}
|
}
|
||||||
|
|
||||||
mergedRenderOpts := RenderOptions{
|
|
||||||
ThemeID: renderOpts.ThemeID,
|
|
||||||
DarkThemeID: renderOpts.DarkThemeID,
|
|
||||||
Sketch: renderOpts.Sketch,
|
|
||||||
Pad: renderOpts.Pad,
|
|
||||||
Center: renderOpts.Center,
|
|
||||||
Scale: input.Opts.Scale,
|
|
||||||
ForceAppendix: input.Opts.ForceAppendix,
|
|
||||||
};
|
|
||||||
|
|
||||||
input.FS["index"] = d2format.Format(g.AST)
|
input.FS["index"] = d2format.Format(g.AST)
|
||||||
|
|
||||||
return CompileResponse{
|
return CompileResponse{
|
||||||
FS: input.FS,
|
FS: input.FS,
|
||||||
Diagram: *diagram,
|
Diagram: *diagram,
|
||||||
Graph: *g,
|
Graph: *g,
|
||||||
RenderOpts: mergedRenderOpts,
|
Options: RenderOptions{
|
||||||
|
ThemeID: renderOpts.ThemeID,
|
||||||
|
DarkThemeID: renderOpts.DarkThemeID,
|
||||||
|
Sketch: renderOpts.Sketch,
|
||||||
|
Pad: renderOpts.Pad,
|
||||||
|
Center: renderOpts.Center,
|
||||||
|
Scale: renderOpts.Scale,
|
||||||
|
ForceAppendix: input.Opts.ForceAppendix,
|
||||||
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ type CompileResponse struct {
|
||||||
FS map[string]string `json:"fs"`
|
FS map[string]string `json:"fs"`
|
||||||
Diagram d2target.Diagram `json:"diagram"`
|
Diagram d2target.Diagram `json:"diagram"`
|
||||||
Graph d2graph.Graph `json:"graph"`
|
Graph d2graph.Graph `json:"graph"`
|
||||||
RenderOpts RenderOptions `json:"renderOpts"`
|
Options RenderOptions `json:"options"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CompletionResponse struct {
|
type CompletionResponse struct {
|
||||||
|
|
|
||||||
|
|
@ -316,7 +316,7 @@
|
||||||
center,
|
center,
|
||||||
forceAppendix,
|
forceAppendix,
|
||||||
});
|
});
|
||||||
const svg = await d2.render(result.diagram, result.renderOpts);
|
const svg = await d2.render(result.diagram, result.options);
|
||||||
document.getElementById("output").innerHTML = svg;
|
document.getElementById("output").innerHTML = svg;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,10 @@ export function setupMessageHandler(isNode, port, initWasm) {
|
||||||
// single-threaded WASM call cannot complete without giving control back
|
// single-threaded WASM call cannot complete without giving control back
|
||||||
// So we compute it, store it here, then during elk layout, instead
|
// So we compute it, store it here, then during elk layout, instead
|
||||||
// of computing again, we use this variable (and unset it for next call)
|
// of computing again, we use this variable (and unset it for next call)
|
||||||
if (data.options.layout === "elk") {
|
|
||||||
const elkGraph = await d2.getELKGraph(JSON.stringify(data));
|
const elkGraph = await d2.getELKGraph(JSON.stringify(data));
|
||||||
const elkGraph2 = JSON.parse(elkGraph).data;
|
const elkGraph2 = JSON.parse(elkGraph).data;
|
||||||
const layout = await elk.layout(elkGraph2);
|
const layout = await elk.layout(elkGraph2);
|
||||||
globalThis.elkResult = layout;
|
globalThis.elkResult = layout;
|
||||||
}
|
|
||||||
|
|
||||||
const result = await d2.compile(JSON.stringify(data));
|
const result = await d2.compile(JSON.stringify(data));
|
||||||
const response = JSON.parse(result);
|
const response = JSON.parse(result);
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,10 @@ export function setupMessageHandler(isNode, port, initWasm) {
|
||||||
|
|
||||||
case "compile":
|
case "compile":
|
||||||
try {
|
try {
|
||||||
if (data.options.layout === "elk") {
|
|
||||||
const elkGraph = await d2.getELKGraph(JSON.stringify(data));
|
const elkGraph = await d2.getELKGraph(JSON.stringify(data));
|
||||||
const elkGraph2 = JSON.parse(elkGraph).data;
|
const elkGraph2 = JSON.parse(elkGraph).data;
|
||||||
const layout = await elk.layout(elkGraph2);
|
const layout = await elk.layout(elkGraph2);
|
||||||
globalThis.elkResult = layout;
|
globalThis.elkResult = layout;
|
||||||
}
|
|
||||||
const result = await d2.compile(JSON.stringify(data));
|
const result = await d2.compile(JSON.stringify(data));
|
||||||
const response = JSON.parse(result);
|
const response = JSON.parse(result);
|
||||||
if (response.error) throw new Error(response.error.message);
|
if (response.error) throw new Error(response.error.message);
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,10 @@ export function setupMessageHandler(isNode, port, initWasm) {
|
||||||
|
|
||||||
case "compile":
|
case "compile":
|
||||||
try {
|
try {
|
||||||
if (data.options.layout === "elk") {
|
|
||||||
const elkGraph = await d2.getELKGraph(JSON.stringify(data));
|
const elkGraph = await d2.getELKGraph(JSON.stringify(data));
|
||||||
const elkGraph2 = JSON.parse(elkGraph).data;
|
const elkGraph2 = JSON.parse(elkGraph).data;
|
||||||
const layout = await elk.layout(elkGraph2);
|
const layout = await elk.layout(elkGraph2);
|
||||||
globalThis.elkResult = layout;
|
globalThis.elkResult = layout;
|
||||||
}
|
|
||||||
const result = await d2.compile(JSON.stringify(data));
|
const result = await d2.compile(JSON.stringify(data));
|
||||||
const response = JSON.parse(result);
|
const response = JSON.parse(result);
|
||||||
if (response.error) throw new Error(response.error.message);
|
if (response.error) throw new Error(response.error.message);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue