図形をたくさん置くと描画に必要な領域が広くなり、スクロールが必要になります。
横スクロールは操作し辛いので、手のひらツールがあるとちょっと便利になります。
実際の動作
全体のソースはこちらにあります
実装内容のポイント説明
ドラッグ&ドロップの挙動を作る
ドラッグ&ドロップをしたときの動作を定義するために、Paperのblank:pointerdown
イベントとblank:pointermove
イベントを利用します。
pointerdown
時の座標を取っておき、pointermove
後の座標との差分をスクロールさせる、という処理内容になります。
また、今回はblank:
のプレフィックスをつけることで、描画済みのElement上ではスクロールの処理が流れないようにしています。描画した要素の移動をさせたい場合はこのような方法で不要なスクロールを回避させます。
// カーソルクリック時の座標を記録する
paper.on('blank:pointerdown', (evt) => {
evt.data = { clientX: evt.clientX, clientY: evt.clientY };
});
// カーソル位置の移動時にスクロールする
paper.on('blank:pointermove', (evt) => {
window.scrollBy( (evt.data.clientX - evt.clientX), (evt.data.clientY - evt.clientY));
// 差分を取る基準をスクロール後の位置で更新
evt.data.clientX = evt.clientX;
evt.data.clientY = evt.clientY;
});
Link上でもドラッグアンドドロップできるようにする
Elementをドラッグ&ドロップしたときはElementの移動を行いますが、Linkについては特に移動せず、他の背景と同様にドラッグ&ドロップでスクロールさせたいとします。そういった場合は、Linkのマウスイベントをスルーさせるpointer-events="none"
を設定すると回避させることができます。
今回のサンプルではLinkが1つしかないため、 link.attr('root/pointerEvents', 'none');
と書くことでも実現できますが、Linkがたくさんある場合に全てのLinkに対してattr
メソッドを実行していくのは効率が悪いです。
こういう場合、pointer-events="none"
を設定済みのカスタム要素を予め作っておき、それをLinkとして使っていくのが効率的です。
// クリックイベントをスルーするカスタムLink
joint.shapes.standard.Link.define(
'example.SimpleLink',
{
attrs: {
root: {
pointerEvents: 'none'
}
}
}
);
const link = new joint.shapes.example.SimpleLink();
link.source(rectangle1);
link.target(rectangle2);
CSSでカーソルを手のひらにする
手のひらツール感を出すためにはカーソルの表示が重要です。
JointJSではなくCSSの設定になりますが、以下の設定を行ってカーソルの表示を制御します。
/* 通常は手のひらを開いた状態 */
#myholder{
cursor: grab;
}
/* ドラッグ中は手のひらを掴んだ状態 */
#myholder:active {
cursor: grabbing;
}
まとめ
今回は、今までに紹介した機能を応用して手のひらツールを実装する方法を紹介しました。
図形描画系のツールではおなじみの機能となっていますので、JointJSで作成する図形に必要になってくることもあると思います(少なくとも私の現場では必要になりました)。
※この記事は JointJS Advent Calendar 2023 の記事です。他の記事を読む場合はカレンダーのページを参照してください。