diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md
index 65780a72c..70ffbdb53 100644
--- a/ci/release/changelogs/next.md
+++ b/ci/release/changelogs/next.md
@@ -1,5 +1,7 @@
#### Features ๐
+- `cross` arrowhead shape is available [#2190](https://github.com/terrastruct/d2/pull/2190)
+
#### Improvements ๐งน
#### Bugfixes โ๏ธ
diff --git a/d2renderers/d2sketch/sketch.go b/d2renderers/d2sketch/sketch.go
index e65e22b3d..090cdabf8 100644
--- a/d2renderers/d2sketch/sketch.go
+++ b/d2renderers/d2sketch/sketch.go
@@ -788,6 +788,13 @@ func ArrowheadJS(r jsrunner.JSRunner, arrowhead d2target.Arrowhead, stroke strin
stroke,
stroke,
)
+ case d2target.CrossArrowhead:
+ arrowJS = fmt.Sprintf(
+ `node = rc.linearPath(%s, { strokeWidth: %d, stroke: "%s", seed: 3 })`,
+ `[[-6, -6], [6, 6], [0, 0], [-6, 6], [0, 0], [6, -6]]`,
+ strokeWidth,
+ stroke,
+ )
case d2target.CfManyRequired:
arrowJS = fmt.Sprintf(
// TODO why does fillStyle: "zigzag" error with path
diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go
index adf6c5d1a..123c88d49 100644
--- a/d2renderers/d2svg/d2svg.go
+++ b/d2renderers/d2svg/d2svg.go
@@ -553,6 +553,51 @@ func arrowheadMarker(isTarget bool, id string, connection d2target.Connection, i
}
path = circleEl.Render()
+ case d2target.CrossArrowhead:
+ inset := strokeWidth / 8
+ rotationAngle := math.Pi / 4
+ origin := geo.NewPoint(width/2, height/2)
+ newOrigin := geo.NewPoint(math.Cos(rotationAngle)*origin.X-math.Sin(rotationAngle)*origin.Y, math.Sin(rotationAngle)*origin.X+math.Cos(rotationAngle)*origin.Y)
+
+ crossEl := d2themes.NewThemableElement("polygon", inlineTheme)
+ crossEl.Points = fmt.Sprintf("%f,%f %f,%f %f,%f %f,%f, %f,%f %f,%f %f,%f %f,%f %f,%f %f,%f %f,%f %f,%f",
+ 0., height/2+inset,
+ width/2-inset, height/2+inset,
+ width/2-inset, height,
+ width/2+inset, height,
+ width/2+inset, height/2+inset,
+ width, height/2+inset,
+ width, height/2-inset,
+ width/2+inset, height/2-inset,
+ width/2+inset, 0.,
+ width/2-inset, 0.,
+ width/2-inset, height/2-inset,
+ 0., height/2-inset,
+ )
+ crossEl.Transform = fmt.Sprintf("translate(%f, %f) rotate(45)", -newOrigin.X+width/2, -newOrigin.Y+height/2)
+
+ childPathEl := d2themes.NewThemableElement("path", inlineTheme)
+ if isTarget {
+ childPathEl.D = fmt.Sprintf("M%f,%f %f,%f",
+ width/2, height/2,
+ width, height/2,
+ )
+ } else {
+ childPathEl.D = fmt.Sprintf("M%f,%f %f,%f",
+ width/2, height/2,
+ 0., height/2,
+ )
+ }
+
+ gEl := d2themes.NewThemableElement("g", inlineTheme)
+ gEl.Fill = d2target.BG_COLOR
+ gEl.Stroke = connection.Stroke
+ gEl.ClassName = "connection"
+ gEl.Attributes = fmt.Sprintf(`stroke-width="%d"`, connection.StrokeWidth)
+ gEl.Content = fmt.Sprintf("%s%s",
+ crossEl.Render(), childPathEl.Render(),
+ )
+ path = gEl.Render()
case d2target.FilledBoxArrowhead:
polygonEl := d2themes.NewThemableElement("polygon", inlineTheme)
polygonEl.ClassName = "connection"
diff --git a/d2target/d2target.go b/d2target/d2target.go
index 4880c2859..8157cce74 100644
--- a/d2target/d2target.go
+++ b/d2target/d2target.go
@@ -809,6 +809,7 @@ const (
FilledDiamondArrowhead Arrowhead = "filled-diamond"
CircleArrowhead Arrowhead = "circle"
FilledCircleArrowhead Arrowhead = "filled-circle"
+ CrossArrowhead Arrowhead = "cross"
BoxArrowhead Arrowhead = "box"
FilledBoxArrowhead Arrowhead = "filled-box"
@@ -836,6 +837,7 @@ var Arrowheads = map[string]struct{}{
string(CfMany): {},
string(CfOneRequired): {},
string(CfManyRequired): {},
+ string(CrossArrowhead): {},
}
func ToArrowhead(arrowheadType string, filled *bool) Arrowhead {
@@ -859,6 +861,8 @@ func ToArrowhead(arrowheadType string, filled *bool) Arrowhead {
return UnfilledTriangleArrowhead
}
return TriangleArrowhead
+ case string(CrossArrowhead):
+ return CrossArrowhead
case string(BoxArrowhead):
if filled != nil && *filled {
return FilledBoxArrowhead
@@ -913,6 +917,11 @@ func (arrowhead Arrowhead) Dimensions(strokeWidth float64) (width, height float6
baseHeight = 9
widthMultiplier = 5.5
heightMultiplier = 4.5
+ case CrossArrowhead:
+ baseWidth = 7
+ baseHeight = 7
+ widthMultiplier = 5
+ heightMultiplier = 5
case FilledCircleArrowhead, CircleArrowhead:
baseWidth = 8
baseHeight = 8
diff --git a/e2etests/stable_test.go b/e2etests/stable_test.go
index 8ea7a6ed5..4b2f6adf9 100644
--- a/e2etests/stable_test.go
+++ b/e2etests/stable_test.go
@@ -2898,6 +2898,7 @@ y: profits {
loadFromFile(t, "unfilled_triangle"),
loadFromFile(t, "grid_container_dimensions"),
loadFromFile(t, "grid_label_positions"),
+ loadFromFile(t, "cross_arrowhead"),
}
runa(t, tcs)
diff --git a/e2etests/testdata/files/cross_arrowhead.d2 b/e2etests/testdata/files/cross_arrowhead.d2
new file mode 100644
index 000000000..7573011de
--- /dev/null
+++ b/e2etests/testdata/files/cross_arrowhead.d2
@@ -0,0 +1,29 @@
+cross: {
+ start: ""
+ end: ""
+ start.1 <-> end.1: 1 {
+ style.stroke-width: 1
+ source-arrowhead.shape: cross
+ target-arrowhead.shape: cross
+ }
+ start.2 <-> end.2: 2 {
+ style.stroke-width: 2
+ source-arrowhead.shape: cross
+ target-arrowhead.shape: cross
+ }
+ start.4 <-> end.4: 4 {
+ style.stroke-width: 4
+ source-arrowhead.shape: cross
+ target-arrowhead.shape: cross
+ }
+ start.8 <-> end.8: 8 {
+ style.stroke-width: 8
+ source-arrowhead.shape: cross
+ target-arrowhead.shape: cross
+ }
+ start.15 <-> end.15: 15 {
+ style.stroke-width: 15
+ source-arrowhead.shape: cross
+ target-arrowhead.shape: cross
+ }
+}
diff --git a/e2etests/testdata/stable/cross_arrowhead/dagre/board.exp.json b/e2etests/testdata/stable/cross_arrowhead/dagre/board.exp.json
new file mode 100644
index 000000000..89189c688
--- /dev/null
+++ b/e2etests/testdata/stable/cross_arrowhead/dagre/board.exp.json
@@ -0,0 +1,902 @@
+{
+ "name": "",
+ "config": {
+ "sketch": false,
+ "themeID": 0,
+ "darkThemeID": null,
+ "pad": null,
+ "center": null,
+ "layoutEngine": null
+ },
+ "isFolderOnly": false,
+ "fontFamily": "SourceSansPro",
+ "shapes": [
+ {
+ "id": "cross",
+ "type": "rectangle",
+ "pos": {
+ "x": 0,
+ "y": 40
+ },
+ "width": 633,
+ "height": 473,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B4",
+ "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": "cross",
+ "fontSize": 28,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 60,
+ "labelHeight": 36,
+ "labelPosition": "OUTSIDE_TOP_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "cross.start",
+ "type": "rectangle",
+ "pos": {
+ "x": 30,
+ "y": 70
+ },
+ "width": 573,
+ "height": 126,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B5",
+ "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": "",
+ "fontSize": 24,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "cross.end",
+ "type": "rectangle",
+ "pos": {
+ "x": 30,
+ "y": 357
+ },
+ "width": 573,
+ "height": 126,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B5",
+ "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": "",
+ "fontSize": 24,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "cross.start.1",
+ "type": "rectangle",
+ "pos": {
+ "x": 60,
+ "y": 100
+ },
+ "width": 52,
+ "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": "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": 3
+ },
+ {
+ "id": "cross.end.1",
+ "type": "rectangle",
+ "pos": {
+ "x": 60,
+ "y": 387
+ },
+ "width": 52,
+ "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": "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": 3
+ },
+ {
+ "id": "cross.start.2",
+ "type": "rectangle",
+ "pos": {
+ "x": 172,
+ "y": 100
+ },
+ "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": "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": 3
+ },
+ {
+ "id": "cross.end.2",
+ "type": "rectangle",
+ "pos": {
+ "x": 172,
+ "y": 387
+ },
+ "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": "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": 3
+ },
+ {
+ "id": "cross.start.4",
+ "type": "rectangle",
+ "pos": {
+ "x": 285,
+ "y": 100
+ },
+ "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": "4",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 9,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 3
+ },
+ {
+ "id": "cross.end.4",
+ "type": "rectangle",
+ "pos": {
+ "x": 285,
+ "y": 387
+ },
+ "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": "4",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 9,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 3
+ },
+ {
+ "id": "cross.start.8",
+ "type": "rectangle",
+ "pos": {
+ "x": 399,
+ "y": 100
+ },
+ "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": "8",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 3
+ },
+ {
+ "id": "cross.end.8",
+ "type": "rectangle",
+ "pos": {
+ "x": 399,
+ "y": 387
+ },
+ "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": "8",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 3
+ },
+ {
+ "id": "cross.start.15",
+ "type": "rectangle",
+ "pos": {
+ "x": 512,
+ "y": 100
+ },
+ "width": 61,
+ "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": "15",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 16,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 3
+ },
+ {
+ "id": "cross.end.15",
+ "type": "rectangle",
+ "pos": {
+ "x": 512,
+ "y": 387
+ },
+ "width": 61,
+ "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": "15",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 16,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 3
+ }
+ ],
+ "connections": [
+ {
+ "id": "cross.(start.1 <-> end.1)[0]",
+ "src": "cross.start.1",
+ "srcArrow": "cross",
+ "dst": "cross.end.1",
+ "dstArrow": "cross",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 1,
+ "stroke": "B1",
+ "borderRadius": 10,
+ "label": "1",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 7,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "link": "",
+ "route": [
+ {
+ "x": 86,
+ "y": 166
+ },
+ {
+ "x": 86,
+ "y": 206
+ },
+ {
+ "x": 86,
+ "y": 228.10000610351562
+ },
+ {
+ "x": 86,
+ "y": 246.25
+ },
+ {
+ "x": 86,
+ "y": 264.3999938964844
+ },
+ {
+ "x": 86,
+ "y": 347
+ },
+ {
+ "x": 86,
+ "y": 387
+ }
+ ],
+ "isCurve": true,
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "cross.(start.2 <-> end.2)[0]",
+ "src": "cross.start.2",
+ "srcArrow": "cross",
+ "dst": "cross.end.2",
+ "dstArrow": "cross",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "B1",
+ "borderRadius": 10,
+ "label": "2",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 9,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "link": "",
+ "route": [
+ {
+ "x": 198.5,
+ "y": 166
+ },
+ {
+ "x": 198.5,
+ "y": 206
+ },
+ {
+ "x": 198.5,
+ "y": 228.10000610351562
+ },
+ {
+ "x": 198.5,
+ "y": 246.25
+ },
+ {
+ "x": 198.5,
+ "y": 264.3999938964844
+ },
+ {
+ "x": 198.5,
+ "y": 347
+ },
+ {
+ "x": 198.5,
+ "y": 387
+ }
+ ],
+ "isCurve": true,
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "cross.(start.4 <-> end.4)[0]",
+ "src": "cross.start.4",
+ "srcArrow": "cross",
+ "dst": "cross.end.4",
+ "dstArrow": "cross",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 4,
+ "stroke": "B1",
+ "borderRadius": 10,
+ "label": "4",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "link": "",
+ "route": [
+ {
+ "x": 312,
+ "y": 166
+ },
+ {
+ "x": 312,
+ "y": 206
+ },
+ {
+ "x": 312,
+ "y": 228.10000610351562
+ },
+ {
+ "x": 312,
+ "y": 246.25
+ },
+ {
+ "x": 312,
+ "y": 264.3999938964844
+ },
+ {
+ "x": 312,
+ "y": 347
+ },
+ {
+ "x": 312,
+ "y": 387
+ }
+ ],
+ "isCurve": true,
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "cross.(start.8 <-> end.8)[0]",
+ "src": "cross.start.8",
+ "srcArrow": "cross",
+ "dst": "cross.end.8",
+ "dstArrow": "cross",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 8,
+ "stroke": "B1",
+ "borderRadius": 10,
+ "label": "8",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "link": "",
+ "route": [
+ {
+ "x": 425.5,
+ "y": 166
+ },
+ {
+ "x": 425.5,
+ "y": 206
+ },
+ {
+ "x": 425.5,
+ "y": 228.10000610351562
+ },
+ {
+ "x": 425.5,
+ "y": 246.25
+ },
+ {
+ "x": 425.5,
+ "y": 264.3999938964844
+ },
+ {
+ "x": 425.5,
+ "y": 347
+ },
+ {
+ "x": 425.5,
+ "y": 387
+ }
+ ],
+ "isCurve": true,
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "cross.(start.15 <-> end.15)[0]",
+ "src": "cross.start.15",
+ "srcArrow": "cross",
+ "dst": "cross.end.15",
+ "dstArrow": "cross",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 15,
+ "stroke": "B1",
+ "borderRadius": 10,
+ "label": "15",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 16,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "link": "",
+ "route": [
+ {
+ "x": 542.5,
+ "y": 166
+ },
+ {
+ "x": 542.5,
+ "y": 206
+ },
+ {
+ "x": 542.5,
+ "y": 228.10000610351562
+ },
+ {
+ "x": 542.5,
+ "y": 246.25
+ },
+ {
+ "x": 542.5,
+ "y": 264.3999938964844
+ },
+ {
+ "x": 542.5,
+ "y": 347
+ },
+ {
+ "x": 542.5,
+ "y": 387
+ }
+ ],
+ "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
+ }
+}
diff --git a/e2etests/testdata/stable/cross_arrowhead/dagre/sketch.exp.svg b/e2etests/testdata/stable/cross_arrowhead/dagre/sketch.exp.svg
new file mode 100644
index 000000000..7574406e8
--- /dev/null
+++ b/e2etests/testdata/stable/cross_arrowhead/dagre/sketch.exp.svg
@@ -0,0 +1,124 @@
+
\ No newline at end of file
diff --git a/e2etests/testdata/stable/cross_arrowhead/elk/board.exp.json b/e2etests/testdata/stable/cross_arrowhead/elk/board.exp.json
new file mode 100644
index 000000000..2d33a9d2d
--- /dev/null
+++ b/e2etests/testdata/stable/cross_arrowhead/elk/board.exp.json
@@ -0,0 +1,797 @@
+{
+ "name": "",
+ "config": {
+ "sketch": false,
+ "themeID": 0,
+ "darkThemeID": null,
+ "pad": null,
+ "center": null,
+ "layoutEngine": null
+ },
+ "isFolderOnly": false,
+ "fontFamily": "SourceSansPro",
+ "shapes": [
+ {
+ "id": "cross",
+ "type": "rectangle",
+ "pos": {
+ "x": 12,
+ "y": 12
+ },
+ "width": 553,
+ "height": 603,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B4",
+ "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": "cross",
+ "fontSize": 28,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 60,
+ "labelHeight": 36,
+ "labelPosition": "INSIDE_TOP_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "cross.start",
+ "type": "rectangle",
+ "pos": {
+ "x": 62,
+ "y": 62
+ },
+ "width": 453,
+ "height": 166,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B5",
+ "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": "",
+ "fontSize": 24,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "cross.end",
+ "type": "rectangle",
+ "pos": {
+ "x": 62,
+ "y": 399
+ },
+ "width": 453,
+ "height": 166,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B5",
+ "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": "",
+ "fontSize": 24,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "cross.start.1",
+ "type": "rectangle",
+ "pos": {
+ "x": 112,
+ "y": 112
+ },
+ "width": 52,
+ "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": "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": 3
+ },
+ {
+ "id": "cross.end.1",
+ "type": "rectangle",
+ "pos": {
+ "x": 112,
+ "y": 449
+ },
+ "width": 52,
+ "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": "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": 3
+ },
+ {
+ "id": "cross.start.2",
+ "type": "rectangle",
+ "pos": {
+ "x": 184,
+ "y": 112
+ },
+ "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": "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": 3
+ },
+ {
+ "id": "cross.end.2",
+ "type": "rectangle",
+ "pos": {
+ "x": 184,
+ "y": 449
+ },
+ "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": "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": 3
+ },
+ {
+ "id": "cross.start.4",
+ "type": "rectangle",
+ "pos": {
+ "x": 257,
+ "y": 112
+ },
+ "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": "4",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 9,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 3
+ },
+ {
+ "id": "cross.end.4",
+ "type": "rectangle",
+ "pos": {
+ "x": 257,
+ "y": 449
+ },
+ "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": "4",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 9,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 3
+ },
+ {
+ "id": "cross.start.8",
+ "type": "rectangle",
+ "pos": {
+ "x": 331,
+ "y": 112
+ },
+ "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": "8",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 3
+ },
+ {
+ "id": "cross.end.8",
+ "type": "rectangle",
+ "pos": {
+ "x": 331,
+ "y": 449
+ },
+ "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": "8",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 3
+ },
+ {
+ "id": "cross.start.15",
+ "type": "rectangle",
+ "pos": {
+ "x": 404,
+ "y": 112
+ },
+ "width": 61,
+ "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": "15",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 16,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 3
+ },
+ {
+ "id": "cross.end.15",
+ "type": "rectangle",
+ "pos": {
+ "x": 404,
+ "y": 449
+ },
+ "width": 61,
+ "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": "15",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 16,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 3
+ }
+ ],
+ "connections": [
+ {
+ "id": "cross.(start.1 <-> end.1)[0]",
+ "src": "cross.start.1",
+ "srcArrow": "cross",
+ "dst": "cross.end.1",
+ "dstArrow": "cross",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 1,
+ "stroke": "B1",
+ "borderRadius": 10,
+ "label": "1",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 7,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "link": "",
+ "route": [
+ {
+ "x": 138,
+ "y": 178
+ },
+ {
+ "x": 138,
+ "y": 449
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "cross.(start.2 <-> end.2)[0]",
+ "src": "cross.start.2",
+ "srcArrow": "cross",
+ "dst": "cross.end.2",
+ "dstArrow": "cross",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "B1",
+ "borderRadius": 10,
+ "label": "2",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 9,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "link": "",
+ "route": [
+ {
+ "x": 210.5,
+ "y": 178
+ },
+ {
+ "x": 210.5,
+ "y": 449
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "cross.(start.4 <-> end.4)[0]",
+ "src": "cross.start.4",
+ "srcArrow": "cross",
+ "dst": "cross.end.4",
+ "dstArrow": "cross",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 4,
+ "stroke": "B1",
+ "borderRadius": 10,
+ "label": "4",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "link": "",
+ "route": [
+ {
+ "x": 284,
+ "y": 178
+ },
+ {
+ "x": 284,
+ "y": 449
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "cross.(start.8 <-> end.8)[0]",
+ "src": "cross.start.8",
+ "srcArrow": "cross",
+ "dst": "cross.end.8",
+ "dstArrow": "cross",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 8,
+ "stroke": "B1",
+ "borderRadius": 10,
+ "label": "8",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "link": "",
+ "route": [
+ {
+ "x": 357.5,
+ "y": 178
+ },
+ {
+ "x": 357.5,
+ "y": 449
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "cross.(start.15 <-> end.15)[0]",
+ "src": "cross.start.15",
+ "srcArrow": "cross",
+ "dst": "cross.end.15",
+ "dstArrow": "cross",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 15,
+ "stroke": "B1",
+ "borderRadius": 10,
+ "label": "15",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 16,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "labelPercentage": 0,
+ "link": "",
+ "route": [
+ {
+ "x": 434.5,
+ "y": 178
+ },
+ {
+ "x": 434.5,
+ "y": 449
+ }
+ ],
+ "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
+ }
+}
diff --git a/e2etests/testdata/stable/cross_arrowhead/elk/sketch.exp.svg b/e2etests/testdata/stable/cross_arrowhead/elk/sketch.exp.svg
new file mode 100644
index 000000000..632579a37
--- /dev/null
+++ b/e2etests/testdata/stable/cross_arrowhead/elk/sketch.exp.svg
@@ -0,0 +1,124 @@
+cross112244881515 1 2 4 8 15
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/e2etests/testdata/txtar/sketch-cross-arrowhead/dagre/board.exp.json b/e2etests/testdata/txtar/sketch-cross-arrowhead/dagre/board.exp.json
new file mode 100644
index 000000000..b27711f8e
--- /dev/null
+++ b/e2etests/testdata/txtar/sketch-cross-arrowhead/dagre/board.exp.json
@@ -0,0 +1,190 @@
+{
+ "name": "",
+ "config": {
+ "sketch": true,
+ "themeID": 0,
+ "darkThemeID": null,
+ "pad": null,
+ "center": null,
+ "layoutEngine": null
+ },
+ "isFolderOnly": false,
+ "fontFamily": "HandDrawn",
+ "shapes": [
+ {
+ "id": "start",
+ "type": "rectangle",
+ "pos": {
+ "x": 0,
+ "y": 0
+ },
+ "width": 86,
+ "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": "start",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 41,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "end",
+ "type": "rectangle",
+ "pos": {
+ "x": 6,
+ "y": 166
+ },
+ "width": 75,
+ "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": "end",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 30,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ }
+ ],
+ "connections": [
+ {
+ "id": "(start <-> end)[0]",
+ "src": "start",
+ "srcArrow": "cross",
+ "dst": "end",
+ "dstArrow": "cross",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 6,
+ "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,
+ "link": "",
+ "route": [
+ {
+ "x": 43,
+ "y": 66
+ },
+ {
+ "x": 43,
+ "y": 106
+ },
+ {
+ "x": 43,
+ "y": 126
+ },
+ {
+ "x": 43,
+ "y": 166
+ }
+ ],
+ "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
+ }
+}
diff --git a/e2etests/testdata/txtar/sketch-cross-arrowhead/dagre/sketch.exp.svg b/e2etests/testdata/txtar/sketch-cross-arrowhead/dagre/sketch.exp.svg
new file mode 100644
index 000000000..be668ebae
--- /dev/null
+++ b/e2etests/testdata/txtar/sketch-cross-arrowhead/dagre/sketch.exp.svg
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+startend
+
+
+
+
\ No newline at end of file
diff --git a/e2etests/testdata/txtar/sketch-cross-arrowhead/elk/board.exp.json b/e2etests/testdata/txtar/sketch-cross-arrowhead/elk/board.exp.json
new file mode 100644
index 000000000..83c6ec006
--- /dev/null
+++ b/e2etests/testdata/txtar/sketch-cross-arrowhead/elk/board.exp.json
@@ -0,0 +1,181 @@
+{
+ "name": "",
+ "config": {
+ "sketch": true,
+ "themeID": 0,
+ "darkThemeID": null,
+ "pad": null,
+ "center": null,
+ "layoutEngine": null
+ },
+ "isFolderOnly": false,
+ "fontFamily": "HandDrawn",
+ "shapes": [
+ {
+ "id": "start",
+ "type": "rectangle",
+ "pos": {
+ "x": 12,
+ "y": 12
+ },
+ "width": 86,
+ "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": "start",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 41,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "end",
+ "type": "rectangle",
+ "pos": {
+ "x": 17,
+ "y": 148
+ },
+ "width": 75,
+ "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": "end",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 30,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ }
+ ],
+ "connections": [
+ {
+ "id": "(start <-> end)[0]",
+ "src": "start",
+ "srcArrow": "cross",
+ "dst": "end",
+ "dstArrow": "cross",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 6,
+ "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,
+ "link": "",
+ "route": [
+ {
+ "x": 55,
+ "y": 78
+ },
+ {
+ "x": 55,
+ "y": 148
+ }
+ ],
+ "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
+ }
+}
diff --git a/e2etests/testdata/txtar/sketch-cross-arrowhead/elk/sketch.exp.svg b/e2etests/testdata/txtar/sketch-cross-arrowhead/elk/sketch.exp.svg
new file mode 100644
index 000000000..10bc46be9
--- /dev/null
+++ b/e2etests/testdata/txtar/sketch-cross-arrowhead/elk/sketch.exp.svg
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+startend
+
+
+
+
\ No newline at end of file
diff --git a/e2etests/txtar.txt b/e2etests/txtar.txt
index 90fb07c1b..19a0c532c 100644
--- a/e2etests/txtar.txt
+++ b/e2etests/txtar.txt
@@ -304,6 +304,19 @@ a <-> e
f <-> g: {style.animated: true}
x -- x: {style.animated: true}
+-- sketch-cross-arrowhead --
+vars: {
+ d2-config: {
+ sketch: true
+ }
+}
+
+start <-> end: {
+ style.stroke-width: 6
+ source-arrowhead.shape: cross
+ target-arrowhead.shape: cross
+}
+
-- sequence-edge-group-tall-edge-label --
Sequence: {
shape: sequence_diagram