Elm 0.19の練習（インタラクティブな似顔絵を作ろう）

![Dec-21-2019 11-52-56.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32030/7c3645bf-26b1-5c78-e97c-140010dc6a92.gif)

ソースコードはこちらに全部あります。
https://github.com/naga3/elm-tutorial

# Elmとは

`Elm`はWebのフロントエンドを作るのに向いている言語です。JavaScriptやHTMLに変換されます。


大変分かりやすい日本語ガイドがありますので、こちらを参照すれば基本的な部分はマスターできます。
https://guide.elm-lang.jp/

対象バージョンは`Elm 0.19`です。

# インストール

こちらを参照してElm本体をインストールしてください。
https://guide.elm-lang.jp/install.html

適当なディレクトリを作り、`elm init`を実行すれば最低限のプロジェクトが作られます。

## VS Code拡張

Extensionは複数ありますが、非推奨のものもあるので、最新のこちらを導入します。
https://marketplace.visualstudio.com/items?itemName=Elmtooling.elm-ls-vscode

# Hello World

`src/Hello.elm`というファイルを以下の内容で作ります。

```elm
module Hello exposing (main)

import Html exposing (text)


main =
    text "Hello, world"
```

`elm reactor`を実行すればブラウザで確認できます。簡単ですね。

# 画像をインタラクティブに動かしてみる

公式でSVGがサポートされているのでインストールします。

```sh
elm install elm/svg
```

`src/Ellipse.elm`というファイルを以下の内容で作ります。

```elm
module Ellipse exposing (main)

import Browser
import Html
import Html.Attributes as HtmlAttr
import Html.Events as HtmlEvent
import Svg
import Svg.Attributes as SvgAttr


main =
    Browser.sandbox { init = init, update = update, view = view }


type alias Model =
    { width : String
    , height : String
    }


init : Model
init =
    Model "100" "100"


type Msg
    = Width String
    | Height String


update : Msg -> Model -> Model
update msg model =
    case msg of
        Width width ->
            { model | width = width }

        Height height ->
            { model | height = height }


view : Model -> Html.Html Msg
view model =
    Html.div []
        [ Html.div []
            [ Html.text "幅"
            , Html.input
                [ HtmlAttr.type_ "number"
                , HtmlAttr.value model.width
                , HtmlEvent.onInput Width
                ]
                []
            ]
        , Html.div []
            [ Html.text "高さ"
            , Html.input
                [ HtmlAttr.type_ "number"
                , HtmlAttr.value model.height
                , HtmlEvent.onInput Height
                ]
                []
            ]
        , Svg.svg
            [ SvgAttr.width "500"
            , SvgAttr.height "500"
            , SvgAttr.viewBox "0 0 500 500"
            ]
            [ Svg.ellipse
                [ SvgAttr.cx "100"
                , SvgAttr.cy "100"
                , SvgAttr.rx model.width
                , SvgAttr.ry model.height
                , SvgAttr.fill "hotpink"
                ]
                []
            ]
        ]
```

フォームで楕円のサイズをインタラクティブに変更できます。

![Dec-21-2019 11-01-40.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32030/0363293a-ec9a-b4f7-2ce8-4ed05a154b93.gif)

 `The Elm Architecture`では、モデルを定義して、それを介してあらゆるデータをやり取りします。

`init`は初期化、`view`は見た目、`update`は変更があったときの処理です。

```elm
type Msg
    = Width String
    | Height String
```

`Msg`型は`Width`関数か`Height`関数のどちらかを持つという定義です。
`Msg`, `Width`, `Height`は、内部で定義したものなので名前は何でもいいです。

```elm
HtmlEvent.onInput Width
HtmlEvent.onInput Height
```

`onInput`関数で入力された文字列は`Msg`型として`update`に渡されます、

```elm
    case msg of
        Width width ->
            { model | width = width }
```

`update`関数でパターンマッチングを行い、型の種類に応じてモデルの適切なフィールドに値を入れています。

詳しくはこちらが大変分かりやすいので参考にしてみてください。
https://guide.elm-lang.jp/architecture/buttons.html