Add box arrowheads

This commit is contained in:
Adam 2024-12-18 17:40:01 +00:00
parent 1ea36d5d39
commit d61287dec5
No known key found for this signature in database
GPG key ID: AFEEFC10154D1D86
22 changed files with 4792 additions and 548 deletions

View file

@ -4,6 +4,7 @@
- Connections now support `link` [#1955](https://github.com/terrastruct/d2/pull/1955)
- Vars: vars in markdown blocks are substituted [#2218](https://github.com/terrastruct/d2/pull/2218)
- Markdown: Github-flavored tables work in `md` blocks [#2221](https://github.com/terrastruct/d2/pull/2221)
- Adds box arrowheads [#2227](https://github.com/terrastruct/d2/issues/2227)
#### Improvements 🧹

View file

@ -850,6 +850,22 @@ func ArrowheadJS(r *Runner, arrowhead d2target.Arrowhead, stroke string, strokeW
stroke,
BG_COLOR,
)
case d2target.BoxArrowhead:
arrowJS = fmt.Sprintf(
`node = rc.polygon(%s, { strokeWidth: %d, stroke: "%s", fill: "%s", fillStyle: "solid", seed: 1})`,
`[[0, -10], [0, 10], [-20, 10], [-20, -10]]`,
strokeWidth,
stroke,
BG_COLOR,
)
case d2target.FilledBoxArrowhead:
arrowJS = fmt.Sprintf(
`node = rc.polygon(%s, { strokeWidth: %d, stroke: "%s", fill: "%s", fillStyle: "solid", seed: 1})`,
`[[0, -10], [0, 10], [-20, 10], [-20, -10]]`,
strokeWidth,
stroke,
stroke,
)
}
return
}

View file

@ -462,6 +462,20 @@ a.9 <-> b.9: cf-one-required {
source-arrowhead.shape: cf-one-required
target-arrowhead.shape: cf-one-required
}
a.10 <-> b.10: box {
source-arrowhead.shape: box
target-arrowhead.shape: box
}
a.11 <-> b.11: box-filled {
source-arrowhead: {
shape: box
style.filled: true
}
target-arrowhead: {
shape: box
style.filled: true
}
}
`,
},
{

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 145 KiB

View file

@ -285,6 +285,51 @@ func arrowheadMarker(isTarget bool, id string, connection d2target.Connection, i
}
path = circleEl.Render()
case d2target.FilledBoxArrowhead:
polygonEl := d2themes.NewThemableElement("polygon", inlineTheme)
polygonEl.ClassName = "connection"
polygonEl.Fill = connection.Stroke
polygonEl.Attributes = fmt.Sprintf(`stroke-width="%d"`, connection.StrokeWidth)
if isTarget {
polygonEl.Points = fmt.Sprintf("%f,%f %f,%f %f,%f %f,%f",
0., 0.,
0., height,
width, height,
width, 0.,
)
} else {
polygonEl.Points = fmt.Sprintf("%f,%f %f,%f %f,%f %f,%f",
0., 0.,
0., height,
width, height,
width, 0.,
)
}
path = polygonEl.Render()
case d2target.BoxArrowhead:
polygonEl := d2themes.NewThemableElement("polygon", inlineTheme)
polygonEl.ClassName = "connection"
polygonEl.Fill = d2target.BG_COLOR
polygonEl.Stroke = connection.Stroke
polygonEl.Attributes = fmt.Sprintf(`stroke-width="%d"`, connection.StrokeWidth)
if isTarget {
polygonEl.Points = fmt.Sprintf("%f,%f %f,%f %f,%f %f,%f",
0., 0.,
0., height,
width, height,
width, 0.,
)
} else {
polygonEl.Points = fmt.Sprintf("%f,%f %f,%f %f,%f %f,%f",
0., 0.,
0., height,
width, height,
width, 0.,
)
}
path = polygonEl.Render()
case d2target.CfOne, d2target.CfMany, d2target.CfOneRequired, d2target.CfManyRequired:
offset := 3.0 + float64(connection.StrokeWidth)*1.8

View file

@ -752,6 +752,8 @@ const (
FilledDiamondArrowhead Arrowhead = "filled-diamond"
CircleArrowhead Arrowhead = "circle"
FilledCircleArrowhead Arrowhead = "filled-circle"
BoxArrowhead Arrowhead = "box"
FilledBoxArrowhead Arrowhead = "filled-box"
// For fat arrows
LineArrowhead Arrowhead = "line"
@ -772,6 +774,7 @@ var Arrowheads = map[string]struct{}{
string(TriangleArrowhead): {},
string(DiamondArrowhead): {},
string(CircleArrowhead): {},
string(BoxArrowhead): {},
string(CfOne): {},
string(CfMany): {},
string(CfOneRequired): {},
@ -799,6 +802,11 @@ func ToArrowhead(arrowheadType string, filled *bool) Arrowhead {
return UnfilledTriangleArrowhead
}
return TriangleArrowhead
case string(BoxArrowhead):
if filled != nil && *filled {
return FilledBoxArrowhead
}
return BoxArrowhead
case string(CfOne):
return CfOne
case string(CfMany):
@ -853,6 +861,11 @@ func (arrowhead Arrowhead) Dimensions(strokeWidth float64) (width, height float6
baseHeight = 8
widthMultiplier = 5
heightMultiplier = 5
case FilledBoxArrowhead, BoxArrowhead:
baseWidth = 6
baseHeight = 6
widthMultiplier = 5
heightMultiplier = 5
case CfOne, CfMany, CfOneRequired, CfManyRequired:
baseWidth = 9
baseHeight = 9

View file

@ -2325,6 +2325,29 @@ c <-> d: filled-circle {
shape: circle
style.filled: true
}
}`,
},
{
name: "box_arrowhead",
script: `
a <-> b: box {
source-arrowhead: {
shape: box
}
target-arrowhead: {
shape: box
}
}
c <-> d: filled-box {
source-arrowhead: {
shape: box
style.filled: true
}
target-arrowhead: {
shape: box
style.filled: true
}
}`,
},
{

View file

@ -215,6 +215,78 @@ filled circle: {
}
}
box: {
start: ""
end: ""
start.1 <-> end.1: 1 {
style.stroke-width: 1
source-arrowhead.shape: box
target-arrowhead.shape: box
}
start.2 <-> end.2: 2 {
style.stroke-width: 2
source-arrowhead.shape: box
target-arrowhead.shape: box
}
start.4 <-> end.4: 4 {
style.stroke-width: 4
source-arrowhead.shape: box
target-arrowhead.shape: box
}
start.8 <-> end.8: 8 {
style.stroke-width: 8
source-arrowhead.shape: box
target-arrowhead.shape: box
}
start.15 <-> end.15: 15 {
style.stroke-width: 15
source-arrowhead.shape: box
target-arrowhead.shape: box
}
}
filled-box: {
start: ""
end: ""
start.1 <-> end.1: 1 {
style.stroke-width: 1
source-arrowhead.shape: box
target-arrowhead.shape: box
source-arrowhead.style.filled: true
target-arrowhead.style.filled: true
}
start.2 <-> end.2: 2 {
style.stroke-width: 2
source-arrowhead.shape: box
target-arrowhead.shape: box
source-arrowhead.style.filled: true
target-arrowhead.style.filled: true
}
start.4 <-> end.4: 4 {
style.stroke-width: 4
source-arrowhead.shape: box
target-arrowhead.shape: box
source-arrowhead.style.filled: true
target-arrowhead.style.filled: true
}
start.8 <-> end.8: 8 {
style.stroke-width: 8
source-arrowhead.shape: box
target-arrowhead.shape: box
source-arrowhead.style.filled: true
target-arrowhead.style.filled: true
}
start.15 <-> end.15: 15 {
style.stroke-width: 15
source-arrowhead.shape: box
target-arrowhead.shape: box
source-arrowhead.style.filled: true
target-arrowhead.style.filled: true
}
}
cf one: {
start: ""
end: ""

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 174 KiB

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 167 KiB

View file

@ -0,0 +1,314 @@
{
"name": "",
"isFolderOnly": false,
"fontFamily": "SourceSansPro",
"shapes": [
{
"id": "a",
"type": "rectangle",
"pos": {
"x": 0,
"y": 0
},
"width": 53,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B6",
"stroke": "B1",
"animated": false,
"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": 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": "b",
"type": "rectangle",
"pos": {
"x": 0,
"y": 187
},
"width": 53,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B6",
"stroke": "B1",
"animated": false,
"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": 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": "c",
"type": "rectangle",
"pos": {
"x": 114,
"y": 0
},
"width": 53,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B6",
"stroke": "B1",
"animated": false,
"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": "d",
"type": "rectangle",
"pos": {
"x": 113,
"y": 187
},
"width": 54,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B6",
"stroke": "B1",
"animated": false,
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "d",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 9,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 1
}
],
"connections": [
{
"id": "(a <-> b)[0]",
"src": "a",
"srcArrow": "box",
"dst": "b",
"dstArrow": "box",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "box",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 25,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"link": "",
"route": [
{
"x": 26.5,
"y": 65.5
},
{
"x": 26.5,
"y": 114.30000305175781
},
{
"x": 26.5,
"y": 138.6999969482422
},
{
"x": 26.5,
"y": 187.5
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "(c <-> d)[0]",
"src": "c",
"srcArrow": "filled-box",
"dst": "d",
"dstArrow": "filled-box",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "filled-box",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 63,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"link": "",
"route": [
{
"x": 140,
"y": 65.5
},
{
"x": 140,
"y": 114.30000305175781
},
{
"x": 140,
"y": 138.6999969482422
},
{
"x": 140,
"y": 187.5
}
],
"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": "",
"animated": false,
"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,296 @@
{
"name": "",
"isFolderOnly": false,
"fontFamily": "SourceSansPro",
"shapes": [
{
"id": "a",
"type": "rectangle",
"pos": {
"x": 12,
"y": 12
},
"width": 53,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B6",
"stroke": "B1",
"animated": false,
"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": 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": "b",
"type": "rectangle",
"pos": {
"x": 12,
"y": 239
},
"width": 53,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B6",
"stroke": "B1",
"animated": false,
"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": 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": "c",
"type": "rectangle",
"pos": {
"x": 85,
"y": 12
},
"width": 53,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B6",
"stroke": "B1",
"animated": false,
"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": "d",
"type": "rectangle",
"pos": {
"x": 85,
"y": 239
},
"width": 54,
"height": 66,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "B6",
"stroke": "B1",
"animated": false,
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "d",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 9,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 1
}
],
"connections": [
{
"id": "(a <-> b)[0]",
"src": "a",
"srcArrow": "box",
"dst": "b",
"dstArrow": "box",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "box",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 25,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"link": "",
"route": [
{
"x": 38.5,
"y": 78
},
{
"x": 38.5,
"y": 239
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "(c <-> d)[0]",
"src": "c",
"srcArrow": "filled-box",
"dst": "d",
"dstArrow": "filled-box",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "filled-box",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 63,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"link": "",
"route": [
{
"x": 112,
"y": 78
},
{
"x": 112,
"y": 239
}
],
"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": "",
"animated": false,
"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