From d116f7d9184c796a6423620fac5ccdaf921f2a5c Mon Sep 17 00:00:00 2001 From: Gavin Nishizawa Date: Wed, 3 May 2023 19:34:57 -0700 Subject: [PATCH] size grid container according to shape --- d2graph/d2graph.go | 51 ++++++++++++++++++++---------------- d2layouts/d2grid/layout.go | 53 ++++++++++++++++++++++++-------------- 2 files changed, 63 insertions(+), 41 deletions(-) diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go index 1bab9c273..86240947a 100644 --- a/d2graph/d2graph.go +++ b/d2graph/d2graph.go @@ -1052,6 +1052,34 @@ func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.R return &dims, nil } +func (obj *Object) SizeToContent(contentBox *geo.Box, paddingX, paddingY, desiredWidth, desiredHeight float64, labelDims d2target.TextDimensions) { + dslShape := strings.ToLower(obj.Shape.Value) + shapeType := d2target.DSL_SHAPE_TO_SHAPE_TYPE[dslShape] + s := shape.NewShape(shapeType, contentBox) + + var fitWidth, fitHeight float64 + if shapeType == shape.PERSON_TYPE { + fitWidth = contentBox.Width + paddingX + fitHeight = contentBox.Height + paddingY + } else { + fitWidth, fitHeight = s.GetDimensionsToFit(contentBox.Width, contentBox.Height, paddingX, paddingY) + } + obj.Width = math.Max(float64(desiredWidth), fitWidth) + obj.Height = math.Max(float64(desiredHeight), fitHeight) + if s.AspectRatio1() { + sideLength := math.Max(obj.Width, obj.Height) + obj.Width = sideLength + obj.Height = sideLength + } else if desiredHeight == 0 || desiredWidth == 0 { + switch s.GetType() { + case shape.PERSON_TYPE: + obj.Width, obj.Height = shape.LimitAR(obj.Width, obj.Height, shape.PERSON_AR_LIMIT) + case shape.OVAL_TYPE: + obj.Width, obj.Height = shape.LimitAR(obj.Width, obj.Height, shape.OVAL_AR_LIMIT) + } + } +} + func (obj *Object) OuterNearContainer() *Object { for obj != nil { if obj.NearKey != nil { @@ -1435,7 +1463,6 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler contentBox := geo.NewBox(geo.NewPoint(0, 0), float64(defaultDims.Width), float64(defaultDims.Height)) shapeType := d2target.DSL_SHAPE_TO_SHAPE_TYPE[dslShape] s := shape.NewShape(shapeType, contentBox) - paddingX, paddingY := s.GetDefaultPadding() if desiredWidth != 0 { paddingX = 0. @@ -1468,27 +1495,7 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler } } - var fitWidth, fitHeight float64 - if shapeType == shape.PERSON_TYPE { - fitWidth = contentBox.Width + paddingX - fitHeight = contentBox.Height + paddingY - } else { - fitWidth, fitHeight = s.GetDimensionsToFit(contentBox.Width, contentBox.Height, paddingX, paddingY) - } - obj.Width = math.Max(float64(desiredWidth), fitWidth) - obj.Height = math.Max(float64(desiredHeight), fitHeight) - if s.AspectRatio1() { - sideLength := math.Max(obj.Width, obj.Height) - obj.Width = sideLength - obj.Height = sideLength - } else if desiredHeight == 0 || desiredWidth == 0 { - switch s.GetType() { - case shape.PERSON_TYPE: - obj.Width, obj.Height = shape.LimitAR(obj.Width, obj.Height, shape.PERSON_AR_LIMIT) - case shape.OVAL_TYPE: - obj.Width, obj.Height = shape.LimitAR(obj.Width, obj.Height, shape.OVAL_AR_LIMIT) - } - } + obj.SizeToContent(contentBox, paddingX, paddingY, float64(desiredWidth), float64(desiredHeight), *labelDims) } for _, edge := range g.Edges { usedFont := fontFamily diff --git a/d2layouts/d2grid/layout.go b/d2layouts/d2grid/layout.go index dd87f4cb6..2e8d4f30d 100644 --- a/d2layouts/d2grid/layout.go +++ b/d2layouts/d2grid/layout.go @@ -5,10 +5,13 @@ import ( "fmt" "math" "sort" + "strings" "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/d2/lib/shape" "oss.terrastruct.com/util-go/go2" ) @@ -70,26 +73,38 @@ func withoutGridDiagrams(ctx context.Context, g *d2graph.Graph) (gridDiagrams ma obj.Children = make(map[string]*d2graph.Object) obj.ChildrenArray = nil - var dx, dy float64 - width := gd.width + 2*CONTAINER_PADDING - labelWidth := float64(obj.LabelDimensions.Width) + 2*label.PADDING - if labelWidth > width { - dx = (labelWidth - width) / 2 - width = labelWidth + if obj.Box != nil { + // size shape according to grid + contentBox := geo.NewBox(geo.NewPoint(0, 0), float64(gd.width), float64(gd.height)) + obj.SizeToContent(contentBox, 2*CONTAINER_PADDING, 2*CONTAINER_PADDING, 0, 0, obj.LabelDimensions) + + // compute where the grid should be placed inside shape + dslShape := strings.ToLower(obj.Shape.Value) + shapeType := d2target.DSL_SHAPE_TO_SHAPE_TYPE[dslShape] + s := shape.NewShape(shapeType, geo.NewBox(geo.NewPoint(0, 0), obj.Width, obj.Height)) + innerBox := s.GetInnerBox() + if innerBox.TopLeft.X != 0 || innerBox.TopLeft.Y != 0 { + gd.shift(innerBox.TopLeft.X, innerBox.TopLeft.Y) + } + + var dx, dy float64 + labelWidth := float64(obj.LabelDimensions.Width) + 2*label.PADDING + if labelWidth > obj.Width { + dx = (labelWidth - obj.Width) / 2 + obj.Width = labelWidth + } + labelHeight := float64(obj.LabelDimensions.Height) + 2*label.PADDING + if labelHeight > CONTAINER_PADDING { + // if the label doesn't fit within the padding, we need to add more + grow := labelHeight - CONTAINER_PADDING + dy = grow / 2 + obj.Height += grow + } + // we need to center children if we have to expand to fit the container label + if dx != 0 || dy != 0 { + gd.shift(dx, dy) + } } - height := gd.height + 2*CONTAINER_PADDING - labelHeight := float64(obj.LabelDimensions.Height) + 2*label.PADDING - if labelHeight > CONTAINER_PADDING { - // if the label doesn't fit within the padding, we need to add more - grow := labelHeight - CONTAINER_PADDING - dy = grow / 2 - height += grow - } - // we need to center children if we have to expand to fit the container label - if dx != 0 || dy != 0 { - gd.shift(dx, dy) - } - obj.Box = geo.NewBox(nil, width, height) obj.LabelPosition = go2.Pointer(string(label.InsideTopCenter)) gridDiagrams[obj.AbsID()] = gd