fix dagre shifting connection start past 2nd point

This commit is contained in:
Gavin Nishizawa 2023-06-02 14:15:49 -07:00
parent f6580b69df
commit 4015a48664
No known key found for this signature in database
GPG key ID: AE3B177777CE55CD
3 changed files with 133 additions and 2 deletions

View file

@ -141,6 +141,118 @@ func (obj *Object) ShiftDescendants(dx, dy float64) {
})
}
// ShiftStart moves the starting point of the route by delta either horizontally or vertically
// if subsequent points are in line with the movement, they will be removed (unless it is the last point)
// start end
// . ├────┼────┼───┼────┼───┤ before
// . ├──dx──►
// . ├──┼───┼────┼───┤ after
func (edge *Edge) ShiftStart(delta float64, isHorizontal bool) {
position := func(p *geo.Point) float64 {
if isHorizontal {
return p.X
}
return p.Y
}
start := edge.Route[0]
next := edge.Route[1]
isIncreasing := position(start) < position(next)
if isHorizontal {
start.X += delta
} else {
start.Y += delta
}
if isIncreasing == (delta < 0) {
// nothing more to do when moving away from the next point
return
}
isAligned := func(p *geo.Point) bool {
if isHorizontal {
return p.Y == start.Y
}
return p.X == start.X
}
isPastStart := func(p *geo.Point) bool {
if delta > 0 {
return position(p) < position(start)
} else {
return position(p) > position(start)
}
}
needsRemoval := false
toRemove := make([]bool, len(edge.Route))
for i := 1; i < len(edge.Route)-1; i++ {
if !isAligned(edge.Route[i]) {
break
}
if isPastStart(edge.Route[i]) {
toRemove[i] = true
needsRemoval = true
}
}
if needsRemoval {
edge.Route = geo.RemovePoints(edge.Route, toRemove)
}
}
// ShiftEnd moves the ending point of the route by delta either horizontally or vertically
// if prior points are in line with the movement, they will be removed (unless it is the first point)
func (edge *Edge) ShiftEnd(delta float64, isHorizontal bool) {
position := func(p *geo.Point) float64 {
if isHorizontal {
return p.X
}
return p.Y
}
end := edge.Route[len(edge.Route)-1]
prev := edge.Route[len(edge.Route)-2]
isIncreasing := position(prev) < position(end)
if isHorizontal {
end.X += delta
} else {
end.Y += delta
}
if isIncreasing == (delta > 0) {
// nothing more to do when moving away from the next point
return
}
isAligned := func(p *geo.Point) bool {
if isHorizontal {
return p.Y == end.Y
}
return p.X == end.X
}
isPastEnd := func(p *geo.Point) bool {
if delta > 0 {
return position(p) < position(end)
} else {
return position(p) > position(end)
}
}
needsRemoval := false
toRemove := make([]bool, len(edge.Route))
for i := len(edge.Route) - 2; i > 0; i-- {
if !isAligned(edge.Route[i]) {
break
}
if isPastEnd(edge.Route[i]) {
toRemove[i] = true
needsRemoval = true
}
}
if needsRemoval {
edge.Route = geo.RemovePoints(edge.Route, toRemove)
}
}
// GetModifierElementAdjustments returns width/height adjustments to account for shapes with 3d or multiple
func (obj *Object) GetModifierElementAdjustments() (dx, dy float64) {
if obj.Is3D() {

View file

@ -384,7 +384,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
if isHorizontal && e.Src.Parent != g.Root && e.Dst.Parent != g.Root {
moveWholeEdge = true
} else {
e.Route[0].Y += stepSize
e.ShiftStart(stepSize, false)
}
}
}
@ -393,7 +393,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
if isHorizontal && e.Dst.Parent != g.Root && e.Src.Parent != g.Root {
moveWholeEdge = true
} else {
e.Route[len(e.Route)-1].Y += stepSize
e.ShiftEnd(stepSize, false)
}
}
}

View file

@ -305,3 +305,22 @@ func (p *Point) TruncateDecimals() {
p.X = TruncateDecimals(p.X)
p.Y = TruncateDecimals(p.Y)
}
// RemovePoints returns a new Points slice without the points in toRemove
func RemovePoints(points Points, toRemove []bool) Points {
newLen := len(points)
for _, should := range toRemove {
if should {
newLen--
}
}
without := make([]*Point, 0, newLen)
for i := 0; i < len(points); i++ {
if toRemove[i] {
continue
}
without = append(without, points[i])
}
return without
}