fix grid icon positioning

This commit is contained in:
Gavin Nishizawa 2023-05-30 11:59:39 -07:00
parent f64c0f1c77
commit 176df52cec
No known key found for this signature in database
GPG key ID: AE3B177777CE55CD
3 changed files with 75 additions and 48 deletions

View file

@ -238,7 +238,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
obj.Width = math.Ceil(dn.Width)
obj.Height = math.Ceil(dn.Height)
if obj.HasLabel() {
if obj.HasLabel() && obj.LabelPosition == nil {
if len(obj.ChildrenArray) > 0 {
obj.LabelPosition = go2.Pointer(string(label.OutsideTopCenter))
} else if obj.HasOutsideBottomLabel() {
@ -251,7 +251,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
obj.LabelPosition = go2.Pointer(string(label.InsideMiddleCenter))
}
}
if obj.Icon != nil {
if obj.Icon != nil && obj.IconPosition == nil {
if len(obj.ChildrenArray) > 0 {
obj.IconPosition = go2.Pointer(string(label.OutsideTopLeft))
obj.LabelPosition = go2.Pointer(string(label.OutsideTopRight))

View file

@ -407,7 +407,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
obj.Width = math.Ceil(n.Width)
obj.Height = math.Ceil(n.Height)
if obj.HasLabel() {
if obj.HasLabel() && obj.LabelPosition == nil {
if len(obj.ChildrenArray) > 0 {
obj.LabelPosition = go2.Pointer(string(label.InsideTopCenter))
} else if obj.HasOutsideBottomLabel() {
@ -419,7 +419,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
obj.LabelPosition = go2.Pointer(string(label.InsideMiddleCenter))
}
}
if obj.Icon != nil {
if obj.Icon != nil && obj.IconPosition == nil {
if len(obj.ChildrenArray) > 0 {
obj.IconPosition = go2.Pointer(string(label.InsideTopLeft))
obj.LabelPosition = go2.Pointer(string(label.InsideTopRight))

View file

@ -8,6 +8,7 @@ import (
"sort"
"oss.terrastruct.com/d2/d2graph"
"oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/label"
"oss.terrastruct.com/util-go/go2"
@ -112,62 +113,88 @@ func withoutGridDiagrams(ctx context.Context, g *d2graph.Graph, layout d2graph.L
gd.shift(innerBox.TopLeft.X, innerBox.TopLeft.Y)
}
// compute how much space the label and icon occupy
var occupiedWidth, occupiedHeight float64
if obj.Icon != nil {
iconSpace := float64(d2target.MAX_ICON_SIZE + 2*label.PADDING)
occupiedWidth = iconSpace
occupiedHeight = iconSpace
}
var dx, dy float64
if obj.LabelDimensions.Width != 0 {
labelWidth := float64(obj.LabelDimensions.Width) + 2*label.PADDING
if labelWidth > obj.Width {
dx = (labelWidth - obj.Width) / 2
obj.Width = labelWidth
}
}
if obj.LabelDimensions.Height != 0 {
labelHeight := float64(obj.LabelDimensions.Height) + 2*label.PADDING
// also check for grid cells with outside top labels
// the first grid object is at the top (and always exists)
topY := gd.objects[0].TopLeft.Y
highestLabel := 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 < highestLabel {
highestLabel = labelTL.Y
}
}
}
}
if highestLabel < topY {
labelHeight += topY - highestLabel + 2*label.PADDING
}
if labelHeight > float64(verticalPadding) {
// if the label doesn't fit within the padding, we need to add more
grow := labelHeight - float64(verticalPadding)
dy = grow
obj.Height += grow
occupiedHeight = math.Max(
occupiedHeight,
float64(obj.LabelDimensions.Height)+2*label.PADDING,
)
}
if obj.LabelDimensions.Width != 0 {
// . ├────┤───────├────┤
// . icon label icon
// with an icon in top left we need 2x the space to fit the label in the center
occupiedWidth *= 2
occupiedWidth += float64(obj.LabelDimensions.Width) + 2*label.PADDING
if occupiedWidth > obj.Width {
dx = (occupiedWidth - obj.Width) / 2
obj.Width = occupiedWidth
}
}
// 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)
obj.Height += dy
}
// we need to center children if we have to expand to fit the container label
if dx != 0 || dy != 0 {
gd.shift(dx, dy)
}
}
if obj.LabelPosition == nil {
if obj.HasLabel() {
obj.LabelPosition = go2.Pointer(string(label.InsideTopCenter))
}
if obj.Icon != nil {
obj.IconPosition = go2.Pointer(string(label.InsideTopLeft))
}
gridDiagrams[obj.AbsID()] = gd
for _, o := range gd.objects {