Merge pull request #1591 from gavin-ts/fix-multiple-constant-nears

Fix multiple constant nears
This commit is contained in:
gavin-ts 2023-09-18 22:25:49 -07:00 committed by GitHub
commit 833843a1cb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 1268 additions and 11 deletions

View file

@ -14,3 +14,4 @@
- Fixes `d2 fmt` to format all files passed as arguments rather than first non-formatted only [#1523](https://github.com/terrastruct/d2/issues/1523)
- Fixes Markdown cropping last element in mixed-element blocks (e.g. em and strong) [#1543](https://github.com/terrastruct/d2/issues/1543)
- Fixes missing compile error for non-blockstring empty labels [#1590](https://github.com/terrastruct/d2/issues/1590)
- Fixes multiple constant nears overlapping in some cases [#1591](https://github.com/terrastruct/d2/issues/1591)

View file

@ -14,6 +14,23 @@ import (
const pad = 20
type set map[string]struct{}
var HorizontalCenterNears = set{
"center-left": {},
"center-right": {},
}
var VerticalCenterNears = set{
"top-center": {},
"bottom-center": {},
}
var NonCenterNears = set{
"top-left": {},
"top-right": {},
"bottom-left": {},
"bottom-right": {},
}
// Layout finds the shapes which are assigned constant near keywords and places them.
func Layout(ctx context.Context, g *d2graph.Graph, constantNearGraphs []*d2graph.Graph) error {
if len(constantNearGraphs) == 0 {
@ -30,10 +47,11 @@ func Layout(ctx context.Context, g *d2graph.Graph, constantNearGraphs []*d2graph
// Imagine the graph has two long texts, one at top center and one at top left.
// Top left should go left enough to not collide with center.
// So place the center ones first, then the later ones will consider them for bounding box
for _, processCenters := range []bool{true, false} {
for _, currentSet := range []set{VerticalCenterNears, HorizontalCenterNears, NonCenterNears} {
for _, tempGraph := range constantNearGraphs {
obj := tempGraph.Root.ChildrenArray[0]
if processCenters == strings.Contains(d2graph.Key(obj.NearKey)[0], "-center") {
_, in := currentSet[d2graph.Key(obj.NearKey)[0]]
if in {
prevX, prevY := obj.TopLeft.X, obj.TopLeft.Y
obj.TopLeft = geo.NewPoint(place(obj))
dx, dy := obj.TopLeft.X-prevX, obj.TopLeft.Y-prevY
@ -56,7 +74,8 @@ func Layout(ctx context.Context, g *d2graph.Graph, constantNearGraphs []*d2graph
}
for _, tempGraph := range constantNearGraphs {
obj := tempGraph.Root.ChildrenArray[0]
if processCenters == strings.Contains(d2graph.Key(obj.NearKey)[0], "-center") {
_, in := currentSet[d2graph.Key(obj.NearKey)[0]]
if in {
// The z-index for constant nears does not matter, as it will not collide
g.Objects = append(g.Objects, tempGraph.Objects...)
if obj.Parent.Children == nil {
@ -83,28 +102,20 @@ func place(obj *d2graph.Object) (float64, float64) {
switch nearKeyStr {
case "top-left":
x, y = tl.X-obj.Width-pad, tl.Y-obj.Height-pad
break
case "top-center":
x, y = tl.X+w/2-obj.Width/2, tl.Y-obj.Height-pad
break
case "top-right":
x, y = br.X+pad, tl.Y-obj.Height-pad
break
case "center-left":
x, y = tl.X-obj.Width-pad, tl.Y+h/2-obj.Height/2
break
case "center-right":
x, y = br.X+pad, tl.Y+h/2-obj.Height/2
break
case "bottom-left":
x, y = tl.X-obj.Width-pad, br.Y+pad
break
case "bottom-center":
x, y = br.X-w/2-obj.Width/2, br.Y+pad
break
case "bottom-right":
x, y = br.X+pad, br.Y+pad
break
}
if obj.LabelPosition != nil && !strings.Contains(*obj.LabelPosition, "INSIDE") {

View file

@ -1039,6 +1039,7 @@ cf many required: {
loadFromFile(t, "dagre_disconnected_edge"),
loadFromFile(t, "outside_grid_label_position"),
loadFromFile(t, "arrowhead_font_color"),
loadFromFile(t, "multiple_constant_nears"),
}
runa(t, tcs)

View file

@ -0,0 +1,17 @@
a
b
c
a: {
1 -> 2 -> 3
near: center-right
style.fill: red
style.opacity: 0.5
}
b: {
1111 -> 2222
near: bottom-right
style.fill: green
style.opacity: 0.5
}

View file

@ -0,0 +1,518 @@
{
"name": "",
"isFolderOnly": false,
"fontFamily": "SourceSansPro",
"shapes": [
{
"id": "c",
"type": "rectangle",
"pos": {
"x": 0,
"y": 0
},
"width": 53,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "c",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 8,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "a",
"type": "rectangle",
"pos": {
"x": 73,
"y": -196
},
"width": 113,
"height": 458,
"opacity": 0.5,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "red",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "a",
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 12,
"labelHeight": 36,
"labelPosition": "OUTSIDE_TOP_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "a.1",
"type": "rectangle",
"pos": {
"x": 104,
"y": -166
},
"width": 52,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "1",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 7,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "a.2",
"type": "rectangle",
"pos": {
"x": 103,
"y": 0
},
"width": 53,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "2",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 8,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "a.3",
"type": "rectangle",
"pos": {
"x": 103,
"y": 166
},
"width": 53,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "3",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 8,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "b",
"type": "rectangle",
"pos": {
"x": 73,
"y": 318
},
"width": 139,
"height": 292,
"opacity": 0.5,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "green",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "b",
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 13,
"labelHeight": 36,
"labelPosition": "OUTSIDE_TOP_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "b.1111",
"type": "rectangle",
"pos": {
"x": 104,
"y": 348
},
"width": 78,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "1111",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 33,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "b.2222",
"type": "rectangle",
"pos": {
"x": 103,
"y": 514
},
"width": 79,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "2222",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 34,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
}
],
"connections": [
{
"id": "a.(1 -> 2)[0]",
"src": "a.1",
"srcArrow": "none",
"dst": "a.2",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 129.5,
"y": -100
},
{
"x": 129.5,
"y": -60
},
{
"x": 129.5,
"y": -40
},
{
"x": 129.5,
"y": 0
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "a.(2 -> 3)[0]",
"src": "a.2",
"srcArrow": "none",
"dst": "a.3",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 129.5,
"y": 66
},
{
"x": 129.5,
"y": 106
},
{
"x": 129.5,
"y": 126
},
{
"x": 129.5,
"y": 166
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "b.(1111 -> 2222)[0]",
"src": "b.1111",
"srcArrow": "none",
"dst": "b.2222",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 142.5,
"y": 414
},
{
"x": 142.5,
"y": 454
},
{
"x": 142.5,
"y": 474
},
{
"x": 142.5,
"y": 514
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
}
],
"root": {
"id": "",
"type": "",
"pos": {
"x": 0,
"y": 0
},
"width": 0,
"height": 0,
"opacity": 0,
"strokeDash": 0,
"strokeWidth": 0,
"borderRadius": 0,
"fill": "N7",
"stroke": "",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "",
"fontSize": 0,
"fontFamily": "",
"language": "",
"color": "",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"zIndex": 0,
"level": 0
}
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

View file

@ -0,0 +1,491 @@
{
"name": "",
"isFolderOnly": false,
"fontFamily": "SourceSansPro",
"shapes": [
{
"id": "c",
"type": "rectangle",
"pos": {
"x": 12,
"y": 12
},
"width": 53,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "c",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 8,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "a",
"type": "rectangle",
"pos": {
"x": 85,
"y": -174
},
"width": 153,
"height": 438,
"opacity": 0.5,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "red",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "a",
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 12,
"labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "a.1",
"type": "rectangle",
"pos": {
"x": 135,
"y": -124
},
"width": 52,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "1",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 7,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "a.2",
"type": "rectangle",
"pos": {
"x": 135,
"y": 12
},
"width": 53,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "2",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 8,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "a.3",
"type": "rectangle",
"pos": {
"x": 135,
"y": 148
},
"width": 53,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "3",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 8,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "b",
"type": "rectangle",
"pos": {
"x": 85,
"y": 284
},
"width": 179,
"height": 302,
"opacity": 0.5,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "green",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "b",
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 13,
"labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "b.1111",
"type": "rectangle",
"pos": {
"x": 135,
"y": 334
},
"width": 78,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "1111",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 33,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
},
{
"id": "b.2222",
"type": "rectangle",
"pos": {
"x": 135,
"y": 470
},
"width": 79,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "2222",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 34,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 2
}
],
"connections": [
{
"id": "a.(1 -> 2)[0]",
"src": "a.1",
"srcArrow": "none",
"dst": "a.2",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 161.5,
"y": -58
},
{
"x": 161.5,
"y": 12
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "a.(2 -> 3)[0]",
"src": "a.2",
"srcArrow": "none",
"dst": "a.3",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 161.5,
"y": 78
},
{
"x": 161.5,
"y": 148
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "b.(1111 -> 2222)[0]",
"src": "b.1111",
"srcArrow": "none",
"dst": "b.2222",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"labelPosition": "",
"labelPercentage": 0,
"route": [
{
"x": 174.5,
"y": 400
},
{
"x": 174.5,
"y": 470
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
}
],
"root": {
"id": "",
"type": "",
"pos": {
"x": 0,
"y": 0
},
"width": 0,
"height": 0,
"opacity": 0,
"strokeDash": 0,
"strokeWidth": 0,
"borderRadius": 0,
"fill": "N7",
"stroke": "",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "",
"fontSize": 0,
"fontFamily": "",
"language": "",
"color": "",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"zIndex": 0,
"level": 0
}
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB