Shine 将 javascript 的绘图函数包装在声明式 API 中。
很大程度上受到光泽的启发。
演示(编译的闪耀示例)在这里
你需要ghcjs
构建 ghcjs 包的一个好方法是使用 reflex 平台
Picture
要表示您的绘图,您必须使用Picture
数据类型构建一棵树。
pic :: Picture
pic = Rect 10 20 -- represents a 10x20 square
要合成多个Picture
,您可以使用Over
,它接受两个Picture
并将它们重叠。
Picture
是一个幺半群: <>
是Over
的别名, mempty
是空图片。
-- draw some shapes on top of each other
pic :: Picture
pic = Rect 10 20
<> Translate 30 30 ( Circle 15 )
<> Colored ( Color 255 0 0 0.2 ) ( RectF 4 4 )
<> Text " Sans 12px " LeftAlign 200 " The quick brown fox jumps over the lazy dog. "
使用Foldable
你可以做类似的事情
concentricCircles :: Picture
concentricCircles = foldMap Circle [ 1 , 10 .. 100 ]
Picture
在绘制任何内容之前,您需要获取CanvasRenderingContext2D
(有时还需要获取Document
)。为此,shine提供了两个实用函数: fullScreenCanvas
和fixedSizeCanvas
{-# LANGUAGE CPP #-}
import Graphics.Shine
import Graphics.Shine.Input
import Graphics.Shine.Picture
import GHCJS.DOM ( currentDocumentUnchecked )
-- This is how the ghcjs-dom hello-world does it.
-- It's boilerplate, so in the next shine version there
-- will probably be a ready-to-use run function
#if defined(ghcjs_HOST_OS)
run :: a -> a
run = id
#elif defined(MIN_VERSION_jsaddle_wkwebview)
import Language.Javascript.JSaddle.WKWebView ( run )
#else
import Language.Javascript.JSaddle.WebKitGTK ( run )
#endif
main :: IO ()
main = run $ do
doc <- currentDocumentUnchecked -- use currentDocument to handle failure
ctx <- fixedSizeCanvas doc 400 400
-- do something with ctx (and maybe doc)
要在上下文中渲染Picture
,您有以下三个选项:
render
您可以使用Graphics.Shine.Render
的render
手动绘制它
main :: IO ()
{- omitted: get the context, see before -}
render ctx concentricCircles
animate
你可以画一幅取决于时间的Picture
。也就是说,一个Float -> Picture
。
-- An expanding-and-contracting circle.
animation :: Float -> Picture
animation = Translate 200 200
. Circle
. ( * 100 ) . ( + 1 ) -- bigger positive oscillation
. sin -- the circle's radius oscillates
main :: IO ()
main = do
{- omitted: get the context, see before -}
animate ctx 30 animation
play
最后,您可以绘制一个取决于时间、输入(键盘和鼠标)和内部状态的Picture
。这对于游戏特别有用,因此得名。
-- this code draws a black rectangle in the center of the canvas only when the
-- left mouse button is pressed
main :: IO ()
main = do
{- omitted: get the context and the document, see before -}
play ctx doc 30 initialState draw handleInput step
where
-- our state represents the state of the left mouse button
initialState = Up
-- we draw a square only if the button is pressed
draw Up = Empty
draw Down = Translate 200 200 $ RectF 200 200
-- when an event is fired we store the button state
handleInput ( MouseBtn BtnLeft buttonState _) = const buttonState
handleInput _ = id -- catch-all for all other events
step _ = id -- our state does not depend on time
请参阅shine-examples
包 (Hackage)。
使用 ghcjs 和浏览器处理资源有些棘手。
对于普通 Haskell 程序来说,通常的方法是使用data-files
。不幸的是,这项工作通过在可执行文件中硬编码绝对路径来实现,当程序放在不同路径的服务器上时,这将不起作用;或者使用环境变量覆盖( $pkgname_datadir
),这将不起作用,因为环境变量会起作用浏览器中不存在。
因此,目前的解决方案是在源代码中显式指定绝对或相对路径,然后在构建/部署代码后将资产复制到适当的位置。这就是我在辣椒图像的animated-shapes
演示中所做的。
相关阴谋集团票据,讨论一种可能的处理资产的新方式:haskell/cabal#6096(评论)