react-draggable使った話

研究で色々あってreactを使う判断をしました。

研究ではAndroidのセンサログ情報やら開発者が実装した行動認識を行うクラスを可視化して想定通りに行動認識アルゴリズムが動作しているかの調査や、そもそもどういったセンサデータが用いれるかを調べられるWebベースのデバッグツールを作っていました。 本デバッグツールでは様々なセンサデータを可視化することとなるのですが、その際には、ツール利用者が自由にグラフ配置できるような仕組みが求められるかと思います。 なにぶん、昨今Androidのセンサは増えていますし、行動認識と一口に言っても様々なパラメータや計算過程の値が跋扈するわけです、大量のグラフを並べたいように並べる仕組みが必要かと思います。

そこで mzabriskie/react-draggable: React draggable component というライブラリを使いました。 名前の通りドラッグ可能にする便利コンポーネントです。

インストール方法と設定については公式READMEをご覧ください。

ドラッグ可能にする

ドラッグ可能にしたい要素を Draggable コンポーネントで囲います。

<Draggable>
  <div>
    ドラッグできるよ
  </div>
</Draggable>

これで div 要素はドラッグ可能になりました。簡単ですね。Reactのコンポーネントでも同様にできます。

ウインドウっぽくしたい

現状の実装だと要素内のどこをドラッグしてもドラッグされます。できればウインドウのUIっぽく上の方だけクリックしたら移動みたいな実装にしたいですね。 それには handle 属性を利用すれば良いです。 handle で指定したclassの要素をドラッグすることで移動ができるようになります。

<Draggable handle="handle">
  <div className="handle">
    ここをドラッグ!
  </div>
  こっちではドラッグできないよ
</Draggable>

位置を保存したい

今回のツールはブラウザベースで開発しているのですがリロードのたびに配置が変わるのは好ましくありません。 そこで位置を保存して再読込の際にはロードされるようにしましょう。

// constructorなどで実行
this.state = {
  componentPosition: {
    x: parseInt(localStorage.getItem(`position_x`), 10) || 0,
    y: parseInt(localStorage.getItem(`position_y`), 10) || 0
  }
};

function onDrag(e, position){
  const {x, y} = position;
  this.setState({
    position: {x, y}
  });
}

function onStop(e, position){
  const {x, y} = position;

  localStorage.setItem("position_x", x);
  localStorage.setItem("position_y", y)
}

<Draggable handle="handle" position={this.state.positon} onDrag={onDrag} onStop={onStop}>
  <div className="handle">
    ここをドラッグ!
  </div>
  こっちではドラッグできないよ
</Draggable>

こうすると、初回は position 属性によって位置が決められる。ドラッグ時には onDrag が呼び出され、 state.position が更新される。 ドラッグ停止時には onStop が呼び出され localStorage への保存が行われる。