为Canvas设计一个绘图api



我正在添加一些功能到threenpenny ui api。我希望有能力用画布画线。

我可以写的函数有以下签名:

moveTo :: Vector -> UI ()
lineTo :: Vector -> UI ()
stroke :: UI ()
strokeStyle :: UI ()
beginPath :: UI ()

每个原语moveTolineTo应该出现在beginPath之间。中风的电话。你将如何执行beginPath…中风序列。通过设计,我想让用户没有选择绘制线条。所以用户不知道beginPath…中风序列。

将API设计成不会被不恰当地使用绝对是件好事。这里可以采用的一种方法是创建一个未导出的包装器,该包装器允许您控制这些特定操作的组合方式(对不起,我没有尝试运行这个):

-- Don't export constructor
newtype Line a = Line { runLine :: UI a }
-- Wrap the return types in your current implementation with Line, for:
moveTo :: Vector -> Line ()
lineTo :: Vector -> Line ()
...
instance Monad Line where
         (Line ui) >>= f = Line (ui >>= a-> beginPath >> (runLine $ f a))
         return = Line . return

其他几点:

  1. 你可能想使用Monoid实例代替,如果你的API不需要绑定任何值(即所有的行API函数在-> Line ()

  2. 结束)
  3. 如果你需要做一些事情,比如在startend动作或其他动作中包装整个组合行动作序列,你可以进一步扩展上面的

    runLine (Line ui) = start >> ui >> end
    

我将如何设计一个canvas API

newtype Drawing = ...
instance Monoid Drawing where ... -- for combining drawings
line :: Vector -> Vector -> Drawing
path :: [Vector] -> Drawing
withStyle :: Style -> Drawing -> Drawing
runDrawing :: Drawing -> UI ()

这里的函数操作语义上有意义的对象(从用户的角度来看),而不是命令式命令。这应该可以通过

类型实现。
newtype Drawing = Drawing (UI ())

然而,有时微妙的要求类型有更多的结构,所以开放的(例如Something -> UI ())。

相关内容

最新更新