zudo-panel-designer docs
GitHub リポジトリ

検索したい単語を入力

いつでも検索バーを開ける

ツール

ツールは、キャンバス上のポインタ入力とキーボード入力を解釈するモジュールです。それぞれが自己登録された ToolModule拡張アーキテクチャを参照)であり、packages/app/src/editor/tools/ から検出されます。このページでは、組み込みの 5 つのツールと、すべてのツールが実装するイベントルーティングの契約を解説します。

組み込みツール

ツールショートカットカーソル概要
選択Vdefault本格的な複数選択ツール。クリック/マーキーでの選択、移動、回転、リサイズ、パスのアンカー/ハンドル編集ができる。
ペンPcrosshairベジェパスをアンカー単位で描く。閉じて塗りつぶし形状にするか、開いたストロークとして終える。
テキストTtextキャンバスをクリックして新しいテキストレイヤーを置き、選択ツールへ引き継ぐ。
パンHgrabドラッグでカメラをパンする。他のツールでも Space を押している間だけ一時的に呼び出せる。
ズームZzoom-inクリックでポインタ位置を基点にズームイン。Alt+クリックでズームアウト。

選択ツール(V

tools/select.tsx はリファレンス実装となるツールです。ツール契約のあらゆる部分を使い切っており、新しいツールを作るときにコピー元とするファイルです。これは本格的な 複数選択ベクター編集 ツールで、選択・移動・回転・リサイズ・パスアンカー編集のすべてがこの 1 つのファイルに収まっています。Help パネルの description はその要約版であり、ここではその全語彙を扱います。どのジェスチャーがどのレイヤー型に適用されるかは、後述のレイヤー適用可否マトリクスが定めます。

ポインタダウン時 には、次の固定された優先順位でつかむ対象を解決します(それぞれが次より優先されます)。現在の選択上のパスノード/ベジェハンドル(tryGrabNode — アンカーは 7px 以内、ハンドルは 6px 以内)→ 回転ノブ(tryGrabRotateHandle)→ 8 個のリサイズハンドルのいずれか(tryGrabResizeHandle)→ 複数選択の合成ボックスの角ハンドル(tryGrabMultiResizeHandle)→ それ以外は上から順のヒットテスト(topmostHit)で、選択・トグル、あるいは何もない場所ならマーキーを開始します。

選択する

  • クリック でレイヤーを選択します(同時に移動を開始します)。何もない場所をクリック すると選択解除します。

  • 何もないキャンバス上でドラッグ すると マーキー でラバーバンド選択します。その判定は含有ではなく 交差 です。(回転を考慮した)バウンディングボックスが矩形に 重なる レイヤーはすべて選択されます。境界はレンダラーの正規の layerBbox から得られるため、マーキーと画面上のクロムはピクセル単位で一致します。マーキーは 4px のドラッグしきい値を越えて初めて実体化するため、ただのクリックでマーキーがちらつくことはありません。

  • Shift+クリック は選択への追加(または選択からの除外)、Meta/Ctrl+クリック はちょうど 1 つのレイヤーのトグルです。マーキー中に修飾キーを押していると、マーキーのヒットがダウン時の選択と 和集合 になります。

  • ホバー はカーソル下のレイヤーを、控えめな実線の輪郭で縁取ります。破線の選択クロムより弱いので、「選択されるであろう」対象だと分かります。ポインタがキャンバスから離れると消えます。

  • パターンの正方形は最後にヒットテストされ、マーキーには決して加わりません。 パターンレイヤーは移動可能な正方形オブジェクトです(後述のパターンの正方形を参照)。クリックが当たるのは、ポインタの下にほかのレイヤーが何もないときだけで、マーキードラッグは重なっていても決してそれを拾いません——完全な二段階ルールはパターンの正方形を参照してください。

移動する

  • ドラッグ で選択中のレイヤーを移動します。複数選択のいずれかのメンバー をドラッグすると、選択全体が 1 つのジェスチャーとして移動します。移動は 0.1mm のグリッドにスナップし、同じ軸のガイドが範囲内にあればそれにスナップします。

  • Alt+ドラッグ は移動ではなく複製です。ドラッグがしきい値を越えた瞬間にクローンがサンプリングされ、元のレイヤーはそのままで、選択はクローンに移ります。しきい値を越えない Alt+クリック は何も複製しません。

  • ドラッグ中の Shift は移動を支配的な軸に拘束します。ライブに再評価されるため、離さずにドラッグの軸を切り替えられます。

  • 矢印キー で選択をナッジします(キーボードのフォールバックを参照)。

リサイズと回転

  • 単体リサイズshape または image を 1 つ選択した状態で、その 8 個のハンドルをドラッグします。回転した shape もリサイズできます(回転とリサイズの両方ができる唯一の型です)。ハンドルは回転した角に乗り、ドラッグはレイヤーのローカル座標系で resizeRotatedRect@zpd/core)により解決されます。軸に沿ったリサイズはグリッドとガイドにスナップしますが、回転したリサイズは浮動小数点の衛生管理のみです。回転した矩形の辺を個別にスナップすると、固定された角が目に見えて外れてしまうためです。

  • 回転shape または text レイヤーは、上辺の上に伸びるステムの先に丸いノブをまといます。これをドラッグすると bbox の中心を軸に回転します。Shift はジェスチャー開始時点を基準として 45° 刻みにスナップします。

  • 複数リサイズ — 2 つ以上のレイヤーを選択すると、合成ボックスは 角ハンドルのみ をまといます。その 1 つをドラッグすると、選択全体が対角の角を基点に 一様に スケールします。Alt はスケールの基点を中心に付け替えます。スケールは構造上つねに一様なので、ここでは Shift は意図的に何もしません(選択に含まれるパターンはそのまま動きません — 詳細は後述)。

パターンの正方形

pattern レイヤーは位置を持つ 正方形 オブジェクトです——mm 単位の xysize があり、パターンは (x,y)(x+size,y+size) の内側に描かれます。パネル全体を覆う暗黙のフィルではありません。移動については image レイヤーと同じように振る舞いますが、拾い上げ方には 1 つ意図的なひねりがあります。

  • デフォルトはパネルを覆う配置。 追加したばかりのパターン(あるいはパネルサイズが変わった直後のパターン)は、どんなアスペクト比でもパネル全体を覆うようにサイズと中心が決められます——一辺の長さはパネルの大きい方の寸法、patternCoverGeometry()@zpd/core)による配置です。パネルの HP を変更しても、これは自動的には再実行されないため、正方形はパネルを覆わなくなることがあります。インスペクタの Cover panel ボタン(インスペクタ → Patternを参照)が、必要なときに中心とサイズをパネルを覆う状態へ戻します。

  • 二段階のヒットテスト。 パターンの正方形がクリックに応じるのは、ポインタの下に ほかのレイヤーが一切ない ときだけです——z 順で上にも下にも重なる shape/text/path/image からクリックを奪うことは決してありません。また、マーキーの矩形が重なっていても 決してマーキーには加わりません未選択の パターンの正方形の上をドラッグすると、そこに何もない空のキャンバスがあるかのようにマーキーが描かれるため、パネルを覆うサイズの正方形が、その上にある何かをラバーバンド選択する邪魔をすることはありません。

  • 選択するにはやはりクリックが要ります。 ドラッグのしきい値を一度も越えない、未選択のパターンの正方形へのプレス→リリースは、ほかのレイヤーと同じく(トグル)選択します——上記のマーキー除外が変えるのは ドラッグ の挙動だけで、クリック の挙動は変わりません。

  • 選択されたパターンはほかのレイヤーと同じようにドラッグできます。 (そのクリック、またはレイヤーリストから)一度選択されると、次のドラッグはそれを 移動 させます——グリッドスナップ、ガイドスナップ、複数選択の一部としてのドラッグも、ほかと同じです。ただし、パターンの正方形にはリサイズ/回転ハンドルがありません。size を変えるには、代わりにプロパティパネルCover panel リセットを使います。

  • 複数リサイズ・回転・整列/分布からは除外されます。 パターンの正方形は複数選択の一様スケール(前述)の影響を受けず、rotation フィールドを持たず、整列と分布からも除外されます——このページの他の箇所と同じ「グループの計算が働きかけられる独立したリサイズ可能な矩形がない」という理由です。

  • 矢印キーでも動きます。 選択のナッジ(後述)は、パターンの正方形の xy もほかの移動可能なメンバーと同じように平行移動します。ピン留めされてはいません。

  • パネル外の部分はゴースト表示されます。 パターンの正方形をパネルの外へ一部ドラッグすると、Show content outside the panel がオンの間、パネルの端からはみ出した部分がほかのレイヤーのはみ出しと同じように減光したゴーストとして描かれます——レンダリングとカメラ → パネル外のゴーストパスを参照。

  • コピー・カット・複製・ペーストはできますが、すべて選択の対象ではありません。 クリップボードは、選択されたパターンの正方形をコピー/カット/複製/ペーストについてはほかのレイヤーと同じように扱います。⌘/Ctrl+A のすべて選択だけが意図的にパターンをスキップします。「すべてを選択して」が背景のようなカバー正方形を巻き添えにしないためです。

パスアンカーを編集する

path を 1 つ選択した状態で、そのアンカーをドラッグして移動(グリッドスナップ)したり、ベジェハンドルをドラッグして曲線を作り直したりできます。ハンドルのドラッグ中に Alt を押すと対称が外れ、両側が独立して動きます。path にボックスリサイズがないのはこのためです。代わりにアンカーで形を作り直します。

ジェスチャーと履歴

ドラッグは ctx.replace() で変更をストリーミングし、undo エントリ(ctx.beginGesture())を開くのは 遅延して — 実際に変化がゼロでなくなったときだけです。純粋なクリックや、スナップ未満のぶれで実質的な変化がゼロになる場合は、履歴は変更されません。Alt+複製は、クローンの挿入そのものが実際の変更であるため、エントリを直ちに開きます。pointerUp / onDeactivate はどちらもすべてのドラッグ状態をクリアするため、ドラッグの途中でツールを切り替えても、古いジェスチャーが開いたまま残ることはありません。

クリップボードと整列/分布

これとは別に、選択駆動の操作がさらに 2 つ、独立したモジュールとして存在しますが、Select が保持しているのとまったく同じ選択に対して働きます。クリップボード⌘/Ctrl+C/X/D/A、およびペースト)と、整列と分布(サイドバーのパネル、またはコマンドパレットの chordless な Align コマンド)です。この 2 つはパターンの扱いについて、意図的に食い違っています。コピー/カット/複製/ペーストは、選択されたパターンの正方形をほかのレイヤーと同じように扱います(すべて選択だけがパターンをスキップします——前述のパターンの正方形を参照)。一方、整列と分布はパターンレイヤーを完全に除外します。これは、このページのレイヤー適用可否マトリクスが複数リサイズ/回転について定めているのと同じ適用可否のルールです。

ペンツール(P

tools/pen.tsx はベジェパスを 1 アンカーずつ組み立てます。

  • クリック でグリッドにスナップしたコーナーアンカーを追加します。

  • 直前に置いたアンカー上で クリックしてドラッグ すると、対称な hout / hin のベジェハンドルが引き出され、スムーズアンカーに変わります。

  • 最初のアンカーの近くをクリック すると(パスに 3 個以上のアンカーが必要)、Copper コンテナ内の塗りつぶし形状(fill 有効、ストロークなし)として閉じます。

  • Enter を押すと、代わりにパスを開いたまま終えます(ストロークのみ、塗りなし)。アンカーが 2 個以上必要です。

  • Esc で作成中のドラフトをキャンセルします。

この複数クリックからなるジェスチャーは、パスが完成するまで ctx.doc にはいっさい触れません。選択ツールのライブドラッグとは異なり、ドキュメント内に途中経過が発生しないため、完成時にはちょうど 1 回の ctx.commit()(1 つの undo エントリ)にまとまります。フローティングのヒントバー(ツール契約にはクロム用のスロットがないため、ツール自身がマウントする独立した React ツリー)が、利用できる操作とその有効/無効の状態を表示します。作成中のパスは、メインのレンダラーではなくツールの renderDraft フックで描画されます。

テキストツール(T

tools/text.tsx は意図的に最小のツールです。ポインタダウンでクリック位置の Silkscreen コンテナに TextLayer を作成し(デフォルトの内容は "TEXT"、サイズ 6mm)、コミットして選択し、直ちにアクティブなツールを select に戻します。こうすることで、置いたばかりのテキストをすぐにドラッグ・リサイズ・編集できるようになります。

パンツール(H / Space ドラッグ)

tools/pan.tsx はカメラの画面ピクセルのオフセットをドラッグで動かします。ツールを切り替えずに呼び出すこともできます。他のどのツールがアクティブでも Space を押している間は、Editor がポインタイベントを pan にルーティングします(後述の Space ドラッグのオーバーライド を参照)。これにより、たとえば作成中のペンパスを見失うことなく、編集の途中でパンできます。

ズームツール(Z

tools/zoom.tsx は固定倍率(ズームインは 1.5 倍、ズームアウトは 1/1.5 倍)で、camera.zoomAt によりクリック位置を基点にズームします。ポインタの下にある mm 座標の点はその場に留まります。Alt+クリックではズームインの代わりにズームアウトします。

レイヤー適用可否マトリクス

選択ツールのジェスチャーは、汎用のベクターエディタよりも狭い、zpd の実際のドキュメントモデルを基準に定義されています。すべてのジェスチャーがすべてのレイヤー型に適用されるわけではありません。

レイヤー型キャンバスのクリックキャンバスのマーキー移動 / ナッジ単体リサイズ回転複数リサイズ(一様)
shape可(回転したものも含む — 唯一そうできる型)
text不可(独立した幅/高さがない)可(sizeMm をスケール)
path不可(代わりにアンカーを編集)不可(rotation フィールドがない)可(点とハンドルをスケール)
image可(決して回転しない)不可(rotation フィールドがない)
pattern可、ただし最後(二段階 — 後述)不可不可(ハンドルではなくインスペクタのフィールドでリサイズ)不可(rotation フィールドがない)不可
  • パターンはクリックで選択できますが、マーキーでは決して選択できません。 pattern レイヤーの xysize の正方形は、ほかのすべてのレイヤー型の あとで ヒットテストされます——クリックが当たるのは、ポインタの下にほかに何もないときだけです——そしてマーキー/ラバーバンド選択からは完全に除外されるため、パネルを覆うサイズの正方形があらゆる矩形ドラッグを飲み込んでしまうことはありません。一度選択すれば image と同じように移動/ナッジできます。リサイズ/回転ハンドルはありませんが、インスペクタの xysize フィールド(または Cover panel リセット)はあります。完全な操作ルールは、前述の選択ツール → パターンの正方形を参照してください。

  • 回転は単一選択かつ shape/text のみです。 その 2 つの型だけが rotation フィールドを持つため、回転ノブが提供されるのもそれらだけです。path/image には設定する回転がなく、クロムがそれを勝手に作り出してはいけません。複数選択全体の回転も path/image では表現できないため、グループ回転は存在しません。

  • 複数リサイズは一様スケール・角ハンドルのみ・Shift は無効です。 回転した 矩形の非一様スケールは x/y/width/height/rotation モデルでは表現できず(せん断が必要)、text には独立した幅/高さがありません(sizeMm のみ)。そのため、グループのスケールは一様にしかなりません。これは好みではなく、モデルによって強制されるスコープの縮小です。

  • shape は、回転と単体リサイズの両方ができる唯一の型です。 ImageLayer にはそもそも rotation フィールドがなく、text には独立した幅/高さがありません。ですから、回転を考慮したリサイズの計算には、実際の利用者がちょうど 1 つ — 回転した shape — しかいません。

ツールを知る手がかり: ツールチップと Help パネル

ドキュメントを開かなくてもツールの役割が分かるように、2 つの表面が用意されています。どちらも ToolModule のデータからそのまま供給されます。

  • ツールバーのツールチップ。 各ツールバーボタン(components/toolbar.tsxChromeButton)は、ツールの labelshortcut から組み立てたホバーツールチップを表示します(例: Select (V)Pen (P))。このツールチップのテキストはボタンの aria-label でもあるため、ボタンのアクセシブルネームにもなっています。ホバー後に短い遅延を置いて現れ、また(プレーンなフォーカスではなく):focus-visible を基準にしているため、クリックしてボタンにフォーカスが残っても、ツールチップが開いたまま張り付くことはありません。追加アクションのボタンも、その label から同じ扱いを受けます(こちらはショートカットを持ちません)。

  • サイドバーの Help パネル。 固定された Help フッター(components/help-panel.tsx)は、現在アクティブなツールの名前、ショートカットのバッジ、そしてより長い description を表示します。description は、そのツールが何をするか、主要なポインタ操作、そしてショートカットを説明する 2〜4 文です。組み込みの各ツールは、任意項目の ToolModule.description フィールドでこれを提供します(拡張アーキテクチャを参照)。省略したツールは、汎用的な「No description available」の行にフォールバックします。パネルは activeToolId に追従するため、Space を押して一時的にパンしても、表示される説明が入れ替わることはありません。

ポインタ/キーボードイベントの契約

Editor シェル(Editor.tsx)は、入力のルーティングについてただ 1 つのルールを持ちます。アクティブなツールに最初の受け取り権があり、その後にアプリレベルのフォールバックが動く というものです。

ポインタイベント

キャンバス上のすべてのポインタイベントは ToolPointerEvent(キャンバス基準の画面ピクセル、それに対応するドキュメントの mm、button / buttons、修飾キー、pointerId)に正規化され、その時点で 有効 なツールの onPointerDown / onPointerMove / onPointerUp / onDoubleClick に渡されます。

Space ドラッグのオーバーライド

有効なツールは通常 activeToolId ですが、Space が押されている間は、何がアクティブであるかにかかわらず強制的に 'pan' になります。これにより、activeToolId 自体を変えずに、どのツールからでも一時的なオーバーライドとしてパンが使えます。Space を離す(あるいはドラッグ中に Space が離れたことを捉える buttons === 0 の移動)と、直前にアクティブだったツールに戻ります。

キーボードイベント

keydown の際、シェルはまずアクティブなツールの onKeyDown(e, ctx) を呼び出します。それが true を返した場合に限り、ルーティングはそこで止まります。ツールがそのキーを要求したことになり、アプリレベルのフォールバックは動きません。これが、シェル側にすべてのツールが編集しなければならない共通のキーボード用 switch を持たせることなく、ペンがドラフトの確定/キャンセルのために Enter/Esc を所有できる仕組みです。

ツールが true を返さなかった場合、シェルは次の順でフォールバックを実行します。

  1. ⌘/Ctrl+Z(undo) / ⌘/Ctrl+Shift+Z(redo)。

  2. 単一キーのツールショートカット(V / P / T / H / Z、大文字小文字は区別しない)。修飾キーが押されていないときにのみマッチするため、undo/redo の判定より先に発火することはありません。

  3. Esc — 選択解除。

  4. Delete / Backspace — 現在の選択を削除(選択中のすべてのレイヤーを、1 つの undo エントリとして)。

  5. 矢印キー — 選択を 0.1mm、Shift を押していれば 1mm 移動(ナッジ)。移動可能なメンバーはすべて同じデルタを受け取り、選択は剛体として平行移動します。shapetextimagepattern レイヤーはすべて自身の xy の原点を介して平行移動し(パターンの正方形も image と同じように動きます——前述のパターンの正方形を参照)、path レイヤーは点集合全体を平行移動します。

<input> / <textarea> / <select> にフォーカスがある間(レイヤー名の変更フィールドやインスペクタの数値フィールドなど)は、キーボード入力はグローバルに無視されます。そのため、テキストボックスに "V" と入力してもツールが切り替わることはありません。

Tip

新しいツールを作るとき、シェルのフォールバックより先にキーを横取りする 唯一 の方法は onKeyDowntrue を返すことです。編集すべき別の優先度リストは存在しません。ツールの追加を参照してください。