diff --git a/d2exporter/export.go b/d2exporter/export.go index fe9be6c46..fc3557c37 100644 --- a/d2exporter/export.go +++ b/d2exporter/export.go @@ -200,15 +200,9 @@ func toConnection(edge *d2graph.Edge, theme *d2themes.Theme) d2target.Connection text := edge.Text() if edge.SrcArrow { - connection.SrcArrow = d2target.TriangleArrowhead - if edge.SrcArrowhead != nil { - if edge.SrcArrowhead.Shape.Value != "" { - filled := false - if edge.SrcArrowhead.Style.Filled != nil { - filled, _ = strconv.ParseBool(edge.SrcArrowhead.Style.Filled.Value) - } - connection.SrcArrow = d2target.ToArrowhead(edge.SrcArrowhead.Shape.Value, filled) - } + connection.SrcArrow = d2target.DefaultArrowhead + if edge.SrcArrowhead != nil && edge.SrcArrowhead.Shape.Value != "" { + connection.SrcArrow = edge.SrcArrowhead.ToArrowhead() } } if edge.SrcArrowhead != nil { @@ -221,15 +215,9 @@ func toConnection(edge *d2graph.Edge, theme *d2themes.Theme) d2target.Connection } } if edge.DstArrow { - connection.DstArrow = d2target.TriangleArrowhead - if edge.DstArrowhead != nil { - if edge.DstArrowhead.Shape.Value != "" { - filled := false - if edge.DstArrowhead.Style.Filled != nil { - filled, _ = strconv.ParseBool(edge.DstArrowhead.Style.Filled.Value) - } - connection.DstArrow = d2target.ToArrowhead(edge.DstArrowhead.Shape.Value, filled) - } + connection.DstArrow = d2target.DefaultArrowhead + if edge.DstArrowhead != nil && edge.DstArrowhead.Shape.Value != "" { + connection.DstArrow = edge.DstArrowhead.ToArrowhead() } } if edge.DstArrowhead != nil { diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go index f80a35b21..1bab9c273 100644 --- a/d2graph/d2graph.go +++ b/d2graph/d2graph.go @@ -164,6 +164,18 @@ func (a *Attributes) ApplyTextTransform() { } } +func (a *Attributes) ToArrowhead() d2target.Arrowhead { + if a.Shape.Value == "" { + return d2target.NoArrowhead + } + + filled := false + if a.Style.Filled != nil { + filled, _ = strconv.ParseBool(a.Style.Filled.Value) + } + return d2target.ToArrowhead(a.Shape.Value, filled) +} + // TODO references at the root scope should have their Scope set to root graph AST type Reference struct { Key *d2ast.KeyPath `json:"key"` diff --git a/d2target/d2target.go b/d2target/d2target.go index cb173cb2e..baa6ffc3e 100644 --- a/d2target/d2target.go +++ b/d2target/d2target.go @@ -553,19 +553,13 @@ func (connection *Connection) GetArrowheadLabelPosition(isDst bool) *geo.Point { index = len(connection.Route) - 2 } start, end := connection.Route[index], connection.Route[index+1] + // Note: end to start to get normal towards unlocked top position + normalX, normalY := geo.GetUnitNormalVector(end.X, end.Y, start.X, start.Y) - // how much to move the label back from the very end of the edge - var shift float64 - if start.Y == end.Y { - // shift left/right to fit on horizontal segment - shift = width/2. + label.PADDING - } else if start.X == end.X { - // shift up/down to fit on vertical segment - shift = height/2. + label.PADDING - } else { - // TODO compute amount to shift according to angle instead of max - shift = math.Max(width, height) - } + // determine how much to move the label back from the very end of the edge + // e.g. if normal points up {x: 0, y:1}, shift width/2 + padding to fit + shift := math.Abs(normalX)*(height/2.+label.PADDING) + + math.Abs(normalY)*(width/2.+label.PADDING) length := geo.Route(connection.Route).Length() var position float64 @@ -583,7 +577,7 @@ func (connection *Connection) GetArrowheadLabelPosition(isDst bool) *geo.Point { strokeWidth := float64(connection.StrokeWidth) - labelTL, index := label.UnlockedTop.GetPointOnRoute(connection.Route, strokeWidth, position, width, height) + labelTL, _ := label.UnlockedTop.GetPointOnRoute(connection.Route, strokeWidth, position, width, height) var arrowSize float64 if isDst && connection.DstArrow != NoArrowhead { @@ -597,9 +591,6 @@ func (connection *Connection) GetArrowheadLabelPosition(isDst bool) *geo.Point { // labelTL already accounts for strokeWidth and padding, we only want to shift further if the arrow is larger than this offset := (arrowSize/2 + ARROWHEAD_PADDING) - strokeWidth/2 - label.PADDING if offset > 0 { - start, end = connection.Route[index], connection.Route[index+1] - // Note: end to start to get normal towards unlocked top position - normalX, normalY := geo.GetUnitNormalVector(end.X, end.Y, start.X, start.Y) labelTL.X += normalX * offset labelTL.Y += normalY * offset } @@ -635,6 +626,8 @@ const ( CfMany Arrowhead = "cf-many" CfOneRequired Arrowhead = "cf-one-required" CfManyRequired Arrowhead = "cf-many-required" + + DefaultArrowhead Arrowhead = TriangleArrowhead ) var Arrowheads = map[string]struct{}{ @@ -663,8 +656,12 @@ func ToArrowhead(arrowheadType string, filled bool) Arrowhead { return FilledCircleArrowhead } return CircleArrowhead + case string(NoArrowhead): + return NoArrowhead case string(ArrowArrowhead): return ArrowArrowhead + case string(TriangleArrowhead): + return TriangleArrowhead case string(CfOne): return CfOne case string(CfMany): @@ -674,7 +671,7 @@ func ToArrowhead(arrowheadType string, filled bool) Arrowhead { case string(CfManyRequired): return CfManyRequired default: - return TriangleArrowhead + return DefaultArrowhead } }