...

Source file src/oss.terrastruct.com/d2/d2layouts/d2grid/grid_diagram.go

Documentation: oss.terrastruct.com/d2/d2layouts/d2grid

     1  package d2grid
     2  
     3  import (
     4  	"strconv"
     5  
     6  	"oss.terrastruct.com/d2/d2graph"
     7  	"oss.terrastruct.com/d2/lib/geo"
     8  )
     9  
    10  type gridDiagram struct {
    11  	root    *d2graph.Object
    12  	objects []*d2graph.Object
    13  	edges   []*d2graph.Edge
    14  	rows    int
    15  	columns int
    16  
    17  	// if true, place objects left to right along rows
    18  	// if false, place objects top to bottom along columns
    19  	rowDirected bool
    20  
    21  	width  float64
    22  	height float64
    23  
    24  	verticalGap   int
    25  	horizontalGap int
    26  }
    27  
    28  func newGridDiagram(root *d2graph.Object) *gridDiagram {
    29  	gd := gridDiagram{
    30  		root:          root,
    31  		objects:       root.ChildrenArray,
    32  		verticalGap:   DEFAULT_GAP,
    33  		horizontalGap: DEFAULT_GAP,
    34  	}
    35  
    36  	if root.GridRows != nil {
    37  		gd.rows, _ = strconv.Atoi(root.GridRows.Value)
    38  	}
    39  	if root.GridColumns != nil {
    40  		gd.columns, _ = strconv.Atoi(root.GridColumns.Value)
    41  	}
    42  
    43  	if gd.rows != 0 && gd.columns != 0 {
    44  		// . row-directed  column-directed
    45  		// .  ┌───────┐    ┌───────┐
    46  		// .  │ a b c │    │ a d g │
    47  		// .  │ d e f │    │ b e h │
    48  		// .  │ g h i │    │ c f i │
    49  		// .  └───────┘    └───────┘
    50  		// if keyword rows is first, make it row-directed, if columns is first it is column-directed
    51  		if root.GridRows.MapKey.Range.Before(root.GridColumns.MapKey.Range) {
    52  			gd.rowDirected = true
    53  		}
    54  
    55  		// rows and columns specified, but we want to continue naturally if user enters more objects
    56  		// e.g. 2 rows, 3 columns specified + g added:      │ with 3 columns, 2 rows:
    57  		// . original  add row   add column                 │ original  add row   add column
    58  		// . ┌───────┐ ┌───────┐ ┌─────────┐                │ ┌───────┐ ┌───────┐ ┌─────────┐
    59  		// . │ a b c │ │ a b c │ │ a b c d │                │ │ a c e │ │ a d g │ │ a c e g │
    60  		// . │ d e f │ │ d e f │ │ e f g   │                │ │ b d f │ │ b e   │ │ b d f   │
    61  		// . └───────┘ │ g     │ └─────────┘                │ └───────┘ │ c f   │ └─────────┘
    62  		// .           └───────┘ ▲                          │           └───────┘ ▲
    63  		// .           ▲         └─existing objects modified│           ▲         └─existing columns preserved
    64  		// .           └─existing rows preserved            │           └─existing objects modified
    65  		capacity := gd.rows * gd.columns
    66  		for capacity < len(gd.objects) {
    67  			if gd.rowDirected {
    68  				gd.rows++
    69  				capacity += gd.columns
    70  			} else {
    71  				gd.columns++
    72  				capacity += gd.rows
    73  			}
    74  		}
    75  	} else if gd.columns == 0 {
    76  		gd.rowDirected = true
    77  		// we can only make N rows with N objects
    78  		if len(gd.objects) < gd.rows {
    79  			gd.rows = len(gd.objects)
    80  		}
    81  	} else {
    82  		if len(gd.objects) < gd.columns {
    83  			gd.columns = len(gd.objects)
    84  		}
    85  	}
    86  
    87  	// grid gap sets both, but can be overridden
    88  	if root.GridGap != nil {
    89  		gd.verticalGap, _ = strconv.Atoi(root.GridGap.Value)
    90  		gd.horizontalGap = gd.verticalGap
    91  	}
    92  	if root.VerticalGap != nil {
    93  		gd.verticalGap, _ = strconv.Atoi(root.VerticalGap.Value)
    94  	}
    95  	if root.HorizontalGap != nil {
    96  		gd.horizontalGap, _ = strconv.Atoi(root.HorizontalGap.Value)
    97  	}
    98  
    99  	for _, o := range gd.objects {
   100  		o.TopLeft = geo.NewPoint(0, 0)
   101  	}
   102  
   103  	return &gd
   104  }
   105  
   106  func (gd *gridDiagram) shift(dx, dy float64) {
   107  	for _, obj := range gd.objects {
   108  		obj.MoveWithDescendants(dx, dy)
   109  	}
   110  	for _, e := range gd.edges {
   111  		e.Move(dx, dy)
   112  	}
   113  }
   114  

View as plain text