diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go index 28ea03ef9..f4b99a03e 100644 --- a/d2graph/d2graph.go +++ b/d2graph/d2graph.go @@ -707,6 +707,9 @@ func (obj *Object) GetLabelSize(mtexts []*d2target.MText, ruler *textmeasure.Rul } if dims == nil { + if obj.Text().Text == "" { + return d2target.NewTextDimensions(0, 0), nil + } if shapeType == d2target.ShapeImage { dims = d2target.NewTextDimensions(0, 0) } else { @@ -728,7 +731,7 @@ func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.R return d2target.NewTextDimensions(128, 128), nil case d2target.ShapeClass: - maxWidth := labelDims.Width + maxWidth := go2.Max(12, labelDims.Width) for _, f := range obj.Class.Fields { fdims := GetTextDimensions(mtexts, ruler, f.Text(), go2.Pointer(d2fonts.SourceCodePro)) @@ -764,7 +767,7 @@ func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.R rowHeight := GetTextDimensions(mtexts, ruler, anyRowText, go2.Pointer(d2fonts.SourceCodePro)).Height + 20 dims.Height = rowHeight * (len(obj.Class.Fields) + len(obj.Class.Methods) + 2) } else { - dims.Height = labelDims.Height + dims.Height = go2.Max(12, labelDims.Height) } case d2target.ShapeSQLTable: @@ -804,10 +807,10 @@ func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.R } // The rows get padded a little due to header font being larger than row font - dims.Height = labelDims.Height * (len(obj.SQLTable.Columns) + 1) + dims.Height = go2.Max(12, labelDims.Height*(len(obj.SQLTable.Columns)+1)) headerWidth := d2target.HeaderPadding + labelDims.Width + d2target.HeaderPadding rowsWidth := d2target.NamePadding + maxNameWidth + d2target.TypePadding + maxTypeWidth + d2target.TypePadding + constraintWidth - dims.Width = go2.Max(headerWidth, rowsWidth) + dims.Width = go2.Max(12, go2.Max(headerWidth, rowsWidth)) } return &dims, nil diff --git a/e2etests/e2e_test.go b/e2etests/e2e_test.go index dcca4bba2..35a7c6c6d 100644 --- a/e2etests/e2e_test.go +++ b/e2etests/e2e_test.go @@ -37,6 +37,7 @@ func TestE2E(t *testing.T) { t.Run("stable", testStable) t.Run("regression", testRegression) t.Run("todo", testTodo) + t.Run("measured", testMeasured) } func testSanity(t *testing.T) { @@ -73,6 +74,7 @@ a -> c type testCase struct { name string script string + mtexts []*d2target.MText assertions func(t *testing.T, diagram *d2target.Diagram) skip bool } @@ -118,12 +120,16 @@ func run(t *testing.T, tc testCase) { ctx = log.WithTB(ctx, t, nil) ctx = log.Leveled(ctx, slog.LevelDebug) - ruler, err := textmeasure.NewRuler() - if !tassert.Nil(t, err) { - return - } + var ruler *textmeasure.Ruler + var err error + if tc.mtexts == nil { + ruler, err = textmeasure.NewRuler() + if !tassert.Nil(t, err) { + return + } - serde(t, tc, ruler) + serde(t, tc, ruler) + } layoutsTested := []string{"dagre", "elk"} @@ -132,12 +138,17 @@ func run(t *testing.T, tc testCase) { if layoutName == "dagre" { layout = d2dagrelayout.DefaultLayout } else if layoutName == "elk" { + // If measured texts exists, we are specifically exercising text measurements, no need to run on both layouts + if tc.mtexts != nil { + continue + } layout = d2elklayout.DefaultLayout } diagram, _, err := d2lib.Compile(ctx, tc.script, &d2lib.CompileOptions{ - Ruler: ruler, - ThemeID: 0, - Layout: layout, + Ruler: ruler, + MeasuredTexts: tc.mtexts, + ThemeID: 0, + Layout: layout, }) if !tassert.Nil(t, err) { return diff --git a/e2etests/measured_test.go b/e2etests/measured_test.go new file mode 100644 index 000000000..777fda482 --- /dev/null +++ b/e2etests/measured_test.go @@ -0,0 +1,34 @@ +package e2etests + +import ( + _ "embed" + "testing" + + "oss.terrastruct.com/d2/d2target" +) + +// testMeasured exercises the code paths that provide pre-measured texts +func testMeasured(t *testing.T) { + tcs := []testCase{ + { + name: "empty-shape", + mtexts: []*d2target.MText{}, + script: `a: "" +`, + }, + { + name: "empty-class", + mtexts: []*d2target.MText{}, + script: `a: "" { shape: class } +`, + }, + { + name: "empty-sql_table", + mtexts: []*d2target.MText{}, + script: `a: "" { shape: sql_table } +`, + }, + } + + runa(t, tcs) +} diff --git a/e2etests/testdata/measured/empty-class/dagre/board.exp.json b/e2etests/testdata/measured/empty-class/dagre/board.exp.json new file mode 100644 index 000000000..1f92e5b45 --- /dev/null +++ b/e2etests/testdata/measured/empty-class/dagre/board.exp.json @@ -0,0 +1,49 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "class", + "pos": { + "x": 0, + "y": 0 + }, + "width": 112, + "height": 12, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#0A0F25", + "stroke": "#FFFFFF", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 20, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 1, + "primaryAccentColor": "#0D32B2", + "secondaryAccentColor": "#4A6FF3", + "neutralAccentColor": "#676C7E" + } + ], + "connections": [] +} diff --git a/e2etests/testdata/measured/empty-class/dagre/sketch.exp.svg b/e2etests/testdata/measured/empty-class/dagre/sketch.exp.svg new file mode 100644 index 000000000..830b5caa3 --- /dev/null +++ b/e2etests/testdata/measured/empty-class/dagre/sketch.exp.svg @@ -0,0 +1,45 @@ + + + + + \ No newline at end of file diff --git a/e2etests/testdata/measured/empty-shape/dagre/board.exp.json b/e2etests/testdata/measured/empty-shape/dagre/board.exp.json new file mode 100644 index 000000000..bf4da9d37 --- /dev/null +++ b/e2etests/testdata/measured/empty-shape/dagre/board.exp.json @@ -0,0 +1,46 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 100, + "height": 100, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 1 + } + ], + "connections": [] +} diff --git a/e2etests/testdata/measured/empty-shape/dagre/sketch.exp.svg b/e2etests/testdata/measured/empty-shape/dagre/sketch.exp.svg new file mode 100644 index 000000000..1acdbb250 --- /dev/null +++ b/e2etests/testdata/measured/empty-shape/dagre/sketch.exp.svg @@ -0,0 +1,45 @@ + + + + + \ No newline at end of file diff --git a/e2etests/testdata/measured/empty-sql_table/dagre/board.exp.json b/e2etests/testdata/measured/empty-sql_table/dagre/board.exp.json new file mode 100644 index 000000000..dcd887dd3 --- /dev/null +++ b/e2etests/testdata/measured/empty-sql_table/dagre/board.exp.json @@ -0,0 +1,49 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "a", + "type": "sql_table", + "pos": { + "x": 0, + "y": 0 + }, + "width": 50, + "height": 12, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#0A0F25", + "stroke": "#FFFFFF", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 20, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 1, + "primaryAccentColor": "#0D32B2", + "secondaryAccentColor": "#4A6FF3", + "neutralAccentColor": "#676C7E" + } + ], + "connections": [] +} diff --git a/e2etests/testdata/measured/empty-sql_table/dagre/sketch.exp.svg b/e2etests/testdata/measured/empty-sql_table/dagre/sketch.exp.svg new file mode 100644 index 000000000..69d917f3c --- /dev/null +++ b/e2etests/testdata/measured/empty-sql_table/dagre/sketch.exp.svg @@ -0,0 +1,45 @@ + + + + + \ No newline at end of file