diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go index 8b01bc9642..cd5661edbd 100644 --- a/d2graph/d2graph.go +++ b/d2graph/d2graph.go @@ -1951,6 +1951,10 @@ func (obj *Object) Is3D() bool { } func (obj *Object) Spacing() (margin, padding geo.Spacing) { + return obj.SpacingOpt(2*label.PADDING, 2*label.PADDING, true) +} + +func (obj *Object) SpacingOpt(labelPadding, iconPadding float64, maxIconSize bool) (margin, padding geo.Spacing) { if obj.HasLabel() { var position label.Position if obj.LabelPosition != nil { @@ -1959,10 +1963,10 @@ func (obj *Object) Spacing() (margin, padding geo.Spacing) { var labelWidth, labelHeight float64 if obj.LabelDimensions.Width > 0 { - labelWidth = float64(obj.LabelDimensions.Width) + 2*label.PADDING + labelWidth = float64(obj.LabelDimensions.Width) + labelPadding } if obj.LabelDimensions.Height > 0 { - labelHeight = float64(obj.LabelDimensions.Height) + 2*label.PADDING + labelHeight = float64(obj.LabelDimensions.Height) + labelPadding } switch position { @@ -1991,7 +1995,10 @@ func (obj *Object) Spacing() (margin, padding geo.Spacing) { position = label.FromString(*obj.IconPosition) } - iconSize := float64(d2target.MAX_ICON_SIZE + 2*label.PADDING) + iconSize := float64(d2target.MAX_ICON_SIZE + iconPadding) + if !maxIconSize { + iconSize = float64(d2target.GetIconSize(obj.Box, position.String())) + iconPadding + } switch position { case label.OutsideTopLeft, label.OutsideTopCenter, label.OutsideTopRight: margin.Top = math.Max(margin.Top, iconSize) diff --git a/d2graph/layout.go b/d2graph/layout.go index 907b6b7f68..d8228c3462 100644 --- a/d2graph/layout.go +++ b/d2graph/layout.go @@ -464,11 +464,6 @@ func (edge *Edge) TraceToShape(points []*geo.Point, startIndex, endIndex int) (n iconTL := iconPosition.GetPointOnBox(edge.Src.Box, label.PADDING, iconWidth, iconHeight) iconBox := geo.NewBox(iconTL, iconWidth, iconHeight) - // TODO not for icons - // add left/right padding to box - iconBox.TopLeft.X -= label.PADDING - iconBox.Width += 2 * label.PADDING - for iconBox.Contains(startingSegment.End) && startIndex+1 > endIndex { startingSegment.Start = startingSegment.End startingSegment.End = points[startIndex+2] @@ -555,10 +550,6 @@ func (edge *Edge) TraceToShape(points []*geo.Point, startIndex, endIndex int) (n fmt.Printf("\thas dst outside icon %v\n", iconPosition.String()) iconBox := geo.NewBox(labelTL, iconWidth, iconHeight) - // TODO not for icons - // add left/right padding to box - iconBox.TopLeft.X -= label.PADDING - iconBox.Width += 2 * label.PADDING for iconBox.Contains(endingSegment.Start) && endIndex-1 > startIndex { endingSegment.End = endingSegment.Start endingSegment.Start = points[endIndex-2] @@ -587,7 +578,7 @@ func (edge *Edge) TraceToShape(points []*geo.Point, startIndex, endIndex int) (n } } if !overlapsOutsideLabel && !overlapsOutsideIcon { - fmt.Printf("\ttracing to shape\n") + fmt.Printf("\ttracing to shape %v segment %v\n", edge.Dst.Box.ToString(), endingSegment.ToString()) if intersections := edge.Dst.Intersections(endingSegment); len(intersections) > 0 { fmt.Printf("\tfound intersection\n") // move ending segment to intersection point diff --git a/d2layouts/d2elklayout/layout.go b/d2layouts/d2elklayout/layout.go index a9a34a7cbc..a303d2e610 100644 --- a/d2layouts/d2elklayout/layout.go +++ b/d2layouts/d2elklayout/layout.go @@ -218,6 +218,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err positionLabelsIcons(obj) } + adjustments := make(map[*d2graph.Object]geo.Spacing) elkNodes := make(map[*d2graph.Object]*ELKNode) elkEdges := make(map[*d2graph.Edge]*ELKEdge) @@ -256,7 +257,10 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err } } - width, height := adjustDimensions(obj) + margin, _ := obj.SpacingOpt(2*label.PADDING, 0, false) + width := margin.Left + obj.Width + margin.Right + height := margin.Top + obj.Height + margin.Bottom + adjustments[obj] = margin n := &ELKNode{ ID: obj.AbsID(), @@ -537,7 +541,28 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err } for _, obj := range g.Objects { - cleanupAdjustment(obj) + if margin, has := adjustments[obj]; has { + // TODO adjust edges on the shrinking sides or trace to shape from outside box + if margin.Left > 0 { + obj.TopLeft.X += margin.Left + obj.ShiftDescendants(margin.Left, 0) + obj.Width -= margin.Left + } + if margin.Right > 0 { + // TODO is this right? + obj.ShiftDescendants(-margin.Right/2, 0) + obj.Width -= margin.Right + } + if margin.Top > 0 { + obj.TopLeft.Y += margin.Top + obj.ShiftDescendants(margin.Top, 0) + obj.Height -= margin.Top + } + if margin.Bottom > 0 { + obj.ShiftDescendants(-margin.Bottom/2, 0) + obj.Height -= margin.Bottom + } + } } for _, edge := range g.Edges { @@ -1050,143 +1075,6 @@ func adjustPadding(obj *d2graph.Object, width, height float64, padding shapePadd return padding } -func adjustDimensions(obj *d2graph.Object) (width, height float64) { - width = obj.Width - height = obj.Height - - // reserve spacing for labels - if obj.HasLabel() { - var position label.Position - if obj.LabelPosition != nil { - position = label.FromString(*obj.LabelPosition) - } else if len(obj.ChildrenArray) == 0 && obj.HasOutsideBottomLabel() { - position = label.OutsideBottomCenter - } - - if position.IsShapePosition() { - switch position { - case label.OutsideLeftTop, label.OutsideLeftMiddle, label.OutsideLeftBottom, - label.OutsideRightTop, label.OutsideRightMiddle, label.OutsideRightBottom: - width += float64(obj.LabelDimensions.Width) + label.PADDING - case label.OutsideTopLeft, label.OutsideTopCenter, label.OutsideTopRight, - label.OutsideBottomLeft, label.OutsideBottomCenter, label.OutsideBottomRight: - height += float64(obj.LabelDimensions.Height) + label.PADDING - default: - width = go2.Max(width, float64(obj.LabelDimensions.Width)+2*label.PADDING) - height = go2.Max(height, float64(obj.LabelDimensions.Height)+2*label.PADDING) - } - } - - // // special handling - // if obj.Icon != nil { - // height += float64(obj.LabelDimensions.Height) + label.PADDING - // } - } - - if obj.Icon != nil && obj.Shape.Value != d2target.ShapeImage { - var position label.Position - if obj.IconPosition != nil { - position = label.FromString(*obj.IconPosition) - } - - if position.IsShapePosition() { - switch position { - case label.OutsideLeftTop, label.OutsideLeftMiddle, label.OutsideLeftBottom, - label.OutsideRightTop, label.OutsideRightMiddle, label.OutsideRightBottom: - width += d2target.MAX_ICON_SIZE + label.PADDING - case label.OutsideTopLeft, label.OutsideTopCenter, label.OutsideTopRight, - label.OutsideBottomLeft, label.OutsideBottomCenter, label.OutsideBottomRight: - height += d2target.MAX_ICON_SIZE + label.PADDING - default: - width = go2.Max(width, d2target.MAX_ICON_SIZE+2*label.PADDING) - height = go2.Max(height, d2target.MAX_ICON_SIZE+2*label.PADDING) - } - } - } - - // reserve extra space for 3d/multiple by providing elk the larger dimensions - dx, dy := obj.GetModifierElementAdjustments() - width += dx - height += dy - - return -} - -func cleanupAdjustment(obj *d2graph.Object) { - // adjust size and position to account for space reserved for labels - if obj.HasLabel() { - position := label.FromString(*obj.LabelPosition) - if position.IsShapePosition() { - var labelWidth, labelHeight float64 - switch position { - case label.OutsideLeftTop, label.OutsideLeftMiddle, label.OutsideLeftBottom, - label.OutsideRightTop, label.OutsideRightMiddle, label.OutsideRightBottom: - labelWidth = float64(obj.LabelDimensions.Width) + label.PADDING - obj.Width -= labelWidth - case label.OutsideTopLeft, label.OutsideTopCenter, label.OutsideTopRight, - label.OutsideBottomLeft, label.OutsideBottomCenter, label.OutsideBottomRight: - labelHeight = float64(obj.LabelDimensions.Height) + label.PADDING - obj.Height -= labelHeight - } - switch position { - case label.OutsideLeftTop, label.OutsideLeftMiddle, label.OutsideLeftBottom: - obj.TopLeft.X += labelWidth - obj.ShiftDescendants(labelWidth/2, 0) - case label.OutsideRightTop, label.OutsideRightMiddle, label.OutsideRightBottom: - obj.ShiftDescendants(-labelWidth/2, 0) - case label.OutsideTopLeft, label.OutsideTopCenter, label.OutsideTopRight: - obj.TopLeft.Y += labelHeight - obj.ShiftDescendants(0, labelHeight/2) - case label.OutsideBottomLeft, label.OutsideBottomCenter, label.OutsideBottomRight: - obj.ShiftDescendants(0, -labelHeight/2) - } - } - } - if obj.Icon != nil && obj.Shape.Value != d2target.ShapeImage { - position := label.FromString(*obj.IconPosition) - if position.IsShapePosition() { - iconSize := float64(d2target.MAX_ICON_SIZE + label.PADDING) - switch position { - case label.OutsideLeftTop, label.OutsideLeftMiddle, label.OutsideLeftBottom, - label.OutsideRightTop, label.OutsideRightMiddle, label.OutsideRightBottom: - obj.Width -= iconSize - case label.OutsideTopLeft, label.OutsideTopCenter, label.OutsideTopRight, - label.OutsideBottomLeft, label.OutsideBottomCenter, label.OutsideBottomRight: - obj.Height -= iconSize - } - switch position { - case label.OutsideLeftTop, label.OutsideLeftMiddle, label.OutsideLeftBottom: - obj.TopLeft.X += iconSize - obj.ShiftDescendants(iconSize/2, 0) - case label.OutsideRightTop, label.OutsideRightMiddle, label.OutsideRightBottom: - obj.ShiftDescendants(-iconSize/2, 0) - case label.OutsideTopLeft, label.OutsideTopCenter, label.OutsideTopRight: - obj.TopLeft.Y += iconSize - obj.ShiftDescendants(0, iconSize/2) - case label.OutsideBottomLeft, label.OutsideBottomCenter, label.OutsideBottomRight: - obj.ShiftDescendants(0, -iconSize/2) - } - } - } - - // // special handling to start/end connections below label - // if obj.HasOutsideBottomLabel() { - // obj.Height -= float64(obj.LabelDimensions.Height) + label.PADDING - // } - - // remove the extra width/height we added for 3d/multiple after all objects/connections are placed - // and shift the shapes down accordingly - dx, dy := obj.GetModifierElementAdjustments() - if dx != 0 || dy != 0 { - obj.TopLeft.Y += dy - obj.ShiftDescendants(0, dy) - if !obj.IsContainer() { - obj.Width -= dx - obj.Height -= dy - } - } -} - func positionLabelsIcons(obj *d2graph.Object) { if obj.Icon != nil && obj.IconPosition == nil { if len(obj.ChildrenArray) > 0 {