This is as close as I can get to your diagram (using Luxor.jl) with a quick bit of code:
Code
using Luxor
function vector(pt1, pt2)
arrow(pt1, pt2,
arrowheadfunction=(s, e, sl) -> begin
@layer begin
translate(s)
rotate(sl)
@layer begin
sethue("white")
ngon(O, 10, 3, 0, :fillpreserve)
end
strokepath()
end
end,
linewidth=3)
circle(pt1, 5, :fill)
end
function draw_vector_angle(r, θ)
p₁ = Point(0, 0)
p₂ = polar(r, 0)
p₃ = Point(r * cos(θ), r * sin(θ))
sethue("darkcyan")
vector(p₁, p₂)
vector(p₁, p₃)
sethue("red")
arrow(O, r / 4, 0, θ,
clockwise=false,
decoration=0.5,
decorate=() -> begin
sethue("green")
fontsize(12)
rotate(-getrotation())
text("θ = " * string(round(rad2deg(anglethreepoints(p₂, p₁, p₃)), digits=1)) * "°")
end)
sethue("black")
fontsize(20)
fontface("NewCM10-Bold")
label("v", :s, between(p₁, p₂, 0.7), offset=10)
label("u", :nw, between(p₁, p₃, 0.6), offset=10)
end
@drawsvg begin
background("grey90")
tiles = Tiler(600, 600, 2, 2, margin=70)
r = 100
angles = deg2rad.([-30, -100, 180, -210])
for (pos, n) in tiles
@layer begin
translate(pos)
draw_vector_angle(r, angles[n])
end
end
end
Some extra code would be needed to handle the last case correctly. And extra tweaking work would be required, depending on your intended use.