Last active
November 2, 2024 09:56
-
-
Save juliaogris/a0d8eb411c36237099b71e1719154987 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
HOME_XMIN := -60 | |
HOME_YMIN := -1.5 | |
HOME_XSCALE := 0.21 | |
HOME_YSCALE := 33 | |
sinTable := [ | |
[0 0] | |
[15 ((sqrt 3) - 1)/(2 * (sqrt 2))] | |
[30 1/2] | |
[45 1/(sqrt 2)] | |
[60 (sqrt 3)/2] | |
[90 1] | |
[120 (sqrt 3)/2] | |
[135 1/(sqrt 2)] | |
[150 1/2] | |
[165 ((sqrt 3) - 1)/(2 * (sqrt 2))] | |
[180 0] | |
[210 -1/2] | |
[225 -1/(sqrt 2)] | |
[240 -(sqrt 3)/2] | |
[165 ((sqrt 3) - 1)/(2 * (sqrt 2))] | |
[270 -1] | |
[285 -(sqrt 3)/2] | |
[300 -1/(sqrt 2)] | |
[330 -1/2] | |
[165 ((sqrt 3) - 1)/(2 * (sqrt 2))] | |
] | |
func drawContent | |
opts := {color:"red" radius:0.4} | |
drawDots sinTable opts | |
end | |
func drawDots coords:[][]num options:{}any | |
defaults := {width:0.1 radius:0.5 withLine:false color:"red" dur:0.5} | |
opts := merge defaults options | |
style opts | |
width opts.width.(num) | |
r := opts.radius.(num) | |
withLine := opts.withLine.(bool) | |
dur := opts.dur.(num) | |
if withLine and (len coords) > 0 | |
gmove coords[0][0] coords[0][1] | |
end | |
for coord := range coords | |
if withLine | |
gline coord[0] coord[1] | |
else | |
gmove coord[0] coord[1] | |
end | |
circle r | |
end | |
sleep dur | |
end | |
// ---------------------✂------------------------- | |
// generic graphing paper, setup and even handlers | |
// | |
// globals | |
xmin:num | |
ymin:num | |
xscale:num | |
yscale:num | |
// derived and set by update(xmin, ymin, scale) | |
xextend:num | |
yextend:num | |
xmax:num | |
ymax:num | |
xtick:num | |
ytick:num | |
originHidden:bool | |
zooming:bool | |
// drag | |
isdrag := false | |
xdrag := 0 | |
ydrag := 0 | |
// initialize | |
zoomHome | |
func draw | |
drawGraphPaper | |
drawContent | |
end | |
func xstep:num | |
if zooming | |
return xextend / 100 | |
end | |
return xextend / 1000 | |
end | |
func update xmin1:num ymin1:num xscale1:num yscale1:num | |
xmin = xmin1 | |
ymin = ymin1 | |
xscale = xscale1 | |
yscale = yscale1 | |
// derived | |
xextend = 100 / xscale | |
yextend = 100 / yscale | |
xmax = xmin + xextend | |
ymax = ymin + yextend | |
xtick = calcTick xextend | |
ytick = calcTick yextend | |
originHidden = xmin > 0 or xmax < 0 or ymin > 0 or ymax < 0 | |
end | |
on down x:num y:num | |
if isHome x y | |
zoomHome | |
else if isZoomIn x y | |
zoomIn | |
else if isZoomOut x y | |
zoomOut | |
else | |
drag true x y | |
end | |
end | |
on move x:num y:num | |
if isdrag | |
update xmin+(xdrag - x)/xscale ymin+(ydrag - y)/yscale xscale yscale | |
drag true x y | |
draw | |
end | |
end | |
on up | |
drag false 0 0 | |
end | |
func drag d:bool x:num y:num | |
isdrag = d | |
xdrag = x | |
ydrag = y | |
end | |
func zoomHome | |
update HOME_XMIN HOME_YMIN HOME_XSCALE HOME_YSCALE | |
draw | |
end | |
func zoomIn | |
zoom 2 0 0 //1.1 7 0.01 | |
end | |
func zoomOut | |
zoom 1/2 0 0 // 1/1.1 7 0.01 | |
end | |
func zoom f:num count:num dur:num | |
zooming = true | |
for range count-1 | |
zoom1 f | |
draw | |
sleep dur | |
end | |
zooming = false | |
zoom1 f | |
draw | |
end | |
func zoom1 f:num | |
zoomx f | |
end | |
func zoomxy f:num | |
xd := xextend * (f - 1) / (2 * f) | |
yd := yextend * (f - 1) / (2 * f) | |
update xmin+xd ymin+yd xscale*f yscale*f | |
end | |
func zoomx f:num | |
xd := xextend * (f - 1) / (2 * f) | |
update xmin+xd ymin xscale*f yscale | |
end | |
func drawGraphPaper | |
clear | |
width 0.05 | |
color "gainsboro" | |
drawGrid xtick/5 ytick/5 | |
width 0.1 | |
color "dimgrey" | |
drawGrid xtick ytick | |
width 0.2 | |
color (hsl 0 0 20) | |
drawAxes | |
if !zooming | |
drawXLabels | |
drawYLabels | |
drawButtons | |
end | |
end | |
func drawGrid xdist:num ydist:num | |
start := roundUp xmin xdist | |
stop := xmax + xdist | |
for x := range start stop xdist | |
gv x ymin ymax | |
end | |
start = roundUp ymin ydist | |
stop = ymax + ydist | |
for y := range start stop ydist | |
gh xmin xmax y | |
end | |
end | |
func drawAxes | |
gh xmin xmax 0 // x-Axis | |
gv 0 ymin ymax // y-Axis | |
if !originHidden | |
font {baseline:"alphabetic" align:"left" size:2} | |
gtextnumf 0.05*xtick 0.05*ytick 0 "%v" | |
end | |
end | |
func drawXLabels | |
y := ymin // labels on very bottom if x-axis not visible | |
if ymin <= 0 and ymax > 0 | |
y = 0 // x-axis visible | |
end | |
font {baseline:"alphabetic" align:"center" size:2} | |
start := roundUp xmin xtick | |
stop := xmax + xtick | |
tl := 0.025 * ytick | |
for x := range start stop xtick | |
gv x y-tl y+tl | |
// don't double label origin | |
if (abs x) > xtick / 2 or originHidden | |
gtextnum x y+2*tl x xextend | |
end | |
end | |
end | |
func drawYLabels | |
font {baseline:"middle" align:"left" size:2} | |
x := xmin // labels on very left if y-axis not visible | |
if xmin <= 0 and xmax > 0 | |
x = 0 // y-axis visible | |
end | |
start := roundUp ymin ytick | |
stop := ymax + ytick | |
tl := 0.025 * xtick | |
for y := range start stop ytick | |
gh x-tl x+tl y | |
// don't double label origin | |
if (abs y) > ytick / 2 or originHidden | |
gtextnum x+2*tl y y yextend | |
end | |
end | |
end | |
func drawButtons | |
fill "gainsboro" | |
stroke "darkgrey" | |
width 0.3 | |
move 93 93 | |
rect 6 6 | |
move 93 85 | |
rect 6 6 | |
move 93 79 | |
rect 6 6 | |
// labels | |
color "grey" | |
font {baseline:"alphabetic" align:"left" size:3} | |
move 94.1 94.6 | |
text "🏠" | |
font {baseline:"alphabetic" align:"left" size:6} | |
move 94.2 86.1 | |
text "+" | |
move 94.2 80.1 | |
text "-" | |
end | |
func isHome:bool x:num y:num | |
return x >= 93 and x <= 99 and y >= 93 and y <= 99 | |
end | |
func isZoomIn:bool x:num y:num | |
return x >= 93 and x <= 99 and y >= 85 and y <= 91 | |
end | |
func isZoomOut:bool x:num y:num | |
return x >= 93 and x <= 99 and y >= 79 and y <= 85 | |
end | |
func calcTick:num extend:num | |
d := log10 extend/10 | |
f := d - (floor d) | |
if f > 0.15 and f < 0.42 | |
return 2 * (pow 10 (round d)) | |
else if f >= 0.42 and f < 0.5 | |
return 5 * (pow 10 (round d)) | |
else if f >= 0.5 and f < 0.78 | |
return 0.5 * (pow 10 (round d)) | |
end | |
return pow 10 (round d) | |
end | |
func gmove x:num y:num | |
move (ex x) (ey y) | |
end | |
func gline x:num y:num | |
line (ex x) (ey y) | |
end | |
// vertical line | |
func gv x:num y1:num y2:num | |
gmove x y1 | |
gline x y2 | |
end | |
// horizontal line | |
func gh x1:num x2:num y:num | |
gmove x1 y | |
gline x2 y | |
end | |
func gtextnum x:num y:num n:num extend:num | |
p := 0 | |
lg := floor (log10 extend/10) | |
if lg < 0 | |
p = abs (lg) | |
end | |
fstr := sprintf "%%.%0.ff" p | |
gtextnumf x y n fstr | |
end | |
func gtextnumf x:num y:num n:num fstr:string | |
gmove x y | |
text (sprintf fstr n) | |
end | |
// ex is the evy x coordinate (0, 100) for a given | |
// graphing x coordinate graphX (xmin, xmin+extend). | |
func ex:num graphX:num | |
return xscale * (graphX - xmin) | |
end | |
// ey is the evy y coordinate (0, 100) for a given | |
// graphing y coordinate graphY (ymin, ymin+extend). | |
func ey:num graphY:num | |
return yscale * (graphY - ymin) | |
end | |
// gx is the grpahing x coordinate (xmin, xmin+extend) | |
// for a gvien evy x coordinate evyX (0, 100) | |
func gx:num evyX:num | |
return xmin + evyX / xscale | |
end | |
// gy is the grpahing y coordinate (ymin, ymin+extend) | |
// for a gvien evy y coordinate evyY(0, 100) | |
func gy:num evyY:num | |
return ymin + evyY / yscale | |
end | |
func roundUp:num n:num multiple:num | |
r := (abs n) % multiple | |
if r == 0 | |
return n | |
end | |
if n > 0 | |
return n + multiple - r | |
end | |
return -(-n + multiple - r) | |
end | |
func log10:num n:num | |
return (log n) / (log 10) | |
end | |
func style s:{}any | |
if has s "color" | |
color s.color.(string) | |
end | |
if has s "fill" | |
fill s.fill.(string) | |
end | |
if has s "width" | |
width s.width.(num) | |
end | |
end | |
func merge:{}any defaults:{}any overrides:{}any | |
m:{}any | |
for key := range defaults | |
if has overrides key | |
m[key] = overrides[key] | |
else | |
m[key] = defaults[key] | |
end | |
end | |
for key := range overrides | |
if !(has m key) | |
m[key] = overrides[key] | |
end | |
end | |
return m | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment