layout grid including outside label sizes

This commit is contained in:
Gavin Nishizawa 2023-09-26 16:14:19 -07:00
parent c7ec370a54
commit b9c139de59
No known key found for this signature in database
GPG key ID: AE3B177777CE55CD
2 changed files with 67 additions and 54 deletions

View file

@ -2,7 +2,6 @@ package d2grid
import (
"strconv"
"strings"
"oss.terrastruct.com/d2/d2graph"
"oss.terrastruct.com/d2/lib/geo"
@ -112,19 +111,3 @@ func (gd *gridDiagram) shift(dx, dy float64) {
e.Move(dx, dy)
}
}
func (gd *gridDiagram) cleanup(obj *d2graph.Object, graph *d2graph.Graph) {
obj.Children = make(map[string]*d2graph.Object)
obj.ChildrenArray = make([]*d2graph.Object, 0)
restore := func(parent, child *d2graph.Object) {
parent.Children[strings.ToLower(child.ID)] = child
parent.ChildrenArray = append(parent.ChildrenArray, child)
graph.Objects = append(graph.Objects, child)
}
for _, child := range gd.objects {
restore(obj, child)
child.IterDescendants(restore)
}
graph.Edges = append(graph.Edges, gd.edges...)
}

View file

@ -77,43 +77,6 @@ func Layout(ctx context.Context, g *d2graph.Graph) error {
}
}
// also check for grid cells with outside top labels or icons
// the first grid object is at the top (and always exists)
topY := gd.objects[0].TopLeft.Y
highestOutside := topY
for _, o := range gd.objects {
// we only want to compute label positions for objects at the top of the grid
if o.TopLeft.Y > topY {
if gd.rowDirected {
// if the grid is rowDirected (row1, row2, etc) we can stop after finishing the first row
break
} else {
// otherwise we continue until the next column
continue
}
}
if o.LabelPosition != nil {
labelPosition := label.Position(*o.LabelPosition)
if labelPosition.IsOutside() {
labelTL := o.GetLabelTopLeft()
if labelTL.Y < highestOutside {
highestOutside = labelTL.Y
}
}
}
if o.IconPosition != nil {
switch label.Position(*o.IconPosition) {
case label.OutsideTopLeft, label.OutsideTopCenter, label.OutsideTopRight:
iconSpace := float64(d2target.MAX_ICON_SIZE + label.PADDING)
if topY-iconSpace < highestOutside {
highestOutside = topY - iconSpace
}
}
}
}
if highestOutside < topY {
occupiedHeight += topY - highestOutside + 2*label.PADDING
}
if occupiedHeight > float64(verticalPadding) {
// if the label doesn't fit within the padding, we need to add more
dy = occupiedHeight - float64(verticalPadding)
@ -179,12 +142,19 @@ func Layout(ctx context.Context, g *d2graph.Graph) error {
func layoutGrid(g *d2graph.Graph, obj *d2graph.Object) (*gridDiagram, error) {
gd := newGridDiagram(obj)
// to handle objects with outside labels, we adjust their dimensions before layout and
// after layout, we remove the label adjustment and reposition TopLeft if needed
// TODO
revertAdjustments := gd.sizeForOutsideLabels()
if gd.rows != 0 && gd.columns != 0 {
gd.layoutEvenly(g, obj)
} else {
gd.layoutDynamic(g, obj)
}
revertAdjustments()
// position labels and icons
for _, o := range gd.objects {
if o.Icon != nil {
@ -871,3 +841,63 @@ func getDistToTarget(layout [][]*d2graph.Object, targetSize float64, horizontalG
}
return totalDelta
}
func (gd *gridDiagram) sizeForOutsideLabels() (revert func()) {
widthAdjustments := make(map[*d2graph.Object]float64)
heightAdjustments := make(map[*d2graph.Object]float64)
// TODO icons!
for _, o := range gd.objects {
if !o.HasLabel() || o.LabelPosition == nil {
continue
}
position := label.Position(*o.LabelPosition)
width := float64(o.LabelDimensions.Width + 2*label.PADDING)
height := float64(o.LabelDimensions.Height + 2*label.PADDING)
switch position {
case label.OutsideTopLeft, label.OutsideTopCenter, label.OutsideTopRight,
label.OutsideBottomLeft, label.OutsideBottomCenter, label.OutsideBottomRight:
heightAdjustments[o] = height
if width > o.Width {
widthAdjustments[o] = width - o.Width
}
case label.OutsideLeftTop, label.OutsideLeftMiddle, label.OutsideLeftBottom,
label.OutsideRightTop, label.OutsideRightMiddle, label.OutsideRightBottom:
widthAdjustments[o] = width
if height > o.Height {
heightAdjustments[o] = height - o.Height
}
}
}
return func() {
for _, o := range gd.objects {
if !o.HasLabel() || o.LabelPosition == nil {
continue
}
widthAdjustment, hasW := widthAdjustments[o]
heightAdjustment, hasH := heightAdjustments[o]
if !hasW && !hasH {
continue
}
position := label.Position(*o.LabelPosition)
o.Height -= heightAdjustment
o.Width -= widthAdjustment
switch position {
case label.OutsideTopLeft, label.OutsideTopCenter, label.OutsideTopRight:
if hasH {
o.TopLeft.Y += heightAdjustment
}
case label.OutsideLeftTop, label.OutsideLeftMiddle, label.OutsideLeftBottom:
if hasW {
o.TopLeft.X += widthAdjustment
}
}
}
}
}