From eccec7afddd51dc2f547b4ae3490a9dcab6865e0 Mon Sep 17 00:00:00 2001 From: Alexander Wang Date: Thu, 29 Dec 2022 22:43:01 -0800 Subject: [PATCH] elk --- d2layouts/d2dagrelayout/layout.go | 4 ++- d2layouts/d2elklayout/layout.go | 49 ++++++++++++++++--------------- d2plugin/plugin_elk.go | 14 ++++----- main.go | 41 ++++++++++++++++++++++++-- 4 files changed, 75 insertions(+), 33 deletions(-) diff --git a/d2layouts/d2dagrelayout/layout.go b/d2layouts/d2dagrelayout/layout.go index 18709c1bf..ee86e9599 100644 --- a/d2layouts/d2dagrelayout/layout.go +++ b/d2layouts/d2dagrelayout/layout.go @@ -32,10 +32,12 @@ var dagreJS string type Opts struct { NodeSep int + EdgeSep int } var DefaultOpts = Opts{ NodeSep: 60, + EdgeSep: 40, } type DagreNode struct { @@ -75,7 +77,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *Opts) (err error) { } rootAttrs := dagreGraphAttrs{ - edgesep: 40, + edgesep: opts.EdgeSep, nodesep: opts.NodeSep, } isHorizontal := false diff --git a/d2layouts/d2elklayout/layout.go b/d2layouts/d2elklayout/layout.go index 610a74572..f46e19004 100644 --- a/d2layouts/d2elklayout/layout.go +++ b/d2layouts/d2elklayout/layout.go @@ -77,29 +77,33 @@ type ELKGraph struct { Edges []*ELKEdge `json:"edges,omitempty"` } -var DefaultOpts = ELKLayoutOptions{ - Algorithm: "layered", - HierarchyHandling: "INCLUDE_CHILDREN", - NodeSpacing: 100.0, - EdgeNodeSpacing: 50.0, - SelfLoopSpacing: 50.0, - ConsiderModelOrder: "NODES_AND_EDGES", +var DefaultOpts = ConfigurableOpts{ + Algorithm: "layered", + NodeSpacing: 100.0, + Padding: "[top=75,left=75,bottom=75,right=75]", + EdgeNodeSpacing: 50.0, + SelfLoopSpacing: 50.0, +} + +type ConfigurableOpts struct { + Algorithm string `json:"elk.algorithm,omitempty"` + NodeSpacing int `json:"spacing.nodeNodeBetweenLayers,omitempty"` + Padding string `json:"elk.padding,omitempty"` + EdgeNodeSpacing int `json:"spacing.edgeNodeBetweenLayers,omitempty"` + SelfLoopSpacing int `json:"elk.spacing.nodeSelfLoop"` } type ELKLayoutOptions struct { - Algorithm string `json:"elk.algorithm,omitempty"` - HierarchyHandling string `json:"elk.hierarchyHandling,omitempty"` - NodeSpacing float64 `json:"spacing.nodeNodeBetweenLayers,omitempty"` - Padding string `json:"elk.padding,omitempty"` - EdgeNodeSpacing float64 `json:"spacing.edgeNodeBetweenLayers,omitempty"` - Direction string `json:"elk.direction"` - SelfLoopSpacing float64 `json:"elk.spacing.nodeSelfLoop"` - InlineEdgeLabels bool `json:"elk.edgeLabels.inline,omitempty"` - ConsiderModelOrder string `json:"elk.layered.considerModelOrder.strategy,omitempty"` - ForceNodeModelOrder bool `json:"elk.layered.crossingMinimization.forceNodeModelOrder,omitempty"` + Direction string `json:"elk.direction"` + HierarchyHandling string `json:"elk.hierarchyHandling,omitempty"` + InlineEdgeLabels bool `json:"elk.edgeLabels.inline,omitempty"` + ForceNodeModelOrder bool `json:"elk.layered.crossingMinimization.forceNodeModelOrder,omitempty"` + ConsiderModelOrder string `json:"elk.layered.considerModelOrder.strategy,omitempty"` + + ConfigurableOpts } -func Layout(ctx context.Context, g *d2graph.Graph, opts *ELKLayoutOptions) (err error) { +func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err error) { if opts == nil { opts = &DefaultOpts } @@ -122,12 +126,9 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ELKLayoutOptions) (err elkGraph := &ELKGraph{ ID: "root", LayoutOptions: &ELKLayoutOptions{ - Algorithm: "layered", HierarchyHandling: "INCLUDE_CHILDREN", - NodeSpacing: 100.0, - EdgeNodeSpacing: 50.0, - SelfLoopSpacing: 50.0, ConsiderModelOrder: "NODES_AND_EDGES", + ConfigurableOpts: *opts, }, } switch g.Root.Attributes.Direction.Value { @@ -171,8 +172,10 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ELKLayoutOptions) (err if len(obj.ChildrenArray) > 0 { n.LayoutOptions = &ELKLayoutOptions{ - Padding: "[top=75,left=75,bottom=75,right=75]", ForceNodeModelOrder: true, + ConfigurableOpts: ConfigurableOpts{ + Padding: opts.Padding, + }, } } diff --git a/d2plugin/plugin_elk.go b/d2plugin/plugin_elk.go index 5bdc018e1..da0ee3a5e 100644 --- a/d2plugin/plugin_elk.go +++ b/d2plugin/plugin_elk.go @@ -13,16 +13,16 @@ import ( var ELKPlugin = elkPlugin{} func init() { - plugins = append(plugins, ELKPlugin) + plugins = append(plugins, &ELKPlugin) } type elkPlugin struct { - opts *d2elklayout.ELKLayoutOptions + opts *d2elklayout.ConfigurableOpts } -func (p elkPlugin) HydrateOpts(ctx context.Context, opts interface{}) error { +func (p *elkPlugin) HydrateOpts(ctx context.Context, opts interface{}) error { if opts != nil { - elkOpts, ok := opts.(d2elklayout.ELKLayoutOptions) + elkOpts, ok := opts.(d2elklayout.ConfigurableOpts) if !ok { return xmain.UsageErrorf("non-dagre layout options given for dagre") } @@ -32,7 +32,7 @@ func (p elkPlugin) HydrateOpts(ctx context.Context, opts interface{}) error { return nil } -func (p elkPlugin) Info(context.Context) (*PluginInfo, error) { +func (p *elkPlugin) Info(context.Context) (*PluginInfo, error) { return &PluginInfo{ Name: "elk", ShortHelp: "Eclipse Layout Kernel (ELK) with the Layered algorithm.", @@ -42,10 +42,10 @@ See https://github.com/kieler/elkjs for more.`, }, nil } -func (p elkPlugin) Layout(ctx context.Context, g *d2graph.Graph) error { +func (p *elkPlugin) Layout(ctx context.Context, g *d2graph.Graph) error { return d2elklayout.Layout(ctx, g, p.opts) } -func (p elkPlugin) PostProcess(ctx context.Context, in []byte) ([]byte, error) { +func (p *elkPlugin) PostProcess(ctx context.Context, in []byte) ([]byte, error) { return in, nil } diff --git a/main.go b/main.go index 83ccef354..28ef74ea2 100644 --- a/main.go +++ b/main.go @@ -18,6 +18,7 @@ import ( "oss.terrastruct.com/util-go/xmain" "oss.terrastruct.com/d2/d2layouts/d2dagrelayout" + "oss.terrastruct.com/d2/d2layouts/d2elklayout" "oss.terrastruct.com/d2/d2lib" "oss.terrastruct.com/d2/d2plugin" "oss.terrastruct.com/d2/d2renderers/d2fonts" @@ -306,18 +307,54 @@ func DiscardSlog(ctx context.Context) context.Context { } func populateLayoutOpts(ms *xmain.State) error { - _, err := ms.Opts.Int64("", "dagre-nodesep", "", int64(d2dagrelayout.DefaultOpts.NodeSep), "number of pixels that separate nodes horizontally in the layout.") + _, err := ms.Opts.Int64("", "dagre-nodesep", "", int64(d2dagrelayout.DefaultOpts.NodeSep), "number of pixels that separate nodes horizontally.") if err != nil { return err } + _, err = ms.Opts.Int64("", "dagre-edgesep", "", int64(d2dagrelayout.DefaultOpts.EdgeSep), "number of pixels that separate edges horizontally.") + if err != nil { + return err + } + + ms.Opts.String("", "elk-algorithm", "", d2elklayout.DefaultOpts.Algorithm, "number of pixels that separate nodes horizontally.") + _, err = ms.Opts.Int64("", "elk-nodeNodeBetweenLayers", "", int64(d2elklayout.DefaultOpts.NodeSpacing), "number of pixels that separate edges horizontally.") + if err != nil { + return err + } + ms.Opts.String("", "elk-padding", "", d2elklayout.DefaultOpts.Padding, "number of pixels that separate nodes horizontally.") + _, err = ms.Opts.Int64("", "elk-edgeNodeBetweenLayers", "", int64(d2elklayout.DefaultOpts.EdgeNodeSpacing), "number of pixels that separate edges horizontally.") + if err != nil { + return err + } + _, err = ms.Opts.Int64("", "elk-nodeSelfLoop", "", int64(d2elklayout.DefaultOpts.SelfLoopSpacing), "number of pixels that separate edges horizontally.") + if err != nil { + return err + } + return nil } func parseLayoutOpts(ms *xmain.State, layout string) (interface{}, error) { - if layout == "dagre" { + switch layout { + case "dagre": nodesep, _ := ms.Opts.Flags.GetInt64("dagre-nodesep") + edgesep, _ := ms.Opts.Flags.GetInt64("dagre-edgesep") return d2dagrelayout.Opts{ NodeSep: int(nodesep), + EdgeSep: int(edgesep), + }, nil + case "elk": + algorithm, _ := ms.Opts.Flags.GetString("elk-algorithm") + nodeSpacing, _ := ms.Opts.Flags.GetInt64("elk-nodeNodeBetweenLayers") + padding, _ := ms.Opts.Flags.GetString("elk-padding") + edgeNodeSpacing, _ := ms.Opts.Flags.GetInt64("elk-edgeNodeSpacing") + selfLoopSpacing, _ := ms.Opts.Flags.GetInt64("elk-nodeSelfLoop") + return d2elklayout.ConfigurableOpts{ + Algorithm: algorithm, + NodeSpacing: int(nodeSpacing), + Padding: padding, + EdgeNodeSpacing: int(edgeNodeSpacing), + SelfLoopSpacing: int(selfLoopSpacing), }, nil }