mirror of
https://github.com/taigrr/wasm-experiments
synced 2025-01-18 04:03:21 -08:00
198 lines
4.2 KiB
Go
198 lines
4.2 KiB
Go
// +build js,wasm
|
|
|
|
package main
|
|
|
|
import (
|
|
"math"
|
|
"math/rand"
|
|
"strconv"
|
|
"syscall/js"
|
|
)
|
|
|
|
var (
|
|
width float64
|
|
height float64
|
|
mousePos [2]float64
|
|
ctx, doc js.Value
|
|
canvasEl js.Value
|
|
dt DotThing
|
|
|
|
tmark float64
|
|
markCount = 0
|
|
tdiffSum float64
|
|
)
|
|
|
|
func main() {
|
|
// Init Canvas stuff
|
|
doc = js.Global().Get("document")
|
|
canvasEl = doc.Call("getElementById", "mycanvas")
|
|
width = doc.Get("body").Get("clientWidth").Float()
|
|
height = doc.Get("body").Get("clientHeight").Float()
|
|
canvasEl.Call("setAttribute", "width", width)
|
|
canvasEl.Call("setAttribute", "height", height)
|
|
ctx = canvasEl.Call("getContext", "2d")
|
|
|
|
// Set up dot thing
|
|
dt = DotThing{speed: 160}
|
|
dt.SetNDots(100)
|
|
dt.lines = false
|
|
|
|
js.Global().Call("requestAnimationFrame", js.Global().Get("renderFrame"))
|
|
}
|
|
|
|
// * Handlers for JS callback functions *
|
|
|
|
//go:export speedInput
|
|
func speedInput(fval float64) {
|
|
dt.speed = fval
|
|
}
|
|
|
|
//go:export countChange
|
|
func countChange(intVal int) {
|
|
dt.SetNDots(intVal)
|
|
}
|
|
|
|
//go:export moveHandler
|
|
func moveHandler(cx int, cy int) {
|
|
mousePos[0] = float64(cx)
|
|
mousePos[1] = float64(cy)
|
|
}
|
|
|
|
//go:export renderFrame
|
|
func renderFrame(now float64) {
|
|
tdiff := now - tmark
|
|
tdiffSum += now - tmark
|
|
markCount++
|
|
if markCount > 10 {
|
|
doc.Call("getElementById", "fps").Set("innerHTML", "FPS: "+strconv.FormatFloat(1000/(tdiffSum/float64(markCount)), 'f', 1, 64))
|
|
tdiffSum, markCount = 0, 0
|
|
}
|
|
tmark = now
|
|
|
|
// Pool window size to handle resize
|
|
curBodyW := doc.Get("body").Get("clientWidth").Float()
|
|
curBodyH := doc.Get("body").Get("clientHeight").Float()
|
|
if curBodyW != width || curBodyH != height {
|
|
width, height = curBodyW, curBodyH
|
|
canvasEl.Set("width", width)
|
|
canvasEl.Set("height", height)
|
|
}
|
|
dt.Update(tdiff / 1000)
|
|
js.Global().Call("requestAnimationFrame", js.Global().Get("renderFrame"))
|
|
}
|
|
|
|
// DotThing manager
|
|
type DotThing struct {
|
|
dots []*Dot
|
|
lines bool
|
|
speed float64
|
|
}
|
|
|
|
// Update updates the dot positions and draws
|
|
func (dt *DotThing) Update(dtTime float64) {
|
|
if dt.dots == nil {
|
|
return
|
|
}
|
|
ctx.Call("clearRect", 0, 0, width, height)
|
|
|
|
// Update
|
|
for i, dot := range dt.dots {
|
|
if dot.pos[0] < dot.size {
|
|
dot.pos[0] = dot.size
|
|
dot.dir[0] *= -1
|
|
}
|
|
if dot.pos[0] > width-dot.size {
|
|
dot.pos[0] = width - dot.size
|
|
dot.dir[0] *= -1
|
|
}
|
|
|
|
if dot.pos[1] < dot.size {
|
|
dot.pos[1] = dot.size
|
|
dot.dir[1] *= -1
|
|
}
|
|
|
|
if dot.pos[1] > height-dot.size {
|
|
dot.pos[1] = height - dot.size
|
|
dot.dir[1] *= -1
|
|
}
|
|
|
|
mdx := mousePos[0] - dot.pos[0]
|
|
mdy := mousePos[1] - dot.pos[1]
|
|
d := math.Sqrt(mdx*mdx + mdy*mdy)
|
|
if d < 200 {
|
|
dInv := 1 - d/200
|
|
dot.dir[0] += (-mdx / d) * dInv * 8
|
|
dot.dir[1] += (-mdy / d) * dInv * 8
|
|
}
|
|
for j, dot2 := range dt.dots {
|
|
if i == j {
|
|
continue
|
|
}
|
|
mx := dot2.pos[0] - dot.pos[0]
|
|
my := dot2.pos[1] - dot.pos[1]
|
|
d := math.Sqrt(mx*mx + my*my)
|
|
if d < 100 {
|
|
dInv := 1 - d/100
|
|
dot.dir[0] += (-mx / d) * dInv
|
|
dot.dir[1] += (-my / d) * dInv
|
|
}
|
|
}
|
|
dot.dir[0] *= 0.1 //friction
|
|
dot.dir[1] *= 0.1 //friction
|
|
|
|
dot.pos[0] += dot.dir[0] * dt.speed * dtTime * 10
|
|
dot.pos[1] += dot.dir[1] * dt.speed * dtTime * 10
|
|
|
|
ctx.Set("globalAlpha", 0.5)
|
|
ctx.Call("beginPath")
|
|
hexCol := hexFormat(dot.color)
|
|
ctx.Set("fillStyle", hexCol)
|
|
ctx.Set("strokeStyle", hexCol)
|
|
ctx.Set("lineWidth", dot.size)
|
|
ctx.Call("arc", dot.pos[0], dot.pos[1], dot.size, 0, 2*math.Pi)
|
|
ctx.Call("fill")
|
|
}
|
|
}
|
|
|
|
// SetNDots reinitializes dots with n size
|
|
func (dt *DotThing) SetNDots(n int) {
|
|
dt.dots = make([]*Dot, n)
|
|
for i := 0; i < n; i++ {
|
|
dt.dots[i] = &Dot{
|
|
pos: [2]float64{
|
|
rand.Float64() * width,
|
|
rand.Float64() * height,
|
|
},
|
|
dir: [2]float64{
|
|
rand.NormFloat64(),
|
|
rand.NormFloat64(),
|
|
},
|
|
color: uint32(rand.Intn(0xFFFFFF)),
|
|
size: 10,
|
|
}
|
|
}
|
|
}
|
|
|
|
// Adapted from the Go source: https://github.com/golang/go/blob/4ce6a8e89668b87dce67e2f55802903d6eb9110a/src/fmt/format.go#L248-L252
|
|
func hexFormat(u uint32) string {
|
|
digits := "0123456789abcdefx"
|
|
buf := make([]uint8, 6)
|
|
i := len(buf)
|
|
for u >= 16 {
|
|
i--
|
|
buf[i] = digits[u&0xF]
|
|
u >>= 4
|
|
}
|
|
i--
|
|
buf[i] = digits[u]
|
|
return "#" + string(buf)
|
|
}
|
|
|
|
// Dot represents a dot ...
|
|
type Dot struct {
|
|
pos [2]float64
|
|
dir [2]float64
|
|
color uint32
|
|
size float64
|
|
}
|