GoのwasmでもCanvasをいじりたい

GoでCanvasをいじりたくなったので,試してみた.
とりあえず,MouseのDown,Up,Moveイベントが取れるかみてみました.
ここで使用しているsyscall/jsというパッケージは,wasmホスト環境つまりJSとの橋渡しとなるパッケージです.
jsをgoから呼び出すことや,jsからgoを呼び出すことが可能になります.

結果的にjsとGoが入り交じったコードになります.

以下wasm用のGoソースコード(main.go)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//Wasming
// compile: GOOS=js GOARCH=wasm go build -o main.wasm ./main.go
package main

import (
"math"
"syscall/js"
)

var (
mousePos [2]float64
ctx js.Value
)

func main() {

doc := js.Global().Get("document")
canvasEl := js.Global().Get("document").Call("getElementById", "mycanvas")

bodyW := doc.Get("body").Get("clientWidth").Float()
bodyH := doc.Get("body").Get("clientHeight").Float()
canvasEl.Set("width", bodyW)
canvasEl.Set("height", bodyH)
ctx = canvasEl.Call("getContext", "2d")

done := make(chan struct{}, 0)

mouseDown := false

mouseDownEvt := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
mouseDown = true
evt := args[0]
if evt.Get("target") != canvasEl {
return nil
}
mousePos[0] = evt.Get("clientX").Float()
mousePos[1] = evt.Get("clientY").Float()
return nil
})
defer mouseDownEvt.Release()

mouseUpEvt := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
mouseDown = false
return nil
})
defer mouseUpEvt.Release()

mouseMoveEvt := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
if !mouseDown {
return nil
}
evt := args[0]
if evt.Get("target") != canvasEl {
return nil
}
mousePos[0] = evt.Get("clientX").Float()
mousePos[1] = evt.Get("clientY").Float()
return nil
})
defer mouseMoveEvt.Release()

doc.Call("addEventListener", "mousedown", mouseDownEvt)
doc.Call("addEventListener", "mouseup", mouseUpEvt)
doc.Call("addEventListener", "mousemove", mouseMoveEvt)

var renderFrame js.Func
renderFrame = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
// Handle window resizing
curBodyW := doc.Get("body").Get("clientWidth").Float()
curBodyH := doc.Get("body").Get("clientHeight").Float()
if curBodyW != bodyW || curBodyH != bodyH {
bodyW, bodyH = curBodyW, curBodyH
canvasEl.Set("width", bodyW)
canvasEl.Set("height", bodyH)
}

penColor := "#000"
penSize := 5
ctx.Set("fillStyle",penColor)
ctx.Call("beginPath")
ctx.Call("arc", mousePos[0], mousePos[1],penSize, 0, 2*math.Pi)
ctx.Call("fill")

js.Global().Call("requestAnimationFrame", renderFrame)
return nil
})
defer renderFrame.Release()

js.Global().Call("requestAnimationFrame", renderFrame)

<-done
}

javascriptのaddEventListenerをcallすることにより,mouse操作の関数を登録しています.
参考: マウスの操作について

以下,HTMLファイルです.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 <html>
<head>
<title>go webassembly Canvas</title>
<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch('main.wasm'), go.importObject).then(res => {
go.run(res.instance)
})
</script>
<style>
body,pre { margin: 0;padding: 0;}
#mycanvas {
position: fixed;
top: 0; right: 0; bottom: 0; left: 0;
}
</style>
</head>
<body>
<canvas id="mycanvas"></canvas>
</body>
</html>

Canvasを画面全体に広げています.

これをブラウザで広げると,以下のような絵が描けるようになりました!  

実行結果1
実行結果2

色々できるような気がしてきましたね.

続きはまた次回にしましょう

Author: Gusugusu
Link: https://gusugusu1018.github.io/2019/09/19/GoのwasmでもCanvasをいじりたい/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.

Comment
Catalog