LoginSignup
18
2

More than 3 years have passed since last update.

Elmでportもネイティブモジュールも使わずJSと通信する方法

Last updated at Posted at 2018-12-20

800px-English_Elm_avenue.jpg

ElmでウェブブラウザのAPIを直接叩けるのは公式のパッケージだけで、サードパーティのパッケージではネイティブなモジュールもportも使うこともできません。でも、joakin/elm-canvas というパッケージが存在していて、公式で対応していないはずのCanvas APIを叩いているのです。どないなっとんねん!と思って調べたので、どんな方法でやっているのか簡単に紹介しておきます。

1. 外部に送信したいデータを、propertyを使って要素の"cmds"というプロパティに突っ込む

commands : Commands -> Attribute msg
commands list =
    list
        |> Encode.list identity
        |> property "cmds"

既存のプロパティでなければどんな名前でもいいはずですが、em-canvasでは"cmds"というプロパティに突っ込んでいるようです。ちなみのこのデータの中身は、次のような感じのJSONになっていました。

[
    {type: "function", name: "restore", args: []},
    {type: "function", name: "fill", args: ["nonzero"]},
    {type: "field", name: "fillStyle", value: "rgba(0%,0%,0%,0.3)"},
    ...

2. elm-canvasというCustom Elementsを描画する

toHtml : ( Int, Int ) -> List (Attribute msg) -> List Renderable -> Html msg
toHtml ( w, h ) attrs entities =
    Html.node "elm-canvas"
        [ commands (render entities) ]
        [ canvas (height h :: width w :: attrs) []
        ]

1で定義したcommandsを使って、そのelm-canvascmdsプロパティにデータを突っ込んでいるわけです。ついでに、その内側に実際の描画先となるcanvas要素も作ってあります。

3. そのCustom Elementsの定義のsetアクセサで、Elm側から送られたデータを受け取る

customElements.define(
  "elm-canvas",
  class extends HTMLElement {

    ...

    set cmds(values) {
      this.commands = values;
      this.render();
    }

    ...

  }
);

JavaScript側のelm-canvas要素の定義で、cmdssetアクセサを用意して、そこでデータを受け取ります。あとは受け取ったデータを元にCanvasの描画を行うだけです。

まとめ

というわけで、Custom Elementsのプロパティ越しにデータを送れば、elm-canvas.jsというスクリプトを別に読み込む必要はあるものの、ネイティブモジュールもportも使わずに、Elmのパッケージから外部のAPIを叩くことができるということがわかりました。このやり方ではJavaScript側からElm側へデータを送ることはできないので、measureTextのような機能は実現できないという制限はあるでしょうが、簡単な描画であればこれで十分でしょう。

……闇の魔術じゃん!

追記

……と思いきや、akira_さんから カスタムイベントでJSからElmへデータを送る方法が提案され、ElmからJSだけでなくJSからElmへとデータを送ることも問題なくできることがわかりました。portガン無視でデータを送りまくれるぞ! 悪の枢軸ッ! 

18
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
2