Android Question Draw broken line; arrow head

Rusty

Well-Known Member
Licensed User
Longtime User
Is there an preferred way to draw a broken line (dashed line) using Canvas Drawline etc. or other method?
Also, I need to put an arrowhead on the end of the line, is there an preferred way to do this as well?
Thanks,
Rusty
 

klaus

Expert
Licensed User
Longtime User
To draw a dashed line you need to use the ABExtDrawing library.
This code does it.
It uses the Paint object to define the line type.
in p.SetDashPathEffect(1, Array As Float(10dip, 10dip), 0)
The first 10dip value is the ON length and the second is the OFF length of the line.
The 0 value is the phase.
B4X:
Sub Globals
    Dim ExtDrawing As ABExtDrawing
    Dim cvsMain As Canvas
End Sub

Sub Activity_Create(FirstTime As Boolean)
    cvsMain.Initialize(Activity)
End Sub

Sub Activity_Resume
    DrawDashLine(10dip, 10dip, 200dip, 210dip, Colors.Red, 2dip)
End Sub

Sub DrawDashLine(x1 As Float, y1 As Float, x2 As Float, y2 As Float, col As Int, Stroke As Float)
    Dim p As ABPaint
    p.Initialize
    p.SetStrokeWidth(Stroke)
    p.SetStyle(p.Style_STROKE)
    p.SetColor(col)
    p.SetDashPathEffect(1, Array As Float(10dip, 10dip), 0)
    p.DoPathEffectSingle(1)
    ExtDrawing.DrawLine(cvsMain, x1, y1, x2, y2, p)
End Sub
There is no 'automatic' arrowhead function.
You need to do it yourself, define a path and draw it.
For oblic lines it needs some trigonometry.
I had used this routine for horizontal or vertical lines.
B4X:
'Draws an arrow with tip at x and y
'x and y = coordinates of the tip
'col = color
'direction = direction of the arrow 
'possible values for direction
'"R" right, "L" left, "U" up "D" down
Sub DrawArrow(x As Int, y As Int, col As Int, direction As String)
    Dim P As Path

    P.Initialize(x, y)
   
    Select direction.ToUpperCase
    Case "R"
        P.LineTo(x - 10dip, y - 5dip)
        P.LineTo(x - 10dip, y + 5dip)
    Case "L"
        P.LineTo(x + 10dip, y + 5dip)
        P.LineTo(x + 10dip, y - 5dip)
    Case "U"
        P.LineTo(x - 5dip, y + 10dip)
        P.LineTo(x + 5dip, y + 10dip)
    Case "D"
        P.LineTo(x - 5dip, y - 10dip)
        P.LineTo(x + 5dip, y - 10dip)
    End Select
    cvsMain.DrawPath(P, col, True, 1)   
End Sub
 
Upvote 0

Rusty

Well-Known Member
Licensed User
Longtime User
Thanks Klaus!
Is there any way to draw the arrowhead oriented to the slope of the line drawn?
i.e. if the slope of a line is .33 (for example), I'd like the tip of the arrow to be at one end of the line and the "triangle" portion to be oriented along the line.
Thanks,
Rusty
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
Below you find two routines:
DrawArrowHeadLine: draws lines with filled arrows at the start and or at the end of the line.
B4X:
Sub DrawArrowHeadLine(cvs As Canvas, x1 As Float, y1 As Float, x2 As Float, y2 As Float, col As Int, StrokeWidth As Int, ArrowLength As Int, HalfArrowWidth As Int, ArrowStartLine As Boolean, ArrowEndLine As Boolean)
    Dim Angle As Double
    Dim path1 As Path
  
    Angle = ATan2D((y2 - y1), (x2 - x1))
  
    If ArrowStartLine = True Then
        path1.Initialize(x1, y1)
        path1.LineTo(x1 + ArrowLength * CosD(Angle) + HalfArrowWidth * SinD(Angle), y1 + ArrowLength * SinD(Angle) - HalfArrowWidth * CosD(Angle))
        path1.LineTo(x1 + ArrowLength * CosD(Angle) - HalfArrowWidth * SinD(Angle), y1 + ArrowLength * SinD(Angle) + HalfArrowWidth * CosD(Angle))
        cvs.DrawPath(path1, col, True, StrokeWidth)
    End If
  
    If ArrowEndLine = True Then
        path1.Initialize(x2, y2)
        path1.LineTo(x2 - ArrowLength * CosD(Angle) + HalfArrowWidth * SinD(Angle), y2 - ArrowLength * SinD(Angle) - HalfArrowWidth * CosD(Angle))
        path1.LineTo(x2 - ArrowLength * CosD(Angle) - HalfArrowWidth * SinD(Angle), y2 - ArrowLength * SinD(Angle) + HalfArrowWidth * CosD(Angle))
        cvs.DrawPath(path1, col, True, StrokeWidth)
    End If  
  
    cvs.DrawLine(x1, y1, x2, y2, col, StrokeWidth)
End Sub

DrawArrowHeadLine2: draws lines with either filled arrows or not filled arrows at the start and or the end of the line :
B4X:
Sub DrawArrowHeadLine2(cvs As Canvas, x1 As Float, y1 As Float, x2 As Float, y2 As Float, col As Int, StrokeWidth As Int, ArrowLength As Int, HalfArrowWidth As Int, ArrowStartLine As Boolean, StartArrowFilled As Boolean, ArrowEndLine As Boolean, EndArrowFilled As Boolean)
   Dim Angle As Double
   Dim path1 As Path
   Dim x11, y11, x21, y21 As Int
   
   Angle = ATan2D((y2 - y1), (x2 - x1))
   
   x11 = x1
   y11 = y1
   x21 = x2
   y21 = y2
   
   If ArrowStartLine = True Then
     If StartArrowFilled = False Then
       x11 = x1 + ArrowLength * CosD(Angle)
       y11 = y1 + ArrowLength * SinD(Angle)
     End If
     
     path1.Initialize(x1, y1)
     path1.LineTo(x1 + ArrowLength * CosD(Angle) + HalfArrowWidth * SinD(Angle), y1 + ArrowLength * SinD(Angle) - HalfArrowWidth * CosD(Angle))
     path1.LineTo(x1 + ArrowLength * CosD(Angle) - HalfArrowWidth * SinD(Angle), y1 + ArrowLength * SinD(Angle) + HalfArrowWidth * CosD(Angle))
     path1.LineTo(x1, y1)
     cvsMain.DrawPath(path1, col, StartArrowFilled, StrokeWidth)
   End If
   
   If ArrowEndLine = True Then
     If EndArrowFilled = False Then
       x21 = x2 - ArrowLength * CosD(Angle)
       y21 = y2 - ArrowLength * SinD(Angle)
     End If
     
     path1.Initialize(x2, y2)
     path1.LineTo(x2 - ArrowLength * CosD(Angle) + HalfArrowWidth * SinD(Angle), y2 - ArrowLength * SinD(Angle) - HalfArrowWidth * CosD(Angle))
     path1.LineTo(x2 - ArrowLength * CosD(Angle) - HalfArrowWidth * SinD(Angle), y2 - ArrowLength * SinD(Angle) + HalfArrowWidth * CosD(Angle))
     path1.LineTo(x2, y2)
     cvsMain.DrawPath(path1, col, EndArrowFilled, StrokeWidth)
   End If
   
   cvsMain.DrawLine(x11, y11, x21, y21, col, StrokeWidth)
End Sub
The routines are with plain lines not with dashed lines, I leave it up to you to adapt them to dashed lines.
 
Upvote 0
Top