我尝试用threepennt-gui 绘制100 个动画圆圈。感觉有点奇怪,所以我把它设为 1000,问题很明显:
- 我可以看到绘图(即画布是黑色的,然后出现圆圈,然后又变黑了,等等
- 只画一次就花了几秒钟(它应该每秒画 50 次(因为计时器不会让我画 60 次))
- 每一帧都花费了越来越长的时间。几帧后它根本不会完成。
这是我的代码:
let draw (Circle c r (x:+y)) = do
canv # set' UI.fillStyle (UI.htmlColor c)
canv # UI.beginPath
canv # UI.arc (x, y) r (-pi) pi
canv # UI.closePath
canv # UI.fill
let drawAll circles = do
UI.clearCanvas canv
ppos <- liftIO $ readIORef player
draw (Circle "green" playerRadius ppos)
mapM draw circles
所以,我想,也许这会生成低效的 js 代码,即展开循环(好吧,几千行仍然应该生成并执行得相当快)所以我将圆圈转换为 Json 并使用 theepenny 的 ffi 函数,如下所示:
circleToJson (Circle color radius (x:+y)) = "{c:\"" ++ color ++ "\",r:" ++ show radius ++ ",x:" ++ show x ++ ",y:" ++ show y ++ "},"
circlesToJson xs = "[" ++ (foldr (++) "" $ map circleToJson xs) ++ "]"
jsDrawFunc = "(function(canvas, circles){var ctx = canvas.getContext(\"2d\"); for (c of circles) {ctx.fillStyle=c.c; ctx.beginPath(); ctx.arc(c.x,c.y,c.r,0,2*Math.PI,true); ctx.fill();}})"
jsCanvasArg = "$(\"canvas\")[0],"
jsDrawAll circles = jsDrawFunc ++ "(" ++ jsCanvasArg ++ circlesToJson circles ++ ");"
在计时器事件中:
runFunction $ ffi $ jsDrawAll circles
- 现在我再也看不到这幅画了(即全部同时出现)。相反,Firefox 停止响应用户输入,直到绘图完成(据我所知,帧时间更加一致) - 编辑:我在 beginPath 之后缺少空括号,因此所有圆圈都连接起来。现在它再次闪烁(100;1000 需要大约 1 秒才能绘制并且不响应用户输入)。
这表明画布是问题所在。(经过一番搜索似乎得到证实)
有没有办法解决这个问题?(理想情况下不涉及使用不同的 gui-lib)