Skip to content

Commit 17ada08

Browse files
authored
🎨 evy: Add ellipse drawing builtin (#127)
Add canvas ellipse drawing builtin to draw ellipse with ellipse x y radiusX [radiusY [rotation [startDegree endDegree]]] Pull-Request: #127
1 parent a702cc8 commit 17ada08

File tree

6 files changed

+189
-2
lines changed

6 files changed

+189
-2
lines changed

frontend/courses/courses.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
{ "id": "squares", "title": "Squares" },
2525
{ "id": "rainbow", "title": "Rainbow" },
2626
{ "id": "poly", "title": "Polygon and Polyline" },
27+
{ "id": "ellipse", "title": "Ellipse" },
2728
{ "id": "fill", "title": "Stroke and Fill" },
2829
{ "id": "linestyle", "title": "Line Styles" },
2930
{ "id": "text", "title": "Text" }
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
labels := ["x" "y" "radX" "radY" "rot°" "start°" "end°"]
2+
vals := [50 60 30 17 5 0 180]
3+
cnt := len vals
4+
cur := 1
5+
w := 11
6+
7+
print "Watermelon, anyone?"
8+
print "🍉"
9+
print "Use arrow keys or drag numbers"
10+
print "for your perfect piece."
11+
12+
draw
13+
14+
func draw
15+
clear "hsl(210deg 5% 15%)" // near black
16+
draw_ellipse
17+
draw_text
18+
draw_highlight cur
19+
end
20+
21+
func draw_ellipse
22+
width 2
23+
fill "red"
24+
stroke "darkgreen"
25+
ellipse vals[0] vals[1] vals[2] vals[3] vals[4] vals[5] vals[6]
26+
end
27+
28+
func draw_text
29+
font "italic 300 2rem \"Fira Code\", monospace"
30+
textsize 2.7
31+
width 0.2
32+
fill "hsl(210deg 13% 72%)" // light grey
33+
move 2 15
34+
text "// "
35+
for i := range (len labels)
36+
move i*w+20 15
37+
text (sprintf "%5s" labels[i])
38+
end
39+
font "2rem \"Fira Code\", monospace"
40+
textsize 2.7
41+
fill "hsl(27deg 100% 74%)" // orange
42+
move 2 10
43+
text "ellipse"
44+
fill "hsl(204deg 100% 75%)" // ligth blue
45+
for i := range (len labels)
46+
move i*w+20 10
47+
text (sprintf "%5.0f" vals[i])
48+
end
49+
50+
end
51+
52+
func draw_highlight i:num
53+
fill "none"
54+
stroke "white"
55+
width 0.4
56+
x := i * w + 20
57+
move x-1 9
58+
rect 10 4
59+
end
60+
61+
// keyboard interaction
62+
on key k:string
63+
if k == "ArrowLeft"
64+
cur = (cur + cnt - 1) % cnt
65+
else if k == "ArrowRight"
66+
cur = (cur + 1) % cnt
67+
else if k == "ArrowUp"
68+
vals[cur] = vals[cur] + 1
69+
else if k == "ArrowDown"
70+
vals[cur] = max 0 vals[cur]-1
71+
end
72+
draw
73+
end
74+
75+
// pointer interaction
76+
77+
dragy := -1
78+
deltay := 0
79+
80+
on down x:num y:num
81+
if y < 20 and x > 18
82+
cur = min (floor (x - 18)/w) (len labels)-1
83+
dragy = y
84+
draw
85+
end
86+
end
87+
88+
on up _:num _:num
89+
dragy = -1
90+
deltay = 0
91+
end
92+
93+
on move _:num y:num
94+
if dragy == -1
95+
return
96+
end
97+
deltay = y - dragy
98+
if deltay < 0
99+
deltay = floor deltay
100+
else
101+
deltay = ceil deltay
102+
end
103+
end
104+
105+
on animate
106+
if deltay == 0
107+
return
108+
end
109+
if cur < 4
110+
val := vals[cur] + deltay / 10
111+
vals[cur] = max 0 (min 100 val)
112+
else
113+
vals[cur] = vals[cur] + deltay / 5
114+
end
115+
draw
116+
end

frontend/index.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ function newEvyGo() {
5757
clear,
5858
// advanced canvas
5959
poly,
60+
ellipse,
6061
stroke,
6162
fill,
6263
dash,
@@ -97,6 +98,7 @@ function needsCanvas(f) {
9798
f.colour ||
9899
f.clear ||
99100
f.poly ||
101+
f.ellipse ||
100102
f.stroke ||
101103
f.fill ||
102104
f.dash ||
@@ -541,6 +543,25 @@ function parsePoints(s) {
541543
return points
542544
}
543545

546+
// ellipse is exported to evy go/wasm.
547+
// see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/ellipse
548+
function ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle) {
549+
const rad = Math.PI / 180
550+
const { ctx, fill, stroke } = canvas
551+
ctx.beginPath()
552+
ctx.ellipse(
553+
transformX(x),
554+
transformY(y),
555+
transformX(radiusX),
556+
transformX(radiusY),
557+
rotation * rad,
558+
startAngle * rad,
559+
endAngle * rad
560+
)
561+
fill && ctx.fill()
562+
stroke && ctx.stroke()
563+
}
564+
544565
// stroke is exported to evy go/wasm.
545566
function stroke(ptr, len) {
546567
const s = memToString(ptr, len)

frontend/module/yace-editor.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,7 @@ const builtins = new Set([
475475
"colour",
476476
"clear",
477477
"poly",
478+
"ellipse",
478479
"stroke",
479480
"fill",
480481
"dash",

pkg/evaluator/builtin.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ func DefaultBuiltins(rt Runtime) Builtins {
9191
"colour": stringBuiltin("colour", rt.Color),
9292
"clear": {Func: clearFunc(rt.Clear), Decl: clearDecl},
9393

94-
"poly": {Func: polyFunc(rt.Poly), Decl: polyDecl},
94+
"poly": {Func: polyFunc(rt.Poly), Decl: polyDecl},
95+
"ellipse": {Func: ellipseFunc(rt.Ellipse), Decl: ellipseDecl},
9596

9697
"stroke": stringBuiltin("stroke", rt.Stroke),
9798
"fill": stringBuiltin("fill", rt.Fill),
@@ -152,6 +153,7 @@ type GraphicsRuntime interface {
152153

153154
// advanced graphics functions
154155
Poly(vertices [][]float64)
156+
Ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle float64)
155157
Stroke(s string)
156158
Fill(s string)
157159
Dash(segments []float64)
@@ -197,6 +199,9 @@ func (rt *UnimplementedRuntime) Text(s string) { rt.Unimplemented("t
197199
func (rt *UnimplementedRuntime) Textsize(size float64) { rt.Unimplemented("textsize") }
198200
func (rt *UnimplementedRuntime) Font(s string) { rt.Unimplemented("font") }
199201
func (rt *UnimplementedRuntime) Fontfamily(s string) { rt.Unimplemented("fontfamily") }
202+
func (rt *UnimplementedRuntime) Ellipse(x, y, rX, rY, rotation, startAngle, endAngle float64) {
203+
rt.Unimplemented("ellipse")
204+
}
200205

201206
var readDecl = &parser.FuncDeclStmt{
202207
Name: "read",
@@ -607,6 +612,40 @@ func polyFunc(polyFn func([][]float64)) BuiltinFunc {
607612
}
608613
}
609614

615+
var ellipseDecl = &parser.FuncDeclStmt{
616+
Name: "ellipse",
617+
VariadicParam: &parser.Var{Name: "n", T: parser.NUM_TYPE},
618+
ReturnType: parser.NONE_TYPE,
619+
}
620+
621+
func ellipseFunc(ellipseFn func(x, y, radiusX, radiusY, rotation, startAngle, endAngle float64)) BuiltinFunc {
622+
return func(_ *scope, args []Value) (Value, error) {
623+
argLen := len(args)
624+
if argLen < 3 || argLen == 6 || argLen > 7 {
625+
return nil, fmt.Errorf("%w: 'ellipse' requires 3, 4, 5 or 7 arguments, found %d", ErrBadArguments, argLen)
626+
}
627+
x := args[0].(*Num).Val
628+
y := args[1].(*Num).Val
629+
radiusX := args[2].(*Num).Val
630+
radiusY := radiusX
631+
rotation := 0.0
632+
startAngle := 0.0
633+
endAngle := 360.0
634+
if argLen > 3 {
635+
radiusY = args[3].(*Num).Val
636+
}
637+
if argLen > 4 {
638+
rotation = args[4].(*Num).Val
639+
}
640+
if argLen > 6 {
641+
startAngle = args[5].(*Num).Val
642+
endAngle = args[6].(*Num).Val
643+
}
644+
ellipseFn(x, y, radiusX, radiusY, rotation, startAngle, endAngle)
645+
return nil, nil
646+
}
647+
}
648+
610649
var dashDecl = &parser.FuncDeclStmt{
611650
Name: "dash",
612651
VariadicParam: &parser.Var{Name: "segments", T: parser.NUM_TYPE},

pkg/wasm/imports.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func newJSRuntime() *jsRuntime {
2727
}
2828

2929
func (rt *jsRuntime) Yielder() evaluator.Yielder { return rt.yielder }
30-
func (*jsRuntime) Print(s string) { jsPrint(s) }
30+
func (rt *jsRuntime) Print(s string) { jsPrint(s) }
3131
func (rt *jsRuntime) Read() string { return rt.yielder.Read() }
3232
func (rt *jsRuntime) Sleep(dur time.Duration) { rt.yielder.Sleep(dur) }
3333
func (rt *jsRuntime) Move(x, y float64) { move(x, y) }
@@ -53,6 +53,10 @@ func (rt *jsRuntime) Poly(vertices [][]float64) {
5353
poly(strings.Join(vStrings, " "))
5454
}
5555

56+
func (rt *jsRuntime) Ellipse(x, y, rX, rY, rotation, startAngle, endAngle float64) {
57+
ellipse(x, y, rX, rY, rotation, startAngle, endAngle)
58+
}
59+
5660
func floatsToString(floats []float64) string {
5761
if len(floats) == 0 {
5862
return ""
@@ -196,6 +200,11 @@ func clear(s string)
196200
//export poly
197201
func poly(s string)
198202

203+
// ellipse is imported from JS
204+
//
205+
//export ellipse
206+
func ellipse(x, y, rX, rY, rotation, startAngle, endAngle float64)
207+
199208
// stroke is imported from JS
200209
//
201210
//export stroke

0 commit comments

Comments
 (0)