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(評論)