RiotとGo言語でデジモンのドット絵打つだけのサイト作った

16*16の2色のドット絵を打って投稿するサイトです。
突発的に思いついて5時間近く費やして作りました。

「Digital Pixel Monster」 http://digimon.laineus.com/

Digital Pixel Monster、略してデジモンです。

![digimon_ss2.png](https://qiita-image-store.s3.amazonaws.com/0/151137/5c1502b6-a132-cf43-88b1-756be0a4835d.png)

何気にGoで作ったapiを公開サーバーで実際に運用するの初めてだったりします。

# 使い方

左のキャンバスはピクセルをクリックすると着色できます。
着色済みのピクセルをクリックすると無色に戻ります。

右側ではサイトに投稿された作品一覧を閲覧できます。
何でも自由に投稿して大丈夫ですが、僕の独断で整理（削除）する場合があります。

riotとcssで描画しているだけなので画像データになったりはしません。

# ソース

以下、RiotとGoのソース（一部）です。
ご指摘・アドバイス大歓迎です。

## Riot ソース

描画と編集を行うコンポーネントです。
動作に最低限必要なところだけ抜き出してます。

```html:app-canvas.tag
<app-canvas>
  <ul class="dots">
    <li each="{row, y in dots}">
      <ul class="row">
        <li class="{active: val==1}" each="{val, x in row}" onclick="{paint.bind(this, x, y)}"></li>
      </ul>
    </li>
  </ul>

  <style scoped>
    :scope {
      display: flex;
      flex-direction: column;
      min-height: 300px;
      align-items: center;
      justify-content: center;
    }
    :scope .dots {
      display: inline-flex;
      flex-direction: column;
      border-top: 1px solid rgba(0,0,0,0.15);
      border-left: 1px solid rgba(0,0,0,0.15);
    }
    :scope .dots .row {
      display: flex;
      flex-direction: row;
    }
    :scope .dots li {
      list-style: none;
    }
    :scope .dots .row li {
      width: 7px;
      height: 7px;
      border-right: 1px solid rgba(0,0,0,0.15);
      border-bottom: 1px solid rgba(0,0,0,0.15);
    }
    :scope .dots .row li:hover {
      background: #ccc;
    }
    :scope .dots .row li.active {
      background: #333;
    }
    :scope .dots .row li.active:hover {
      background: #666;
    }
  </style>

  <script>
    var self = this;
    self.digimons = [];
    self.dots = [
      [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
      [0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0],
      [0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0],
      [0,0,1,1,1,0,0,0,0,1,1,0,0,1,0,0],
      [0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0],
      [0,1,0,0,0,0,0,0,0,1,1,1,0,1,0,0],
      [0,1,0,0,0,0,1,1,0,0,0,0,0,1,0,0],
      [0,0,1,1,1,1,0,0,0,0,0,0,0,1,0,0],
      [0,0,1,0,0,0,0,0,1,1,0,0,1,0,0,0],
      [0,0,0,1,1,1,1,1,0,1,1,0,1,0,0,0],
      [0,0,1,0,0,1,0,0,1,0,0,0,0,1,0,0],
      [0,0,1,1,1,1,0,0,1,1,1,1,0,1,0,0],
      [0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,0],
      [0,0,0,1,1,0,0,1,1,1,1,0,0,0,1,0],
      [0,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1],
      [0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1],
    ];
    self.paint = function(x, y, e) {
      self.dots[y][x] = (self.dots[y][x] == 1) ? 0 : 1;
      self.update();
    }
  </script>
</app-canvas>
```

16*16の長さの配列を`[][]int`型で用意して、それをキャンバスとして扱っています。
テンプレートでは、この配列をループして、0なら白、1なら黒になるようclass名を付与しています。

各ドットをクリックした際のイベントでは、白なら黒、黒なら白に切り替える処理をしています。

`[{x:2,y:3},{x:6,y:4}]`みたいな感じで、塗った部分の座標を保持する形でもできましたかね。

### 実際のソース

||ソース|
|---|---|
|index.html|view-source:http://digimon.laineus.com/index.html|
|editor component|view-source:http://digimon.laineus.com/app-editor.html|
|viewer component|view-source:http://digimon.laineus.com/app-viewer.html|


### Go ソース

コントローラー部分のみ抜粋

```go
package controller

import (
  "../models"
  "github.com/gin-gonic/gin"
  "strconv"
)

// GetDigimon デジモン取得api
func GetDigimon(c *gin.Context) {
  digimonID, e := strconv.Atoi(c.Query("id"))
  repo := model.NewDigimonRepository()
  if e == nil {
    digimon := repo.GetByID(digimonID)
    c.JSON(200, digimon)
  } else {
    digimons := repo.GetAll()
    c.JSON(200, digimons)
  }
}

// Request リクエスト形式を定義する構造体
type Request struct {
  Name string `json:"name"`
  Data [][]int `json:"data"`
}

// PostDigimon デジモン投稿api
func PostDigimon(c *gin.Context) {
  var request Request
  c.BindJSON(&request)
  chk := checkSize(&request.Data, 16, 16)
  if chk {
    if request.Name == "" {
      request.Name = "no name"
    }
    repo := model.NewDigimonRepository()
    repo.SetNewDigimon(request.Name, &request.Data)
    digimons := repo.GetAll()
    c.JSON(200, digimons)
  } else {
    c.JSON(200, false)
  }
}

// n*nの[][]intであるかチェック
func checkSize(dots *[][]int, width, height int) bool {
  chk := true
  if len(*dots) != height {
    chk = false
  } else {
    for _, row := range *dots {
      if len(row) != width {
        chk = false
        break
      }
    }
  }
  return chk
}
```

DBには、`[][]int`のデータをそのままjson型で突っ込んでます。