mirror of
https://github.com/reanimate/reanimate.git
synced 2026-09-16 18:42:21 +00:00
Better caching, bundle viewer.
Former-commit-id: cacfc7fd5402fadd381d16c748cdfdbf97a63cd9
This commit is contained in:
parent
c07f4c18ae
commit
a4121d01d9
27 changed files with 296 additions and 359 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
#!/usr/bin/env stack
|
#!/usr/bin/env stack
|
||||||
-- stack --resolver lts-11.22 runghc --package reanimate
|
-- stack --resolver lts-11.22 runghc --package reanimate
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
module Main (main) where
|
module Main (main) where
|
||||||
|
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,14 @@ build-type: Simple
|
||||||
extra-source-files: ChangeLog.md
|
extra-source-files: ChangeLog.md
|
||||||
cabal-version: >=1.10
|
cabal-version: >=1.10
|
||||||
|
|
||||||
|
data-files: viewer/build/*.js
|
||||||
|
viewer/build/*.html
|
||||||
|
viewer/build/static/js/2.772a56e7.chunk.js
|
||||||
|
viewer/build/static/js/main.db22f45d.chunk.js
|
||||||
|
viewer/build/static/js/runtime~main.9eb600ee.js
|
||||||
|
viewer/build/static/css/main.6efe09fd.chunk.css
|
||||||
|
|
||||||
|
|
||||||
library
|
library
|
||||||
hs-source-dirs: src
|
hs-source-dirs: src
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
@ -28,12 +36,15 @@ library
|
||||||
Reanimate.Driver
|
Reanimate.Driver
|
||||||
Reanimate.Misc
|
Reanimate.Misc
|
||||||
other-modules: Reanimate.Svg.NamedColors
|
other-modules: Reanimate.Svg.NamedColors
|
||||||
|
Reanimate.Cache
|
||||||
|
Paths_reanimate
|
||||||
build-depends: base >=4.10 && <4.13,
|
build-depends: base >=4.10 && <4.13,
|
||||||
time, text, unix, filepath, process, directory,
|
time, text, unix, filepath, process, directory,
|
||||||
containers, reanimate-svg >= 0.7.0.0, xml, bytestring, lens, linear, mtl, matrix,
|
containers, reanimate-svg >= 0.7.0.0, xml, bytestring, lens, linear, mtl, matrix,
|
||||||
JuicyPixels, attoparsec, parallel, diagrams, diagrams-svg,
|
JuicyPixels, attoparsec, parallel, diagrams, diagrams-svg,
|
||||||
diagrams-core, diagrams-lib, diagrams-contrib,
|
diagrams-core, diagrams-lib, diagrams-contrib,
|
||||||
svg-builder, matrices, cubicbezier, palette, hinotify, websockets
|
svg-builder, matrices, cubicbezier, palette, hinotify, websockets,
|
||||||
|
hashable
|
||||||
|
|
||||||
Flag gtk-viewer
|
Flag gtk-viewer
|
||||||
Description: Enable gtk-based viewer
|
Description: Enable gtk-based viewer
|
||||||
|
|
|
||||||
81
src/Reanimate/Cache.hs
Normal file
81
src/Reanimate/Cache.hs
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
module Reanimate.Cache
|
||||||
|
( cacheMem
|
||||||
|
, cacheDisk
|
||||||
|
, cacheDiskSvg
|
||||||
|
, cacheDiskLines
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Control.Exception
|
||||||
|
import Data.Hashable
|
||||||
|
import Data.IORef
|
||||||
|
import Data.Map (Map)
|
||||||
|
import qualified Data.Map as Map
|
||||||
|
import Data.Text (Text)
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import qualified Data.Text.Encoding as T
|
||||||
|
import qualified Data.Text.IO as T
|
||||||
|
import Graphics.SvgTree (Tree (..), parseSvgFile, unparse)
|
||||||
|
import Reanimate.Monad (renderTree)
|
||||||
|
import Reanimate.Svg (unbox)
|
||||||
|
import Text.XML.Light ( Content(..), parseXML )
|
||||||
|
import System.Directory
|
||||||
|
import System.FilePath
|
||||||
|
import System.IO.Unsafe
|
||||||
|
|
||||||
|
-- Memory cache and disk cache
|
||||||
|
|
||||||
|
cacheDisk :: (T.Text -> Maybe a) -> (a -> T.Text) -> (Text -> IO a) -> (Text -> IO a)
|
||||||
|
cacheDisk parse render gen key = do
|
||||||
|
root <- getXdgDirectory XdgCache "reanimate"
|
||||||
|
createDirectoryIfMissing True root
|
||||||
|
let path = root </> show (hash key)
|
||||||
|
hit <- doesFileExist path
|
||||||
|
if hit
|
||||||
|
then do
|
||||||
|
inp <- T.readFile path
|
||||||
|
case parse inp of
|
||||||
|
Nothing -> do
|
||||||
|
let tmp = path <.> "tmp"
|
||||||
|
new <- gen key
|
||||||
|
T.writeFile tmp (render new)
|
||||||
|
renameFile tmp path
|
||||||
|
return new
|
||||||
|
Just val -> pure val
|
||||||
|
else do
|
||||||
|
let tmp = path <.> "tmp"
|
||||||
|
new <- gen key
|
||||||
|
T.writeFile tmp (render new)
|
||||||
|
renameFile tmp path
|
||||||
|
return new
|
||||||
|
|
||||||
|
cacheDiskSvg :: (Text -> IO Tree) -> (Text -> IO Tree)
|
||||||
|
cacheDiskSvg = cacheDisk parse render
|
||||||
|
where
|
||||||
|
parse txt = case parseXML txt of
|
||||||
|
[Elem t] -> Just (unparse t)
|
||||||
|
_ -> Nothing
|
||||||
|
render = T.pack . renderTree
|
||||||
|
|
||||||
|
cacheDiskLines :: (Text -> IO [Text]) -> (Text -> IO [Text])
|
||||||
|
cacheDiskLines = cacheDisk parse render
|
||||||
|
where
|
||||||
|
parse = Just . T.lines
|
||||||
|
render = T.unlines
|
||||||
|
|
||||||
|
|
||||||
|
{-# NOINLINE cache #-}
|
||||||
|
cache :: IORef (Map Text Tree)
|
||||||
|
cache = unsafePerformIO (newIORef Map.empty)
|
||||||
|
|
||||||
|
cacheMem :: (Text -> IO Tree) -> (Text -> IO Tree)
|
||||||
|
cacheMem gen key = do
|
||||||
|
store <- readIORef cache
|
||||||
|
case Map.lookup key store of
|
||||||
|
Just svg -> return svg
|
||||||
|
Nothing -> do
|
||||||
|
svg <- gen key
|
||||||
|
case svg of
|
||||||
|
-- None usually indicates that latex or another tool was misconfigured. In this case,
|
||||||
|
-- don't store the result.
|
||||||
|
None -> pure None
|
||||||
|
_ -> atomicModifyIORef cache (\store -> (Map.insert key svg store, svg))
|
||||||
|
|
@ -11,10 +11,12 @@ import System.INotify (EventVariety (..), addWatch, withINotify)
|
||||||
import System.IO (BufferMode (..), hPutStrLn, hSetBuffering,
|
import System.IO (BufferMode (..), hPutStrLn, hSetBuffering,
|
||||||
stderr, stdin)
|
stderr, stdin)
|
||||||
|
|
||||||
import Reanimate.Misc (runCmdLazy, runCmd_, withTempFile)
|
import Reanimate.Misc (runCmdLazy, runCmd, runCmd_, withTempDir, withTempFile)
|
||||||
import Reanimate.Monad (Animation)
|
import Reanimate.Monad (Animation)
|
||||||
import Reanimate.Render (renderSvgs)
|
import Reanimate.Render (renderSvgs)
|
||||||
|
|
||||||
|
import Paths_reanimate
|
||||||
|
|
||||||
opts = defaultConnectionOptions
|
opts = defaultConnectionOptions
|
||||||
{ connectionCompressionOptions = PermessageDeflateCompression defaultPermessageDeflate }
|
{ connectionCompressionOptions = PermessageDeflateCompression defaultPermessageDeflate }
|
||||||
|
|
||||||
|
|
@ -24,50 +26,55 @@ reanimate animation = do
|
||||||
hSetBuffering stdin NoBuffering
|
hSetBuffering stdin NoBuffering
|
||||||
case args of
|
case args of
|
||||||
["once"] -> renderSvgs animation
|
["once"] -> renderSvgs animation
|
||||||
_ -> runServerWith "127.0.0.1" 9161 opts $ \pending -> do
|
_ -> withTempDir $ \tmpDir -> do
|
||||||
putStrLn "Server pending."
|
url <- getDataFileName "viewer/build/index.html"
|
||||||
prog <- getProgName
|
runCmd "xdg-open" [url]
|
||||||
lst <- listDirectory "."
|
runServerWith "127.0.0.1" 9161 opts $ \pending -> do
|
||||||
mbSelf <- findFile ("." : lst) prog
|
putStrLn "Server pending."
|
||||||
blocker <- newEmptyMVar :: IO (MVar ())
|
prog <- getProgName
|
||||||
case mbSelf of
|
lst <- listDirectory "."
|
||||||
Nothing -> do
|
mbSelf <- findFile ("." : lst) prog
|
||||||
hPutStrLn stderr "Failed to find own source code."
|
blocker <- newEmptyMVar :: IO (MVar ())
|
||||||
Just self -> withINotify $ \notify -> do
|
case mbSelf of
|
||||||
conn <- acceptRequest pending
|
Nothing -> do
|
||||||
slave <- newEmptyMVar
|
hPutStrLn stderr "Failed to find own source code."
|
||||||
let handler = modifyMVar_ slave $ \tid -> do
|
Just self -> withINotify $ \notify -> do
|
||||||
sendTextData conn (T.pack "Compiling")
|
conn <- acceptRequest pending
|
||||||
putStrLn "Kill and respawn."
|
slave <- newEmptyMVar
|
||||||
killThread tid
|
let handler = modifyMVar_ slave $ \tid -> do
|
||||||
tid <- forkIO $ withTempFile ".exe" $ \tmpExecutable -> do
|
sendTextData conn (T.pack "Compiling")
|
||||||
ret <- runCmd_ "stack" $ ["ghc", "--"] ++ ghcOptions ++ [self, "-o", tmpExecutable]
|
putStrLn "Kill and respawn."
|
||||||
case ret of
|
killThread tid
|
||||||
Left err ->
|
tid <- forkIO $ withTempFile ".exe" $ \tmpExecutable -> do
|
||||||
sendTextData conn $ T.pack $ "Error" ++ unlines (drop 3 (lines err))
|
ret <- runCmd_ "stack" $ ["ghc", "--"] ++ ghcOptions tmpDir ++ [self, "-o", tmpExecutable]
|
||||||
Right{} -> do
|
case ret of
|
||||||
getFrame <- runCmdLazy tmpExecutable ["once", "+RTS", "-N", "-M200M", "-RTS"]
|
Left err ->
|
||||||
flip fix [] $ \loop acc -> do
|
sendTextData conn $ T.pack $ "Error" ++ unlines (drop 3 (lines err))
|
||||||
frame <- getFrame
|
Right{} -> do
|
||||||
case frame of
|
getFrame <- runCmdLazy tmpExecutable ["once", "+RTS", "-N", "-M200M", "-RTS"]
|
||||||
Left "" -> do
|
flip fix [] $ \loop acc -> do
|
||||||
sendTextData conn (T.pack "Done")
|
frame <- getFrame
|
||||||
-- insertCache msg (reverse acc)
|
case frame of
|
||||||
Left err -> do
|
Left "" -> do
|
||||||
-- _ <- getChanContents queue
|
sendTextData conn (T.pack "Done")
|
||||||
sendTextData conn $ T.pack $ "Error" ++ err
|
-- insertCache msg (reverse acc)
|
||||||
Right frame -> do
|
Left err -> do
|
||||||
sendTextData conn frame
|
-- _ <- getChanContents queue
|
||||||
loop (frame : acc)
|
sendTextData conn $ T.pack $ "Error" ++ err
|
||||||
return tid
|
Right frame -> do
|
||||||
putStrLn "Found self. Listening."
|
sendTextData conn frame
|
||||||
addWatch notify [Modify] self (const handler)
|
loop (frame : acc)
|
||||||
putMVar slave =<< forkIO (return ())
|
return tid
|
||||||
let loop = do
|
putStrLn "Found self. Listening."
|
||||||
fps <- receiveData conn :: IO T.Text
|
addWatch notify [Modify] self (const handler)
|
||||||
handler
|
putMVar slave =<< forkIO (return ())
|
||||||
loop
|
let loop = do
|
||||||
loop
|
fps <- receiveData conn :: IO T.Text
|
||||||
|
handler
|
||||||
|
loop
|
||||||
|
loop
|
||||||
|
|
||||||
ghcOptions :: [String]
|
ghcOptions :: FilePath -> [String]
|
||||||
ghcOptions = ["-rtsopts", "--make", "-threaded", "-O2"]
|
ghcOptions tmpDir =
|
||||||
|
["-rtsopts", "--make", "-threaded", "-O2"] ++
|
||||||
|
["-odir", tmpDir, "-hidir", tmpDir]
|
||||||
|
|
|
||||||
|
|
@ -7,74 +7,36 @@ import qualified Data.ByteString as B
|
||||||
import Data.IORef
|
import Data.IORef
|
||||||
import Data.Map (Map)
|
import Data.Map (Map)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
import Data.Monoid
|
||||||
|
import Reanimate.Cache
|
||||||
import Reanimate.Misc
|
import Reanimate.Misc
|
||||||
import Reanimate.Svg
|
import Reanimate.Svg
|
||||||
import System.FilePath (replaceExtension, takeFileName, (</>))
|
import System.FilePath (replaceExtension, takeFileName, (</>))
|
||||||
import System.IO.Unsafe (unsafePerformIO)
|
import System.IO.Unsafe (unsafePerformIO)
|
||||||
|
|
||||||
import Control.Lens (over, set, (%~), (&), (.~), (^.))
|
import Control.Lens (over, set, (%~), (&), (.~), (^.))
|
||||||
|
import Data.Text (Text)
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import qualified Data.Text.IO as T
|
||||||
import Graphics.SvgTree (Document (..), Tree (..), defaultSvg,
|
import Graphics.SvgTree (Document (..), Tree (..), defaultSvg,
|
||||||
elements, loadSvgFile, parseSvgFile,
|
elements, loadSvgFile, parseSvgFile,
|
||||||
xmlOfDocument)
|
xmlOfDocument)
|
||||||
import Text.XML.Light (elContent)
|
import Text.XML.Light (elContent)
|
||||||
import Text.XML.Light.Output (ppcContent, ppcElement, prettyConfigPP)
|
import Text.XML.Light.Output (ppcContent, ppcElement, prettyConfigPP)
|
||||||
|
|
||||||
-- instance ToHtml Document where
|
latex :: T.Text -> Tree
|
||||||
-- toHtml = toHtmlRaw
|
latex tex = (unsafePerformIO . (cacheMem . cacheDiskSvg) latexToSVG)
|
||||||
-- toHtmlRaw = toHtmlRaw . ppcElement prettyConfigPP . xmlOfDocument
|
("% plain latex\n" <> tex)
|
||||||
|
|
||||||
-- instance ToHtml Document where
|
xelatex :: Text -> Tree
|
||||||
-- toHtml = toHtmlRaw
|
xelatex tex = (unsafePerformIO . (cacheMem . cacheDiskSvg) latexToSVG)
|
||||||
-- toHtmlRaw doc = toHtmlRaw $ unlines $ map (ppcContent prettyConfigPP) (elContent elt)
|
("% xelatex\n" <> tex)
|
||||||
-- where
|
|
||||||
-- elt = xmlOfDocument doc
|
|
||||||
--
|
|
||||||
-- instance ToHtml Tree where
|
|
||||||
-- toHtml = toHtmlRaw
|
|
||||||
-- toHtmlRaw tree = toHtmlRaw doc
|
|
||||||
-- where
|
|
||||||
-- doc = Document
|
|
||||||
-- { _viewBox = Nothing
|
|
||||||
-- , _width = Nothing
|
|
||||||
-- , _height = Nothing
|
|
||||||
-- , _elements = [tree]
|
|
||||||
-- , _definitions = Map.empty
|
|
||||||
-- , _description = ""
|
|
||||||
-- , _styleRules = []
|
|
||||||
-- , _documentLocation = ""
|
|
||||||
-- }
|
|
||||||
|
|
||||||
{-# NOINLINE cache #-}
|
latexAlign :: Text -> Tree
|
||||||
cache :: IORef (Map String Tree)
|
latexAlign tex = latex $ T.unlines ["\\begin{align*}", tex, "\\end{align*}"]
|
||||||
cache = unsafePerformIO (newIORef Map.empty)
|
|
||||||
|
|
||||||
latex :: String -> Tree
|
|
||||||
latex tex = unsafePerformIO $ do
|
|
||||||
store <- readIORef cache
|
|
||||||
case Map.lookup tex store of
|
|
||||||
Just svg -> return svg
|
|
||||||
Nothing -> do
|
|
||||||
svg <- latexToSVG tex
|
|
||||||
case svg of
|
|
||||||
None -> pure None
|
|
||||||
_ -> atomicModifyIORef cache (\store -> (Map.insert tex svg store, svg))
|
|
||||||
|
|
||||||
xelatex :: String -> Tree
|
|
||||||
xelatex tex = unsafePerformIO $ do
|
|
||||||
store <- readIORef cache
|
|
||||||
case Map.lookup tex store of
|
|
||||||
Just svg -> return svg
|
|
||||||
Nothing -> do
|
|
||||||
svg <- xelatexToSVG tex
|
|
||||||
case svg of
|
|
||||||
None -> pure None
|
|
||||||
_ -> atomicModifyIORef cache (\store -> (Map.insert tex svg store, svg))
|
|
||||||
|
|
||||||
latexAlign :: String -> Tree
|
|
||||||
latexAlign tex = latex $ unlines ["\\begin{align*}", tex, "\\end{align*}"]
|
|
||||||
|
|
||||||
|
|
||||||
latexToSVG :: String -> IO Tree
|
latexToSVG :: Text -> IO Tree
|
||||||
latexToSVG tex = handle (\(e::SomeException) -> return (failedSvg tex)) $ do
|
latexToSVG tex = handle (\(e::SomeException) -> return (failedSvg tex)) $ do
|
||||||
latex <- requireExecutable "latex"
|
latex <- requireExecutable "latex"
|
||||||
dvisvgm <- requireExecutable "dvisvgm"
|
dvisvgm <- requireExecutable "dvisvgm"
|
||||||
|
|
@ -82,7 +44,7 @@ latexToSVG tex = handle (\(e::SomeException) -> return (failedSvg tex)) $ do
|
||||||
let dvi_file = tmp_dir </> replaceExtension (takeFileName tex_file) "dvi"
|
let dvi_file = tmp_dir </> replaceExtension (takeFileName tex_file) "dvi"
|
||||||
writeFile tex_file tex_document
|
writeFile tex_file tex_document
|
||||||
appendFile tex_file tex_prologue
|
appendFile tex_file tex_prologue
|
||||||
appendFile tex_file tex
|
T.appendFile tex_file tex
|
||||||
appendFile tex_file tex_epilogue
|
appendFile tex_file tex_epilogue
|
||||||
runCmd latex ["-interaction=batchmode", "-halt-on-error", "-output-directory="++tmp_dir, tex_file]
|
runCmd latex ["-interaction=batchmode", "-halt-on-error", "-output-directory="++tmp_dir, tex_file]
|
||||||
runCmd dvisvgm [ dvi_file
|
runCmd dvisvgm [ dvi_file
|
||||||
|
|
@ -95,7 +57,7 @@ latexToSVG tex = handle (\(e::SomeException) -> return (failedSvg tex)) $ do
|
||||||
Nothing -> error "Malformed svg"
|
Nothing -> error "Malformed svg"
|
||||||
Just svg -> return $ unbox $ replaceUses svg
|
Just svg -> return $ unbox $ replaceUses svg
|
||||||
|
|
||||||
xelatexToSVG :: String -> IO Tree
|
xelatexToSVG :: Text -> IO Tree
|
||||||
xelatexToSVG tex = handle (\(e::SomeException) -> return (failedSvg tex)) $ do
|
xelatexToSVG tex = handle (\(e::SomeException) -> return (failedSvg tex)) $ do
|
||||||
latex <- requireExecutable "xelatex"
|
latex <- requireExecutable "xelatex"
|
||||||
dvisvgm <- requireExecutable "dvisvgm"
|
dvisvgm <- requireExecutable "dvisvgm"
|
||||||
|
|
@ -104,7 +66,7 @@ xelatexToSVG tex = handle (\(e::SomeException) -> return (failedSvg tex)) $ do
|
||||||
writeFile tex_file tex_document
|
writeFile tex_file tex_document
|
||||||
appendFile tex_file tex_xelatex
|
appendFile tex_file tex_xelatex
|
||||||
appendFile tex_file tex_prologue
|
appendFile tex_file tex_prologue
|
||||||
appendFile tex_file tex
|
T.appendFile tex_file tex
|
||||||
appendFile tex_file tex_epilogue
|
appendFile tex_file tex_epilogue
|
||||||
runCmd latex ["-no-pdf", "-interaction=batchmode", "-halt-on-error", "-output-directory="++tmp_dir, tex_file]
|
runCmd latex ["-no-pdf", "-interaction=batchmode", "-halt-on-error", "-output-directory="++tmp_dir, tex_file]
|
||||||
runCmd dvisvgm [ dvi_file
|
runCmd dvisvgm [ dvi_file
|
||||||
|
|
@ -117,7 +79,7 @@ xelatexToSVG tex = handle (\(e::SomeException) -> return (failedSvg tex)) $ do
|
||||||
Nothing -> error "Malformed svg"
|
Nothing -> error "Malformed svg"
|
||||||
Just svg -> return $ unbox $ replaceUses svg
|
Just svg -> return $ unbox $ replaceUses svg
|
||||||
|
|
||||||
failedSvg :: String -> Tree
|
failedSvg :: Text -> Tree
|
||||||
failedSvg tex = defaultSvg
|
failedSvg tex = defaultSvg
|
||||||
-- text_ [ font_size_ "20"
|
-- text_ [ font_size_ "20"
|
||||||
-- , fill_ "white"] (toHtml $ "bad latex: "++tex)
|
-- , fill_ "white"] (toHtml $ "bad latex: "++tex)
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,7 @@ import Data.Monoid ((<>))
|
||||||
import Data.Text (Text, pack)
|
import Data.Text (Text, pack)
|
||||||
import Graphics.SvgTree (Document (..), Number (..), Text (..),
|
import Graphics.SvgTree (Document (..), Number (..), Text (..),
|
||||||
TextSpan (..), TextSpanContent (..),
|
TextSpan (..), TextSpanContent (..),
|
||||||
Tree, Tree (..), xmlOfDocument)
|
Tree, Tree (..), xmlOfDocument, xmlOfTree)
|
||||||
import Reanimate.LaTeX
|
|
||||||
import Reanimate.Svg
|
import Reanimate.Svg
|
||||||
import Text.XML.Light (elContent)
|
import Text.XML.Light (elContent)
|
||||||
import Text.XML.Light.Output
|
import Text.XML.Light.Output
|
||||||
|
|
@ -101,10 +100,10 @@ frameAt :: Double -> Animation -> Tree
|
||||||
frameAt t (Animation d (Frame f)) = mkGroup $ execState (f d (min d t)) id []
|
frameAt t (Animation d (Frame f)) = mkGroup $ execState (f d (min d t)) id []
|
||||||
|
|
||||||
renderTree :: Tree -> String
|
renderTree :: Tree -> String
|
||||||
renderTree = renderSizedTree Nothing Nothing
|
renderTree t = maybe "" ppElement $ xmlOfTree t
|
||||||
|
|
||||||
renderSizedTree :: Maybe Number -> Maybe Number -> Tree -> String
|
renderSvg :: Maybe Number -> Maybe Number -> Tree -> String
|
||||||
renderSizedTree w h t = ppElement $ xmlOfDocument doc
|
renderSvg w h t = ppElement $ xmlOfDocument doc
|
||||||
where
|
where
|
||||||
width = 320
|
width = 320
|
||||||
height = width / (16/9)
|
height = width / (16/9)
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ renderSvgs ani = do
|
||||||
where
|
where
|
||||||
frames = [0..frameCount-1]
|
frames = [0..frameCount-1]
|
||||||
rate = 60
|
rate = 60
|
||||||
nthFrame nth = renderTree $ frameAt (recip (fromIntegral rate) * fromIntegral nth) ani
|
nthFrame nth = renderSvg Nothing Nothing $ frameAt (recip (fromIntegral rate) * fromIntegral nth) ani
|
||||||
frameCount = round (duration ani * fromIntegral rate) :: Int
|
frameCount = round (duration ani * fromIntegral rate) :: Int
|
||||||
nameTemplate :: String
|
nameTemplate :: String
|
||||||
nameTemplate = "render-%05d.svg"
|
nameTemplate = "render-%05d.svg"
|
||||||
|
|
@ -88,7 +88,7 @@ renderFormat format ani target = do
|
||||||
-- XXX: Use threads
|
-- XXX: Use threads
|
||||||
generateFrames ani width_ rate action = withTempDir $ \tmp -> do
|
generateFrames ani width_ rate action = withTempDir $ \tmp -> do
|
||||||
let frameName nth = tmp </> printf nameTemplate nth
|
let frameName nth = tmp </> printf nameTemplate nth
|
||||||
rendered = [ renderSizedTree width height $ nthFrame n | n <- frames]
|
rendered = [ renderSvg width height $ nthFrame n | n <- frames]
|
||||||
`using` parBuffer 16 rdeepseq
|
`using` parBuffer 16 rdeepseq
|
||||||
forM_ (zip [0::Int ..] rendered) $ \(n, frame) -> do
|
forM_ (zip [0::Int ..] rendered) $ \(n, frame) -> do
|
||||||
writeFile (frameName n) frame
|
writeFile (frameName n) frame
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ resolver: lts-11.22
|
||||||
allow-newer: false
|
allow-newer: false
|
||||||
|
|
||||||
extra-deps:
|
extra-deps:
|
||||||
- reanimate-svg-0.8.1.0
|
- reanimate-svg-0.8.2.0
|
||||||
- diagrams-1.4@sha256:3e36369e84115b900fd9dcb570672a188339a470eb19ca62170775cd835cf8ca
|
- diagrams-1.4@sha256:3e36369e84115b900fd9dcb570672a188339a470eb19ca62170775cd835cf8ca
|
||||||
- diagrams-contrib-1.4.3@sha256:bcfa6c85f8c33b8c48c3a61b7216afdebd51cd793c50da3a2dd358827d25fc76
|
- diagrams-contrib-1.4.3@sha256:bcfa6c85f8c33b8c48c3a61b7216afdebd51cd793c50da3a2dd358827d25fc76
|
||||||
- diagrams-core-1.4.1.1@sha256:6ef6b17785d77997c481eb085570e21b6a00cc91d086fbf49490504130ebc7d1
|
- diagrams-core-1.4.1.1@sha256:6ef6b17785d77997c481eb085570e21b6a00cc91d086fbf49490504130ebc7d1
|
||||||
|
|
|
||||||
23
viewer/.gitignore
vendored
Executable file
23
viewer/.gitignore
vendored
Executable file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.js
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# production
|
||||||
|
# /build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
13
viewer/build/asset-manifest.json
Normal file
13
viewer/build/asset-manifest.json
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"main.css": "./static/css/main.6efe09fd.chunk.css",
|
||||||
|
"main.js": "./static/js/main.db22f45d.chunk.js",
|
||||||
|
"main.js.map": "./static/js/main.db22f45d.chunk.js.map",
|
||||||
|
"runtime~main.js": "./static/js/runtime~main.9eb600ee.js",
|
||||||
|
"runtime~main.js.map": "./static/js/runtime~main.9eb600ee.js.map",
|
||||||
|
"static/js/2.772a56e7.chunk.js": "./static/js/2.772a56e7.chunk.js",
|
||||||
|
"static/js/2.772a56e7.chunk.js.map": "./static/js/2.772a56e7.chunk.js.map",
|
||||||
|
"index.html": "./index.html",
|
||||||
|
"precache-manifest.15b8d497ab10704d87b84878b92d08cf.js": "./precache-manifest.15b8d497ab10704d87b84878b92d08cf.js",
|
||||||
|
"service-worker.js": "./service-worker.js",
|
||||||
|
"static/css/main.6efe09fd.chunk.css.map": "./static/css/main.6efe09fd.chunk.css.map"
|
||||||
|
}
|
||||||
BIN
viewer/build/favicon.ico
Executable file
BIN
viewer/build/favicon.ico
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
1
viewer/build/index.html
Normal file
1
viewer/build/index.html
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="./manifest.json"/><title>Reanimate Playground</title><link href="./static/css/main.6efe09fd.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(l){function e(e){for(var r,t,n=e[0],o=e[1],u=e[2],f=0,i=[];f<n.length;f++)t=n[f],p[t]&&i.push(p[t][0]),p[t]=0;for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(l[r]=o[r]);for(s&&s(e);i.length;)i.shift()();return c.push.apply(c,u||[]),a()}function a(){for(var e,r=0;r<c.length;r++){for(var t=c[r],n=!0,o=1;o<t.length;o++){var u=t[o];0!==p[u]&&(n=!1)}n&&(c.splice(r--,1),e=f(f.s=t[0]))}return e}var t={},p={1:0},c=[];function f(e){if(t[e])return t[e].exports;var r=t[e]={i:e,l:!1,exports:{}};return l[e].call(r.exports,r,r.exports,f),r.l=!0,r.exports}f.m=l,f.c=t,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(r,e){if(1&e&&(r=f(r)),8&e)return r;if(4&e&&"object"==typeof r&&r&&r.__esModule)return r;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:r}),2&e&&"string"!=typeof r)for(var n in r)f.d(t,n,function(e){return r[e]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="./";var r=window.webpackJsonp=window.webpackJsonp||[],n=r.push.bind(r);r.push=e,r=r.slice();for(var o=0;o<r.length;o++)e(r[o]);var s=n;a()}([])</script><script src="./static/js/2.772a56e7.chunk.js"></script><script src="./static/js/main.db22f45d.chunk.js"></script></body></html>
|
||||||
15
viewer/build/manifest.json
Executable file
15
viewer/build/manifest.json
Executable file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"short_name": "React App",
|
||||||
|
"name": "Create React App Sample",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "favicon.ico",
|
||||||
|
"sizes": "64x64 32x32 24x24 16x16",
|
||||||
|
"type": "image/x-icon"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"start_url": ".",
|
||||||
|
"display": "standalone",
|
||||||
|
"theme_color": "#000000",
|
||||||
|
"background_color": "#ffffff"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
self.__precacheManifest = [
|
||||||
|
{
|
||||||
|
"revision": "9eb600ee07a27cdad64f",
|
||||||
|
"url": "./static/js/runtime~main.9eb600ee.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"revision": "db22f45d36ec0c1e28c1",
|
||||||
|
"url": "./static/js/main.db22f45d.chunk.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"revision": "772a56e764e5091f7538",
|
||||||
|
"url": "./static/js/2.772a56e7.chunk.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"revision": "db22f45d36ec0c1e28c1",
|
||||||
|
"url": "./static/css/main.6efe09fd.chunk.css"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"revision": "8912fe90ce5c625516525c7cd80ee665",
|
||||||
|
"url": "./index.html"
|
||||||
|
}
|
||||||
|
];
|
||||||
34
viewer/build/service-worker.js
Normal file
34
viewer/build/service-worker.js
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
* Welcome to your Workbox-powered service worker!
|
||||||
|
*
|
||||||
|
* You'll need to register this file in your web app and you should
|
||||||
|
* disable HTTP caching for this file too.
|
||||||
|
* See https://goo.gl/nhQhGp
|
||||||
|
*
|
||||||
|
* The rest of the code is auto-generated. Please don't update this file
|
||||||
|
* directly; instead, make changes to your Workbox build configuration
|
||||||
|
* and re-run your build process.
|
||||||
|
* See https://goo.gl/2aRDsh
|
||||||
|
*/
|
||||||
|
|
||||||
|
importScripts("https://storage.googleapis.com/workbox-cdn/releases/3.6.3/workbox-sw.js");
|
||||||
|
|
||||||
|
importScripts(
|
||||||
|
"./precache-manifest.15b8d497ab10704d87b84878b92d08cf.js"
|
||||||
|
);
|
||||||
|
|
||||||
|
workbox.clientsClaim();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The workboxSW.precacheAndRoute() method efficiently caches and responds to
|
||||||
|
* requests for URLs in the manifest.
|
||||||
|
* See https://goo.gl/S9QRab
|
||||||
|
*/
|
||||||
|
self.__precacheManifest = [].concat(self.__precacheManifest || []);
|
||||||
|
workbox.precaching.suppressWarnings();
|
||||||
|
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
|
||||||
|
|
||||||
|
workbox.routing.registerNavigationRoute("./index.html", {
|
||||||
|
|
||||||
|
blacklist: [/^\/_/,/\/[^\/]+\.[^\/]+$/],
|
||||||
|
});
|
||||||
2
viewer/build/static/css/main.6efe09fd.chunk.css
Normal file
2
viewer/build/static/css/main.6efe09fd.chunk.css
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
body{margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}.App{height:100vh;background-color:#282c34;color:#fff;display:grid;grid-template-columns:1fr;grid-template-rows:auto;grid-auto-flow:column;-webkit-align-items:center;align-items:center;overflow:hidden}.controls{text-align:center}.controls svg{padding-left:5px;padding-right:5px}.viewer{position:static}.viewer svg{max-width:100vw;max-height:100vh;margin-top:auto;margin-bottom:auto}div.messages{position:fixed;top:0;width:100%;background:#282c34}div.messages pre{margin:0}.home{color:#fff;text-align:center;float:right;margin-right:2em}
|
||||||
|
/*# sourceMappingURL=main.6efe09fd.chunk.css.map */
|
||||||
1
viewer/build/static/css/main.6efe09fd.chunk.css.map
Normal file
1
viewer/build/static/css/main.6efe09fd.chunk.css.map
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"sources":["/home/lemmih/Coding/Haskell/reanimate/viewer/src/index.css","main.6efe09fd.chunk.css","/home/lemmih/Coding/Haskell/reanimate/viewer/src/App.css"],"names":[],"mappings":"AAAA,KACE,QAAA,CACA,SAAA,CACA,mICEY,CDCZ,kCAAA,CACA,iCCCF,CDEA,KACE,uECEF,CCbA,KAGE,YAAA,CACA,wBAAA,CACA,UAAA,CACA,YAAA,CACA,yBAAA,CACA,uBAAA,CAEA,qBAAA,CACA,0BAAA,CAAA,kBAAA,CACA,eDiBF,CCZA,UACE,iBDiBF,CCfA,cACE,gBAAA,CACA,iBDiBF,CCfA,QACE,eDiBF,CCfA,YACE,eAAA,CACA,gBAAA,CACA,eAAA,CACA,kBDiBF,CCfA,aACE,cAAA,CACA,KAAA,CACA,UAAA,CACA,kBDiBF,CCfA,iBACE,QDiBF,CCfA,MACE,UAAA,CACA,iBAAA,CACA,WAAA,CACA,gBDiBF","file":"main.6efe09fd.chunk.css","sourcesContent":["body {\n margin: 0;\n padding: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\n \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\",\n monospace;\n}\n","body {\n margin: 0;\n padding: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\n \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\",\n monospace;\n}\n\n.App {\n /* text-align: center; */\n /* min-height: 100vh; */\n height: 100vh;\n background-color: #282c34;\n color: white;\n display: grid;\n grid-template-columns: 1fr;\n grid-template-rows: auto;\n /* grid-gap: 1em; */\n grid-auto-flow: column;\n -webkit-align-items: center;\n align-items: center;\n overflow: hidden;\n}\n.editor {\n /* min-width: 35em; */\n}\n.controls {\n text-align:center;\n}\n.controls svg {\n padding-left: 5px;\n padding-right: 5px;\n}\n.viewer {\n position: static;\n}\n.viewer svg {\n max-width: 100vw;\n max-height: 100vh;\n margin-top: auto;\n margin-bottom: auto;\n}\ndiv.messages {\n position: fixed;\n top: 0;\n width: 100%;\n background: #282c34;\n}\ndiv.messages pre {\n margin: 0;\n}\n.home {\n color: white;\n text-align: center;\n float:right;\n margin-right: 2em;\n}\n\n\n#editor {\n\n}\n\n",".App {\n /* text-align: center; */\n /* min-height: 100vh; */\n height: 100vh;\n background-color: #282c34;\n color: white;\n display: grid;\n grid-template-columns: 1fr;\n grid-template-rows: auto;\n /* grid-gap: 1em; */\n grid-auto-flow: column;\n align-items: center;\n overflow: hidden;\n}\n.editor {\n /* min-width: 35em; */\n}\n.controls {\n text-align:center;\n}\n.controls svg {\n padding-left: 5px;\n padding-right: 5px;\n}\n.viewer {\n position: static;\n}\n.viewer svg {\n max-width: 100vw;\n max-height: 100vh;\n margin-top: auto;\n margin-bottom: auto;\n}\ndiv.messages {\n position: fixed;\n top: 0;\n width: 100%;\n background: #282c34;\n}\ndiv.messages pre {\n margin: 0;\n}\n.home {\n color: white;\n text-align: center;\n float:right;\n margin-right: 2em;\n}\n\n\n#editor {\n\n}\n"]}
|
||||||
2
viewer/build/static/js/2.772a56e7.chunk.js
Normal file
2
viewer/build/static/js/2.772a56e7.chunk.js
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1 @@
|
||||||
|
4078f6ee1053e716763e575de7ea78c199ad4bbd
|
||||||
2
viewer/build/static/js/main.db22f45d.chunk.js
Normal file
2
viewer/build/static/js/main.db22f45d.chunk.js
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
(window.webpackJsonp=window.webpackJsonp||[]).push([[0],{10:function(e,n,t){e.exports=t(18)},16:function(e,n,t){},17:function(e,n,t){},18:function(e,n,t){"use strict";t.r(n);var s=t(0),a=t.n(s),o=t(4),r=t.n(o),i=(t(16),t(2)),c=t(5),l=t(6),m=t(9),g=t(7),u=t(1),d=t(8),v=(t(17),function(e){function n(e){var t;Object(c.a)(this,n),(t=Object(m.a)(this,Object(g.a)(n).call(this,e))).connect=function(){var e=new WebSocket("ws://localhost:9161");e.onopen=function(n){t.setState(function(e){return Object(i.a)({},e,{message:"Connected."})}),e.send("60")},e.onclose=function(e){t.setState(function(e){return Object(i.a)({},e,{message:"Disconnected."})}),setTimeout(t.connect,1e3)},e.onmessage=function(e){if("Success!"===e.data)console.log("Success");else if("Compiling"===e.data)t.setState({message:"Compiling..."});else if("Rendering"===e.data)t.setState({message:"Rendering..."}),t.nFrames_new=0,t.svgs_new=[];else if("Done"===e.data)t.setState({message:""}),console.log("Done"),t.nFrames=t.nFrames_new,t.svgs=t.svgs_new,t.nFrames_new=0,t.svgs_new=[],t.start=Date.now();else if(e.data.startsWith("Error"))console.log("Error"),t.setState({message:e.data.substring(5)});else{t.setState({message:"Rendering: ".concat(t.nFrames_new)}),t.nFrames_new++;var n=document.createElement("div");n.innerHTML=e.data,t.svgs_new.push(n)}},t.setState(function(n){return Object(i.a)({},n,{socket:e,message:"Connecting..."})})},t.onLoad=function(e){setTimeout(function(){e.resize()},0)},t.state={},setTimeout(t.connect,0),t.nFrames_new=0,t.svgs_new=[],t.nFrames=0,t.svgs=[],t.start=Date.now();var s=Object(u.a)(t);return requestAnimationFrame(function e(){var n=Date.now(),a=s.nFrames,o=Math.round((n-t.start)/1e3*60)%a;if(s.svgs_new.length){for(;s.svg.firstChild;)s.svg.removeChild(s.svg.firstChild);s.svg.appendChild(s.svgs_new[s.svgs_new.length-1])}else if(a){for(;s.svg.firstChild;)s.svg.removeChild(s.svg.firstChild);s.svg.appendChild(s.svgs[o])}else s.svg.innerText="";requestAnimationFrame(e)}),t}return Object(d.a)(n,e),Object(l.a)(n,[{key:"render",value:function(){var e=this,n=this.state.message;return a.a.createElement("div",{className:"App"},a.a.createElement("div",{className:"viewer"},a.a.createElement("div",{ref:function(n){return e.svg=n}}),a.a.createElement("div",{className:"messages"},a.a.createElement("pre",null,n))))}}]),n}(s.Component));Boolean("localhost"===window.location.hostname||"[::1]"===window.location.hostname||window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/));r.a.render(a.a.createElement(v,null),document.getElementById("root")),"serviceWorker"in navigator&&navigator.serviceWorker.ready.then(function(e){e.unregister()})}},[[10,1,2]]]);
|
||||||
|
//# sourceMappingURL=main.db22f45d.chunk.js.map
|
||||||
1
viewer/build/static/js/main.db22f45d.chunk.js.map
Normal file
1
viewer/build/static/js/main.db22f45d.chunk.js.map
Normal file
File diff suppressed because one or more lines are too long
2
viewer/build/static/js/runtime~main.9eb600ee.js
Normal file
2
viewer/build/static/js/runtime~main.9eb600ee.js
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
!function(e){function r(r){for(var n,f,i=r[0],l=r[1],a=r[2],c=0,s=[];c<i.length;c++)f=i[c],o[f]&&s.push(o[f][0]),o[f]=0;for(n in l)Object.prototype.hasOwnProperty.call(l,n)&&(e[n]=l[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,a||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++){var l=t[i];0!==o[l]&&(n=!1)}n&&(u.splice(r--,1),e=f(f.s=t[0]))}return e}var n={},o={1:0},u=[];function f(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.m=e,f.c=n,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,r){if(1&r&&(e=f(e)),8&r)return e;if(4&r&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)f.d(t,n,function(r){return e[r]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="./";var i=window.webpackJsonp=window.webpackJsonp||[],l=i.push.bind(i);i.push=r,i=i.slice();for(var a=0;a<i.length;a++)r(i[a]);var p=l;t()}([]);
|
||||||
|
//# sourceMappingURL=runtime~main.9eb600ee.js.map
|
||||||
1
viewer/build/static/js/runtime~main.9eb600ee.js.map
Normal file
1
viewer/build/static/js/runtime~main.9eb600ee.js.map
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
||||||
c3337c953a23ef5eb5f30ed154dd591fe5a8645e
|
6c7a4342c0b1d2c4a2a8b83b5ecc53ee6d1b6622
|
||||||
|
|
@ -2,10 +2,9 @@
|
||||||
"name": "viewer",
|
"name": "viewer",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://lemmih.github.io/reanimate",
|
"homepage": ".",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react": "^16.8.2",
|
"react": "^16.8.2",
|
||||||
"react-ace": "^6.4.0",
|
|
||||||
"react-dom": "^16.8.2",
|
"react-dom": "^16.8.2",
|
||||||
"react-scripts": "2.1.5"
|
"react-scripts": "2.1.5"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,5 @@
|
||||||
import React, {Component} from 'react';
|
import React, {Component} from 'react';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import AceEditor from 'react-ace';
|
|
||||||
import 'brace/mode/haskell';
|
|
||||||
import 'brace/theme/github';
|
|
||||||
import 'brace/theme/monokai';
|
|
||||||
|
|
||||||
import preset from './Presets';
|
|
||||||
|
|
||||||
class App extends Component {
|
class App extends Component {
|
||||||
connect = () => {
|
connect = () => {
|
||||||
|
|
@ -64,7 +58,6 @@ class App extends Component {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
program: preset[0].programs[0].code
|
|
||||||
};
|
};
|
||||||
setTimeout(this.connect, 0);
|
setTimeout(this.connect, 0);
|
||||||
this.nFrames_new = 0;
|
this.nFrames_new = 0;
|
||||||
|
|
@ -101,27 +94,8 @@ class App extends Component {
|
||||||
ace.resize();
|
ace.resize();
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
onChange = text => {
|
|
||||||
this.setState({program: text});
|
|
||||||
if (this.timeout)
|
|
||||||
clearTimeout(this.timeout);
|
|
||||||
const socket = this.state.socket
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
this.timeout = setTimeout(function() {
|
|
||||||
console.log('change', text);
|
|
||||||
self.setState(state => ({
|
|
||||||
...state,
|
|
||||||
message: "Compiling..."
|
|
||||||
}));
|
|
||||||
socket.send(text);
|
|
||||||
}, 500);
|
|
||||||
};
|
|
||||||
selectPreset = evt => {
|
|
||||||
this.onChange(evt.target.value);
|
|
||||||
};
|
|
||||||
render() {
|
render() {
|
||||||
const {message, program} = this.state;
|
const {message} = this.state;
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<div className="viewer">
|
<div className="viewer">
|
||||||
|
|
|
||||||
|
|
@ -1,217 +0,0 @@
|
||||||
const latex_draw =
|
|
||||||
`animation :: Animation
|
|
||||||
animation =
|
|
||||||
bg \`sim\` (autoReverse $ drawText \`andThen\` fillText)
|
|
||||||
where
|
|
||||||
bg = mkAnimation 0 $ emit (mkBackground "black")
|
|
||||||
msg = "\\\\sum_{k=1}^\\\\infty {1 \\\\over k^2} = {\\\\pi^2 \\\\over 6}"
|
|
||||||
glyphs = center $ latexAlign msg
|
|
||||||
fillText = mkAnimation 1 $ do
|
|
||||||
s <- signal 0 1
|
|
||||||
emit $ scale 5 $ withFillColor "white" $ withFillOpacity s glyphs
|
|
||||||
drawText = mkAnimation 2 $ do
|
|
||||||
s <- signal 0 1
|
|
||||||
emit $ scale 5 $
|
|
||||||
withStrokeColor "white" $ withFillOpacity 0 $ withStrokeWidth (Num 0.1) $
|
|
||||||
partialSvg s glyphs`;
|
|
||||||
|
|
||||||
const bbox =
|
|
||||||
`animation :: Animation
|
|
||||||
animation = bg \`sim\`
|
|
||||||
mapA (translate (-50) 0) bbox1 \`sim\`
|
|
||||||
mapA (translate 50 0) bbox2
|
|
||||||
where
|
|
||||||
bg = mkAnimation 0 $ emit $ mkBackground "black"
|
|
||||||
|
|
||||||
bbox1 :: Animation
|
|
||||||
bbox1 = mkAnimation 5 $ do
|
|
||||||
s <- signal 0 1
|
|
||||||
emit $ mkGroup
|
|
||||||
[ mkBoundingBox $ rotate (360*s) svg
|
|
||||||
, withFillColor "white" $ rotate (360*s) svg ]
|
|
||||||
where
|
|
||||||
svg = scale 3 $ center $ latexAlign "\\\\sum_{k=1}^\\\\infty"
|
|
||||||
|
|
||||||
bbox2 :: Animation
|
|
||||||
bbox2 = autoReverse $ mkAnimation 2.5 $ do
|
|
||||||
s <- signal 0 1
|
|
||||||
emit $ mkGroup
|
|
||||||
[ mkBoundingBox $ partialSvg s heartShape
|
|
||||||
, withStrokeColor "white" $ withFillOpacity 0 $ partialSvg s heartShape ]
|
|
||||||
|
|
||||||
mkBoundingBox :: Tree -> Tree
|
|
||||||
mkBoundingBox svg = withStrokeColor "red" $ withFillOpacity 0 $
|
|
||||||
mkRect (S.Num x, S.Num y) (S.Num w) (S.Num h)
|
|
||||||
where
|
|
||||||
(x, y, w, h) = boundingBox svg
|
|
||||||
|
|
||||||
heartShape =
|
|
||||||
center $ rotateAroundCenter 225 $ mkPathString
|
|
||||||
"M0.0,40.0 v-40.0 h40.0a20.0 20.0 90.0 0 1 0.0,40.0a20.0 20.0 90.0 0 1 -40.0,0.0 Z"`;
|
|
||||||
|
|
||||||
const sinewave =
|
|
||||||
`animation :: Ani ()
|
|
||||||
animation = proc () -> do
|
|
||||||
duration 10 -< ()
|
|
||||||
emit -< toHtml $ mkBackground "black"
|
|
||||||
idx <- signalOscillate 0 1 -< ()
|
|
||||||
emit -< do
|
|
||||||
defs_ $ clipPath_ [id_ "clip"] $ toHtml $
|
|
||||||
mkRect (Num 0, Num (-height)) (Num $ idx*width) (Num 320)
|
|
||||||
toHtml $ translate margin height $ withStrokeColor "white" $
|
|
||||||
withClipPathRef (Ref "clip") $ mkPathText $ renderPathText $ approxFnData 100 wave
|
|
||||||
toHtml $ withStrokeColor "white" $
|
|
||||||
mkLine (Num margin, Num 10) (Num margin, Num 170)
|
|
||||||
toHtml $ withStrokeColor "white" $
|
|
||||||
mkLine (Num margin, Num height) (Num (margin+width), Num height)
|
|
||||||
let (circX, circY) = wave idx
|
|
||||||
emit -< g_ [transform_ $ Lucid.translate margin height] $
|
|
||||||
circle_ [num_ cx_ circX, num_ cy_ circY, r_ "3", fill_ "red"]
|
|
||||||
where
|
|
||||||
freq = 3; margin = 30; width = 260; height = 90
|
|
||||||
wave idx = (idx*width, sin (idx*pi*2*freq) * 50)`;
|
|
||||||
|
|
||||||
const morph_wave =
|
|
||||||
`animation :: Animation
|
|
||||||
animation = autoReverse $ mkAnimation 2.5 $ do
|
|
||||||
morph <- signal 0 1
|
|
||||||
emit $ mkBackground "black"
|
|
||||||
emit $ withStrokeColor "white" $ translate (-320/2) (-180/2) $ mkGroup
|
|
||||||
[ translate 30 50 $ mkLinePath wave1
|
|
||||||
, translate 30 130 $ mkLinePath wave2
|
|
||||||
, translate 30 90 $ mkLinePath $ morphPath wave1 wave2 morph
|
|
||||||
, mkLine (Num 30, Num 10) (Num 30, Num 170)
|
|
||||||
, mkLine (Num 30, Num 90) (Num 290, Num 90) ]
|
|
||||||
where
|
|
||||||
freq = 3; width = 260
|
|
||||||
wave1 = approxFnData 100 $ \\idx -> (idx*width, sin (idx*pi*2*freq) * 20)
|
|
||||||
wave2 = approxFnData 100 $ \\idx -> (idx*width, sin (idx*pi*2*(freq*3)) * 20)`;
|
|
||||||
|
|
||||||
const morph_wave_circle =
|
|
||||||
`animation :: Animation
|
|
||||||
animation = autoReverse $ mkAnimation 2.5 $ do
|
|
||||||
idx <- signal 0 1
|
|
||||||
emit $ mkBackground "black"
|
|
||||||
emit $ withStrokeColor "white" $ translate (-320/2) (-180/2) $ mkGroup
|
|
||||||
[ translate 30 90 $ mkLinePath $ morphPath circle wave1 idx
|
|
||||||
, mkLine (Num 30, Num 10) (Num 30, Num 170)
|
|
||||||
, mkLine (Num 30, Num 90) (Num 290, Num 90) ]
|
|
||||||
where
|
|
||||||
freq = 5; width = 260; radius = 50
|
|
||||||
wave1 = approxFnData 100 $ \\idx -> (idx*width, sin (idx*pi*2*freq) * 20)
|
|
||||||
circle = approxFnData 100 $ \\idx ->
|
|
||||||
(cos (idx*pi*2+pi/2)*radius + width/2, sin (idx*pi*2+pi/2)*radius)`;
|
|
||||||
|
|
||||||
const progressMeters =
|
|
||||||
`animation :: Animation
|
|
||||||
animation =
|
|
||||||
bg \`sim\` labels \`sim\`
|
|
||||||
mapA (translate (-100) 0) (adjustSpeed 1.0 progressMeter) \`simLoop\`
|
|
||||||
mapA (translate 0 0) (adjustSpeed 2.0 progressMeter) \`simLoop\`
|
|
||||||
mapA (translate 100 0) (adjustSpeed 0.5 progressMeter)
|
|
||||||
where
|
|
||||||
bg = mkAnimation 0 $ emit $ mkBackground "black"
|
|
||||||
labels = mkAnimation 0 $ emit $ translate 0 70 $ withFillColor "white" $ mkGroup
|
|
||||||
[ translate (-100) 0 $ scale 2 $ center $ latex "1x"
|
|
||||||
, translate 0 0 $ scale 2 $ center $ latex "2x"
|
|
||||||
, translate 100 0 $ scale 2 $ center $ latex "0.5x"
|
|
||||||
]
|
|
||||||
|
|
||||||
progressMeter :: Animation
|
|
||||||
progressMeter = mkAnimation 3 $ do
|
|
||||||
h <- signal 0 100
|
|
||||||
emit $ center $ mkGroup
|
|
||||||
[ withStrokeColor "white" $ withStrokeWidth (Num 2) $ withFillOpacity 0 $
|
|
||||||
mkRect (Num 0, Num 0) (Num 30) (Num 100)
|
|
||||||
, withFillColor "white" $
|
|
||||||
mkRect (Num 0, Num 0) (Num 30) (Num h) ]`
|
|
||||||
|
|
||||||
const latex_basic =
|
|
||||||
`animation :: Animation
|
|
||||||
animation = autoReverse $ mkAnimation 2 $ do
|
|
||||||
s <- signal 0 1
|
|
||||||
emit $ mkGroup
|
|
||||||
[ mkBackground "black"
|
|
||||||
, withStrokeColor "white" $ withFillOpacity 0 $ withStrokeWidth (Num 0.1) text
|
|
||||||
, withFillColor "white" $ withFillOpacity s text ]
|
|
||||||
where
|
|
||||||
text = scale 4 $ center $ latexAlign
|
|
||||||
"\\\\sum_{k=1}^\\\\infty {1 \\\\over k^2} = {\\\\pi^2 \\\\over 6}"`
|
|
||||||
|
|
||||||
const latex_color =
|
|
||||||
`animation :: Animation
|
|
||||||
animation = mkAnimation 1 $ do
|
|
||||||
emit $ mkBackground "black"
|
|
||||||
emit $ withStrokeWidth (Num 0.2) $
|
|
||||||
withStrokeColor "white" $
|
|
||||||
withSubglyphs [0] (withFillColor "blue") $
|
|
||||||
withSubglyphs [1] (withFillColor "yellow") $
|
|
||||||
withSubglyphs [2] (withFillColor "green") $
|
|
||||||
withSubglyphs [3] (withFillColor "red") $
|
|
||||||
withSubglyphs [4] (withFillColor "darkslategrey") $
|
|
||||||
svg
|
|
||||||
where
|
|
||||||
svg = scale 10 $ center $ latex "\\\\LaTeX"`;
|
|
||||||
|
|
||||||
const valentine =
|
|
||||||
`animation :: Animation
|
|
||||||
animation =
|
|
||||||
all_red \`before\`
|
|
||||||
( background \`sim\`
|
|
||||||
(backgroundDelay \`before\`
|
|
||||||
foldr1 sim [ pause p \`before\` fallingLove p x | (p, x) <- falling ]
|
|
||||||
) \`sim\`
|
|
||||||
(heart_ani \`before\` heart_disappear) \`sim\`
|
|
||||||
(pause 1 \`before\` repeatAnimation 10 (message ai))
|
|
||||||
)
|
|
||||||
where
|
|
||||||
falling = [(6.4, 0.09), (4.9, 0.12), (4.5, 0.88), (0.3, 0.43), (5.3, 0.93)
|
|
||||||
,(0.1, 0.80), (1.1, 0.39), (2.3, 0.21), (2.9, 0.77), (3.4, 0.46)
|
|
||||||
,(6.2, 0.88), (5.9, 0.80), (3.2, 0.14), (7.7, 0.99), (3.4, 0.35)
|
|
||||||
,(0.4, 0.51), (7.1, 0.60), (7.7, 0.65)]
|
|
||||||
ai = center $ xelatex "爱"
|
|
||||||
all_red = mkAnimation 1 $ emit $ mkBackground "red"
|
|
||||||
background = mkAnimation 2 $ do
|
|
||||||
n <- round <$> signal 0 0xFF
|
|
||||||
emit $ mkBackgroundPixel $ PixelRGBA8 0xFF n n 0xFF
|
|
||||||
backgroundDelay = pause (duration background-1)
|
|
||||||
heart_ani = repeatAnimation 10 $ mkAnimation 1 $ do
|
|
||||||
n <- oscillate $ signalSCurve 2 0.9 1.1
|
|
||||||
mapF (scale n) $ drawHeart
|
|
||||||
heart_disappear = mkAnimation 3 $ do
|
|
||||||
n <- signal 0.9 10
|
|
||||||
o <- oscillate $ signal 0 1.5
|
|
||||||
mapF (scale n) drawHeart
|
|
||||||
mapF (scale (n*4)) $ emit $ withFillOpacity o $ withFillColor "white" ai
|
|
||||||
fallingLove rand xPos = mkAnimation 2 $ do
|
|
||||||
n <- signal (-100) 90
|
|
||||||
o <- signal 0 5
|
|
||||||
emit $ withStrokeColor "black" $ withFillColor "red" $
|
|
||||||
translate ((xPos*2-1)*(320/2)) n $ scale 0.3 $ rotate (60*(o+rand+xPos)) heartShape
|
|
||||||
message txt = mkAnimation 1 $ do
|
|
||||||
o <- oscillate $ signal 0 1
|
|
||||||
n <- oscillate $ signalSCurve 2 0.9 1.1
|
|
||||||
emit $ scale n $ scale 2 $ withFillColor "white" $ withFillOpacity o txt
|
|
||||||
|
|
||||||
drawHeart = emit $ withFillColor "red" $ heartShape
|
|
||||||
|
|
||||||
heartShape =
|
|
||||||
center $ rotateAroundCenter 225 $ mkPathString
|
|
||||||
"M0.0,40.0 v-40.0 h40.0a20.0 20.0 90.0 0 1 0.0,40.0a20.0 20.0 90.0 0 1 -40.0,0.0 Z"`;
|
|
||||||
|
|
||||||
export default [
|
|
||||||
{ name: "Examples"
|
|
||||||
, programs:
|
|
||||||
[ {name: "LaTeX Draw", code: latex_draw }
|
|
||||||
, {name: "LaTeX Color", code: latex_color }
|
|
||||||
, {name: "LaTeX Basic", code: latex_basic }
|
|
||||||
, {name: "Bounding boxes", code: bbox }
|
|
||||||
// , {name: "Sinewave", code: sinewave }
|
|
||||||
, {name: "Morphwave", code: morph_wave }
|
|
||||||
, {name: "Morphwave Circle", code: morph_wave_circle }
|
|
||||||
, {name: "Progress meters", code: progressMeters }
|
|
||||||
, {name: "Valentine", code: valentine }
|
|
||||||
// , {name: "Highlight", code: highlight }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
];
|
|
||||||
Loading…
Reference in a new issue