Skip to content

Instantly share code, notes, and snippets.

@juliaogris
Last active November 2, 2024 09:56
Show Gist options
  • Save juliaogris/a0d8eb411c36237099b71e1719154987 to your computer and use it in GitHub Desktop.
Save juliaogris/a0d8eb411c36237099b71e1719154987 to your computer and use it in GitHub Desktop.
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