Shine envuelve las funciones de dibujo de JavaScript en una API declarativa.
Muy inspirado en el brillo.
demostración (ejemplos de brillo compilados) aquí
Necesitas ghcjs
Una excelente manera de crear paquetes ghcjs es utilizar la plataforma reflex.
Picture
Para representar su dibujo, debe construir un árbol usando el tipo de datos Picture
.
pic :: Picture
pic = Rect 10 20 -- represents a 10x20 square
Para componer varias Picture
, puede utilizar Over
, que acepta dos Picture
y las superpone.
Picture
es un monoide: <>
es un alias de Over
y mempty
es la imagen vacía.
-- 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. "
Usando Foldable
puedes hacer cosas como
concentricCircles :: Picture
concentricCircles = foldMap Circle [ 1 , 10 .. 100 ]
Picture
Antes de dibujar cualquier cosa, necesita obtener un CanvasRenderingContext2D
(y, a veces, un Document
). Para ello, Shine proporciona dos funciones de utilidad: fullScreenCanvas
y 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)
Para representar una Picture
en un contexto, tiene tres opciones:
render
Puedes dibujarlo manualmente usando render
desde Graphics.Shine.Render
main :: IO ()
{- omitted: get the context, see before -}
render ctx concentricCircles
animate
Puedes dibujar una Picture
que dependa del tiempo. Es decir, un 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
Finalmente, puedes dibujar una Picture
que depende del tiempo, las entradas (teclado y mouse) y un estado interno. Esto es especialmente útil para juegos, de ahí el nombre.
-- 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
Vea el paquete shine-examples
(Hackage).
Manejar recursos con ghcjs y el navegador es algo complicado.
La forma habitual de hacerlo para programas Haskell normales es utilizar data-files
. Desafortunadamente, esto funciona codificando una ruta absoluta en el ejecutable, lo que no funcionará cuando el programa se coloque en un servidor en una ruta diferente, o con una anulación de variable de entorno ( $pkgname_datadir
), que no funcionará porque las variables de entorno sí lo hacen. no existe en el navegador.
Entonces, por ahora, la solución es especificar explícitamente rutas absolutas o relativas en el código fuente y luego copiar muchos de los recursos en la ubicación adecuada después de compilar/implementar el código. Esto es lo que hice en la demostración animated-shapes
para la imagen de los pimientos.
Ticket de cabal relevante, discutiendo una posible nueva forma de manejar activos: haskell/cabal#6096 (comentario)