This commit is contained in:
Alexander Wang 2022-12-29 22:43:01 -08:00
parent 590caa243c
commit eccec7afdd
No known key found for this signature in database
GPG key ID: D89FA31966BDBECE
4 changed files with 75 additions and 33 deletions

View file

@ -32,10 +32,12 @@ var dagreJS string
type Opts struct { type Opts struct {
NodeSep int NodeSep int
EdgeSep int
} }
var DefaultOpts = Opts{ var DefaultOpts = Opts{
NodeSep: 60, NodeSep: 60,
EdgeSep: 40,
} }
type DagreNode struct { type DagreNode struct {
@ -75,7 +77,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *Opts) (err error) {
} }
rootAttrs := dagreGraphAttrs{ rootAttrs := dagreGraphAttrs{
edgesep: 40, edgesep: opts.EdgeSep,
nodesep: opts.NodeSep, nodesep: opts.NodeSep,
} }
isHorizontal := false isHorizontal := false

View file

@ -77,29 +77,33 @@ type ELKGraph struct {
Edges []*ELKEdge `json:"edges,omitempty"` Edges []*ELKEdge `json:"edges,omitempty"`
} }
var DefaultOpts = ELKLayoutOptions{ var DefaultOpts = ConfigurableOpts{
Algorithm: "layered", Algorithm: "layered",
HierarchyHandling: "INCLUDE_CHILDREN", NodeSpacing: 100.0,
NodeSpacing: 100.0, Padding: "[top=75,left=75,bottom=75,right=75]",
EdgeNodeSpacing: 50.0, EdgeNodeSpacing: 50.0,
SelfLoopSpacing: 50.0, SelfLoopSpacing: 50.0,
ConsiderModelOrder: "NODES_AND_EDGES", }
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 { type ELKLayoutOptions struct {
Algorithm string `json:"elk.algorithm,omitempty"` Direction string `json:"elk.direction"`
HierarchyHandling string `json:"elk.hierarchyHandling,omitempty"` HierarchyHandling string `json:"elk.hierarchyHandling,omitempty"`
NodeSpacing float64 `json:"spacing.nodeNodeBetweenLayers,omitempty"` InlineEdgeLabels bool `json:"elk.edgeLabels.inline,omitempty"`
Padding string `json:"elk.padding,omitempty"` ForceNodeModelOrder bool `json:"elk.layered.crossingMinimization.forceNodeModelOrder,omitempty"`
EdgeNodeSpacing float64 `json:"spacing.edgeNodeBetweenLayers,omitempty"` ConsiderModelOrder string `json:"elk.layered.considerModelOrder.strategy,omitempty"`
Direction string `json:"elk.direction"`
SelfLoopSpacing float64 `json:"elk.spacing.nodeSelfLoop"` ConfigurableOpts
InlineEdgeLabels bool `json:"elk.edgeLabels.inline,omitempty"`
ConsiderModelOrder string `json:"elk.layered.considerModelOrder.strategy,omitempty"`
ForceNodeModelOrder bool `json:"elk.layered.crossingMinimization.forceNodeModelOrder,omitempty"`
} }
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 { if opts == nil {
opts = &DefaultOpts opts = &DefaultOpts
} }
@ -122,12 +126,9 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ELKLayoutOptions) (err
elkGraph := &ELKGraph{ elkGraph := &ELKGraph{
ID: "root", ID: "root",
LayoutOptions: &ELKLayoutOptions{ LayoutOptions: &ELKLayoutOptions{
Algorithm: "layered",
HierarchyHandling: "INCLUDE_CHILDREN", HierarchyHandling: "INCLUDE_CHILDREN",
NodeSpacing: 100.0,
EdgeNodeSpacing: 50.0,
SelfLoopSpacing: 50.0,
ConsiderModelOrder: "NODES_AND_EDGES", ConsiderModelOrder: "NODES_AND_EDGES",
ConfigurableOpts: *opts,
}, },
} }
switch g.Root.Attributes.Direction.Value { 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 { if len(obj.ChildrenArray) > 0 {
n.LayoutOptions = &ELKLayoutOptions{ n.LayoutOptions = &ELKLayoutOptions{
Padding: "[top=75,left=75,bottom=75,right=75]",
ForceNodeModelOrder: true, ForceNodeModelOrder: true,
ConfigurableOpts: ConfigurableOpts{
Padding: opts.Padding,
},
} }
} }

View file

@ -13,16 +13,16 @@ import (
var ELKPlugin = elkPlugin{} var ELKPlugin = elkPlugin{}
func init() { func init() {
plugins = append(plugins, ELKPlugin) plugins = append(plugins, &ELKPlugin)
} }
type elkPlugin struct { 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 { if opts != nil {
elkOpts, ok := opts.(d2elklayout.ELKLayoutOptions) elkOpts, ok := opts.(d2elklayout.ConfigurableOpts)
if !ok { if !ok {
return xmain.UsageErrorf("non-dagre layout options given for dagre") 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 return nil
} }
func (p elkPlugin) Info(context.Context) (*PluginInfo, error) { func (p *elkPlugin) Info(context.Context) (*PluginInfo, error) {
return &PluginInfo{ return &PluginInfo{
Name: "elk", Name: "elk",
ShortHelp: "Eclipse Layout Kernel (ELK) with the Layered algorithm.", ShortHelp: "Eclipse Layout Kernel (ELK) with the Layered algorithm.",
@ -42,10 +42,10 @@ See https://github.com/kieler/elkjs for more.`,
}, nil }, 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) 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 return in, nil
} }

41
main.go
View file

@ -18,6 +18,7 @@ import (
"oss.terrastruct.com/util-go/xmain" "oss.terrastruct.com/util-go/xmain"
"oss.terrastruct.com/d2/d2layouts/d2dagrelayout" "oss.terrastruct.com/d2/d2layouts/d2dagrelayout"
"oss.terrastruct.com/d2/d2layouts/d2elklayout"
"oss.terrastruct.com/d2/d2lib" "oss.terrastruct.com/d2/d2lib"
"oss.terrastruct.com/d2/d2plugin" "oss.terrastruct.com/d2/d2plugin"
"oss.terrastruct.com/d2/d2renderers/d2fonts" "oss.terrastruct.com/d2/d2renderers/d2fonts"
@ -306,18 +307,54 @@ func DiscardSlog(ctx context.Context) context.Context {
} }
func populateLayoutOpts(ms *xmain.State) error { 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 { if err != nil {
return err 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 return nil
} }
func parseLayoutOpts(ms *xmain.State, layout string) (interface{}, error) { func parseLayoutOpts(ms *xmain.State, layout string) (interface{}, error) {
if layout == "dagre" { switch layout {
case "dagre":
nodesep, _ := ms.Opts.Flags.GetInt64("dagre-nodesep") nodesep, _ := ms.Opts.Flags.GetInt64("dagre-nodesep")
edgesep, _ := ms.Opts.Flags.GetInt64("dagre-edgesep")
return d2dagrelayout.Opts{ return d2dagrelayout.Opts{
NodeSep: int(nodesep), 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 }, nil
} }