最終更新: a few seconds agoRemove Netlify-related code from main (grafted, HEAD)

ラベル種類追加

概要

  • circus-web-ui の CIRCUS DB 部分 (case) を更新して cuboid, ellipsoid, rectangle, ellipsis の 4 つのアノテーションを作れるようにする。
  • ラベルに文字列の名前を付けられるようにする。

CIRCUS DB のラベルは現在以下のようなフォーマットになっている。

// MongoDB の clinicalCases の revisions[].labels にある
"labels": [
  {
    "type": "voxel",
    "data": {
      "color": "#ff0000",
      "alpha": 0.7,
      "voxels": "9213eda1bdedaf2791e61585b352f6fe782fb08e",
      "origin": [295, 245, 23],
      "size": [40, 22, 14]
    }
  },
  {
    "type": "voxel",
    "data": { ... }
  }
]

現在はこの type: "voxel" は固定となっているが、ここを可変にし、既存の "voxel" に加え、"cuboid" (3D), "ellipsoid" (3D), "rectangle" (2D), "ellipse" (2D) の 4 つのデータ構造を保存できるようにする。data にはそれぞれの type に対応する座標値や色の情報が入る。

また、type, data の隣に name というキーをオプションで保存できるようにする。名前は省略可能。

バックエンド側 (circus-api)

packages/circus-api/src/schemas/label.yaml を修正する。

  • 上記の 5 種類のデータ構造のバリデーションを行えるようにする。JSON Schema の oneOf を使う。
    data:
      type: object
      oneOf:
        - properties:
            type:
              constant: voxel
            data:
              type: object
              properties:
                color: ...
        - properties:
            type:
              constant: ellipsoid
    
  • name (type: string) を追加する。
  • required: [type, data, attributes] を追加する。type, date, attributes は必須だが name はオプション(スキーマの変更が大変なので)。
  • label.yaml のスキーマを認識していることが分かるレベルの最小限のテストを追加する(おかしなラベルデータを渡したらエラーになることが確認できれば OK)

フロント側 (circus-web-ui)

新規開発項目

  • "+ Add Label" ボタンの左にラベルタイプを選択するドロップダウンボタンを追加し、5 種類のラベル型から選べるようにする。ラベルタイプセレクタの初期値は useLocalPreferences フックを使ってローカルマシンごとに保存されるようにする。
  • 見た目に関することでは色 (color) とアルファ (alhpa) のみを保存する。他の見た目に関するパラメータ(フレーム色や線の太さなど)はひとまず固定で変更不可とする。
  • 現在アクティブなラベルやツールがどれであれ、円・四角系の 4 種のラベルは、ハンドルのドラッグによるサイズ変更に反応する。
    • ただし cuboid と ellipsoid について、外接する枠線はそれらのラベルがアクティブの時のみ表示するようにするのが良さそう?
  • voxel 以外のラベルが選択されている場合、ブラシ・消しゴムツールなどの 3 次元塗り絵に関するツールを無効にする。
    • それらのツールが既に選択されている状態で voxel 以外のラベルを選択した場合は、ページングツールをアクティブにする。
  • 現在のラベル削除ボタン ("×") を "…" (glyphicon-option-horizontal) アイコンのボタンで置き換え、ドロップダウンを表示するようにする。そこに以下のメニュー項目を配置する。可能ならアイコン付きで。
    • "Rename": ラベルに名前を付ける。付けた名前は labels[].name として保存される。
    • "Remove": ラベルを削除する。現在の削除ボタンの挙動と同じ。
    • "Move up" / "Move down": ラベルをひとつ上または下に移動する(保存順と、ラベルが重なったときの描画のされ方に影響する)。
    • "Convert to rectangle" / "Convert to ellipse": 2D アノテーションのタイプを変換する。
    • "Convert to cuboid" / "Convert to ellipsoid": 3D アノテーションのタイプを変換する。
    • "Reveal in viewer": 該当ラベルが見える位置に axial/sagital/coronal をページングする。2D 系ラベルは sagital/coronal では表示されないが、それでも(見えない)中心のある場所にスライスをページングさせる。
  • 新規ラベルを作った際に "Voxels 1", "Ellipsoid 2" のような他と被らない name を作って付ける。Label コンポーネントを修正し、name がない場合はグレーで "Label" と表示し、ある場合はそれを表示するようにする。
  • 上記のラベルデータが正しく revision として保存されるようにする。voxel タイプは先にボクセルデータのバイナリ (data.voxels) を保存するための準備があるが、今回追加する 4 種類は座標などの数値・文字列データのみなので単純に API を呼び出して保存するだけでよいはず。

実装

  • フロントについても出来る範囲でコードを TypeScript 化する。(自分が触る部分のコードについて *.js*.ts にしてエラーを修正しながら少しずつ移行していく感じで OK)
  • React 周りについて
    • 基本的にすべて関数コンポーネントとフックを使い、クラスは使わない。
    • Redux はページ遷移しても保持すべきグローバルなステートに対して使う。基本的に今回は Redux に新たに配置すべきデータはないはず。もし必要になった場合 connect による高階コンポーネントではなく useSelector を使う。
    • ページ内・コンポーネントで完結するステート管理は useStateuseReduer を使う。
    • 高階コンポーネントもフックで置き換えられるならそうする。
    • イミュータビリティの補助のために Immer を導入予定。immutability-helper は今後使わない(そのうち削除する)。

その他

使用ツール

  • Jest: テストランナーは全リポジトリ共通で Jest 化している。push 前に Jest が走ることを確認。
  • prettier: VSCode などの設定で format on save にするのがお勧めだが手動で npm run prettier も可能。
  • eslint (npm run lint): VSCode などで自動化するのが良いが手動で npm run lint も可能。
  • tsc: TSC はコンパイラではなく linter のように使っているので手動で npx tsc して複数ファイルにまたがるインターフェースのエラーなどを検出する。毎コミットで厳密にエラーをゼロにしなくても良いが基本的にはエラーが一切出ない状態が標準なので定期的にチェック。