func (c *Canvas2d) imgCopy() {
	js.CopyBytesToJS(c.copybuff, c.image.Pix)
	c.imgData.Get("data").Call("set", c.copybuff)
	c.ctx.Call("putImageData", c.imgData, 0, 0)
}
Does the actuall copy over of the image data for the 'render' call.
package canvas
import (
	"image"
	"syscall/js"
	"github.com/golang/freetype/truetype"
	"github.com/llgcode/draw2d"
	"github.com/llgcode/draw2d/draw2dimg"
)
type RenderFunc func(gc *draw2dimg.GraphicContext) bool
type Canvas2d struct {
	done chan struct{}  
	window js.Value
	doc    js.Value
	body   js.Value
	canvas  js.Value
	ctx     js.Value
	imgData js.Value
	width   int
	height  int
	gctx     *draw2dimg.GraphicContext  
	image    *image.RGBA                
	font     *truetype.Font
	fontData draw2d.FontData
	reqID    js.Value  
	timeStep float64   
	copybuff js.Value
}
func NewCanvas2d(create bool) (*Canvas2d, error) {
	var c Canvas2d
	c.window = js.Global()
	c.doc = c.window.Get("document")
	c.body = c.doc.Get("body")
	if create {
		c.Create(int(c.window.Get("innerWidth").Int()), int(c.window.Get("innerHeight").Int()))
	}
	return &c, nil
}
func (c *Canvas2d) Create(width int, height int) {
	canvas := c.doc.Call("createElement", "canvas")
	canvas.Set("height", height)
	canvas.Set("width", width)
	c.body.Call("appendChild", canvas)
	c.Set(canvas, width, height)
}
func (c *Canvas2d) Set(canvas js.Value, width int, height int) {
	c.canvas = canvas
	c.height = height
	c.width = width
	c.ctx = c.canvas.Call("getContext", "2d")
	c.imgData = c.ctx.Call("createImageData", width, height)  
	c.image = image.NewRGBA(image.Rect(0, 0, width, height))
	c.copybuff = js.Global().Get("Uint8Array").New(len(c.image.Pix))  
	c.gctx = draw2dimg.NewGraphicContext(c.image)
	c.font, _ = truetype.Parse(FontData["font.ttf"])
	c.fontData = draw2d.FontData{
		Name:   "roboto",
		Family: draw2d.FontFamilySans,
		Style:  draw2d.FontStyleNormal,
	}
	fontCache := &FontCache{}
	fontCache.Store(c.fontData, c.font)
	c.gctx.FontCache = fontCache
}
func (c *Canvas2d) Start(maxFPS float64, rf RenderFunc) {
	c.SetFPS(maxFPS)
	c.initFrameUpdate(rf)
}
func (c *Canvas2d) Stop() {
	c.window.Call("cancelAnimationFrame", c.reqID)
	c.done <- struct{}{}
	close(c.done)
}
func (c *Canvas2d) SetFPS(maxFPS float64) {
	c.timeStep = 1000 / maxFPS
}
func (c *Canvas2d) Gc() *draw2dimg.GraphicContext {
	return c.gctx
}
func (c *Canvas2d) Height() int {
	return c.height
}
func (c *Canvas2d) Width() int {
	return c.width
}
func (c *Canvas2d) initFrameUpdate(rf RenderFunc) {
	go func() {
		var renderFrame js.Func
		var lastTimestamp float64
		renderFrame = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
			timestamp := args[0].Float()
			if timestamp-lastTimestamp >= c.timeStep {  
				if rf != nil {  
					if rf(c.gctx) {  
						c.imgCopy()
					}
				} else {  
					c.imgCopy()
				}
				lastTimestamp = timestamp
			}
			c.reqID = js.Global().Call("requestAnimationFrame", renderFrame)  
			return nil
		})
		defer renderFrame.Release()
		js.Global().Call("requestAnimationFrame", renderFrame)
		<-c.done
	}()
}