プラグイン
plugin は、UI 要素、キーバインド、ライフサイクル フックの自己完結型バンドルです。 コアがその存在を認識する必要なく、それ自体をグラフにインストールします。登録する 宣言的または命令的に:
import { Pivotick, minimap } from 'pivotick'
// declaratively
const graph = new Pivotick(container, data, { plugins: [minimap()] })
// …or at any point later
graph.use(minimap({ position: 'bottom-left' }))グラフがライブになった後にインストールされたプラグインは、現在のライフサイクル フェーズに追いつきます。 したがって、「遅すぎる」ということはありません。登録されているものはすべて UI とともに破棄されます。
プラグインの形状
import type { PivotickPlugin } from 'pivotick'
const myPlugin: PivotickPlugin = {
name: 'my-plugin', // used for de-duplication and logging
install(ctx) { /* … */ }, // called once
}同じ name を 2 回インストールすると警告が表示され、重複したものはスキップされるため、プラグインは pluginsにリストされ、重複せずにgraph.useを通じて再適用されます。
installが渡されるもの
ctx は {@link PluginContext} です:
| メンバー | 何のためにあるのか |
|---|---|
graph | ライブ Graph — ノード、エッジ、データ イベント バス、queryEngine |
ui | UIManager — オプション、通知、モードストア |
layout | DOM スキャフォールド、live を読み取ります (決してスナップショットではありません)。 layout.canvas はキャンバスにドッキングされたクロムの場所です |
addElement(element, slot?) | UIComponent をライフサイクルに入れ、slot にマウントします |
addPanel(panel) / removePanel(id) / refreshPanel(id?) | サイドバー パネル — UI.extraPanels と同じドア |
addDockTab(tab) / removeDockTab(id) | ドック下部のペイン - 内蔵テーブルが通過するのと同じドア |
addRailMode(mode) / removeRailMode(id) | 左側のレールの選択 / 作成 / 表示 / 物理演算の横にあるモード |
addTopBarAction(action) / removeTopBarAction(id) | 上のバーの錠剤 — UI.topBar.actions と同じドア |
addPivot(definition) | 実行可能なエンリッチメント — ピボットとエンリッチメントを参照 |
onPhase(phase, cb) | フック afterMount / graphReady / destroy;購読解除を返します |
addKeybinding(binding) | UI が破棄されると削除されるショートカット |
keyManager | キーバインド レジストリ、さらに複雑なものについては |
バインディングの key は修飾子、次にキーであり、+: 'Shift+K'、'Ctrl+F'、が結合されています。 'ArrowUp'。その中に修飾子を Ctrl、Meta (macOS でコマンド)、Shift、Alt として書き込みます。 順序を指定し、Mod を使用して Ctrl または Meta のいずれかに一致させます。これがショートカットの意味です。 両方のプラットフォームで動作することを望んでいます。キー自体は KeyboardEvent.key なので、 大文字と小文字が区別され、Shift キーを押すと変更されます。アンドゥ ペアの 2 つの半分は 'Mod+z' で、 'Mod+Shift+Z'。テキストフィールドにフォーカスがある間はバインディングは起動しません。
どの layout スロットが存在するかはモードによって異なります: canvas と notification は常に、 static、mainheader / modal / slidePanel / を除くすべてのモードで graphnavigation full、light、sidebarのmoderail / toolpanel / flyout / legend fullのみ。スロットをキャッシュするのではなく、必要なときに読み取ります。
UI要素の提供
UIComponent を延長すると、ライフサイクルが自動的に推進されます (分解も含む)。 track / listen / trackInteraction を通じて登録されたもの:
import { UIComponent } from 'pivotick'
class Watermark extends UIComponent {
onMount(slot) {
this.element = document.createElement('div')
this.element.textContent = 'draft'
slot?.appendChild(this.element)
}
onGraphReady() {
// `listen` and `trackInteraction` unsubscribe themselves on destroy
this.trackInteraction('canvasZoom', () => this.reposition())
}
onDestroy() {
this.element?.remove()
}
}
const watermark: PivotickPlugin = {
name: 'watermark',
install: (ctx) => ctx.addElement(new Watermark(ctx.ui), ctx.layout?.canvas),
}4 つのフェーズは、mount(slot) → afterMount() → graphReady() → destroy() です。 graphReady はシミュレーションが安定すると起動するため、その後 秒 かかる場合があります 大きなグラフにマウント — 画面上に表示されるべきものはすべてすぐに属します onMount / onAfterMount (graph.renderer が必要な場合はフレームを延期します。これは UI の後に構築されます)。
プラグインで拡張する ギャラリーをご覧ください ライブの完全な例のカード。
ドックペインの提供
ctx.addDockTab は、下のドック のデータの横にペインを配置します テーブル。ドックは領域、つまり高さ、分割線、折り目、およびストリップを所有します。 ペインに名前を付けます。ペインはその中にあるものを所有します。
const auditLog: PivotickPlugin = {
name: 'auditLog',
install: (ctx) => ctx.addDockTab({
label: 'Audit',
render: () => buildPane(ctx.graph), // once, on first activation
toolbar: () => [clearButton], // on every activation
onActivate: () => resumePainting(),
onDeactivate: () => stopPainting(),
}),
}知っておく価値のある 4 つのこと:
- タブはペインであり、1 つのビューではありません。 ペインに独自のビューが複数ある場合、タブはペインです。 単一のドック タブのままで、
toolbarに独自のスイッチを描画し、呼び出しますhandle.refresh()で本体を変更します。これにより、renderが再度呼び出されます。まさにそれが、 データテーブルはNodes/Edgesに対応しており、ドックのストリップが平らにならない理由 別のペインの横にあるペインのビュー。ドックの背後で独自の DOM を切り替えると、 機能しません:renderが与えた要素を保持し、古いノードを再アタッチします。 次のアクティベーション。内側のスイッチをタブとしてではなく、セグメント化されたコントロールとして描画します - 外側のスイッチ レベルはすでにタブのように見えます。ストリップにはpvt-dock-views、それぞれにはpvt-dock-viewボタン (プラスactive) はパブリックなので、テーブルのスイッチのように見え、 どちらも言い直すことなくテーマを。 - 最初のペインでリージョンが構築されます。 プラグインがインストールされます。後 UI が構築されるため、タブ ドック自身のモード ゲートがその代わりに「はい」と答えるには、到着が常に遅すぎます。 登録するとドックが有効になり、プラグインが動作することになります。
UI.table: falseで、fullモード以外は何もオンにする必要はありません。 renderは、初めてペインが開かれたときに、遅延 で 1 回呼び出されます。要素は 保持され、後で再接続されるため、独自のスクロール位置が保持されます。toolbarは アクティブ化するたびに再構築されるため、コントロールはペインの現在の状態を読み取ることができます。onActivate/onDeactivateは、画面外 であることを示す唯一の信号です。 それらをどう扱うかはペインによって異なります。グラフの現在の関数であるコンテンツ 状態は非表示の間は動作を停止し、戻ったときに再導出することができます。これがテーブルの機能です。 そうです。何かを 見逃し にするコンテンツ (ライブバスを見ているペイン - イベントがなくなった) 一度起動すると) は動作を継続し、単に ペイント を停止してバックログをフラッシュする必要があります 戻ってきたら。フックについても好みのものはありません。
タブは UIComponent ではないため、ライフサイクル フェーズを開始するものはありません。ペインが graphReady が必要な場合は、UIComponent、addElement を押したまま、そこから addDockTab を呼び出します onMount — 上記の「UI 要素の提供」を参照してください。
ライブについては、「ドック ペインの追加」ギャラリー カードを参照してください。 完全な例 — データ テーブルの横に、独自の 2 つのビューを持つペイン。
レールモードへの貢献
左側のレールの 4 つのモード (選択、作成、表示、物理) が組み込まれています。その他すべて はあなたのものです: addRailMode 独自のモードを** ディバイダ** の下に置き、その後ろに順序付けます orderまでに同業者の間で。
ポインター モード は、コンテキスト ツール パネルを所有します。 tools を宣言するとパネルが引きます それらは、選択と作成が描画される方法、アーミング、有効/無効状態を伴います そして崩壊はあなたのために処理されます:
const explore = {
name: 'explore-mode',
install(ctx) {
const selected = () => ctx.graph.renderer.getGraphInteraction().getSelectedNode()?.node
ctx.addRailMode({
id: 'explore',
label: 'Explore',
icon: compassSvg,
shortcut: 'E',
tools: [
{ id: 'expand', label: 'Expand neighbours', icon: plusSvg, kind: 'action',
enabled: () => !!selected(),
run: () => expandFrom(ctx.graph, selected()) },
{ id: 'walk', label: 'Path walk', icon: pathSvg, kind: 'toggle',
run: (armed) => armPathWalk(ctx.graph, armed) },
],
onExit: () => armPathWalk(ctx.graph, false),
})
},
}
new Pivotick(el, data, { plugins: [explore] })ツールの kind がその動作を決定します。 'action' は 1 回実行され、モードはそのままになります でした。 'toggle' モーダル ツールを準備します。パネルが折りたたまれ、** レール ボタンが次のように変形します。 そのツール自体のアイコンとラベル**は、Select のスロットが Lasso になるのとまったく同じです。あ 'default' モードが依存するツールです。 defaultTool で名前を付けると、トグルが元に戻ります。
tools は 関数 である場合もあり、パネルが描画されるたびに再読み込みされます。 行はグレー表示されるだけでなく、選択された内容によって異なります。何でも一列に 表現できない場合、render() は行の下 に追加された要素を返します。
ctx.addRailMode({
id: 'explore', label: 'Explore', icon: compassSvg,
tools: () => toolsFor(ctx.graph.renderer.getGraphInteraction().getSelectedNode()),
render: () => depthSlider(),
})フライアウト モード では、代わりに [ビュー] や [物理] などの設定オーバーレイが開きます。サブクラス Flyout そして工場にaddRailMode を渡す — コアがパネルを取り付け、正確に開きます。 あなたのモードはアクティブであり、モードとともにそれを取り除きます。
import { Pivotick, Flyout } from 'pivotick'
class EnrichFlyout extends Flyout {
mode = 'enrich' // must match the definition's id
template() { return this.headerRow(sparklesSvg, 'Enrich') + this.toggleRow('auto', gearSvg, 'Auto-enrich', 'Enrich on load') }
wire() { this.wireToggle('auto', () => toggleAuto(), () => isAuto()) }
}
ctx.addRailMode({
id: 'enrich', label: 'Enrich', icon: sparklesSvg,
kind: 'flyout',
flyout: (ui) => new EnrichFlyout(ui),
})モードは相互に排他的であるため、View と Physics は無料で除外されます — 1 つのストア、1 つのモード アクティブモード。
知っておく価値のある 3 つのこと:
iconは生の SVG 文字列で、HTML として挿入され、サニタイズされていません。 から取得される必要があります。 あなたが信頼できる情報源。 CSS のサイズは、レール上で 20 ピクセル、パネル内で 18 ピクセルです。shortcutは通常のキーバインドルールに従います: すでに別のキーを要求しています 所有者は、モードが削除されるまで、警告とともにそれをシャドウします。onExitは武装を解除する場所です。 モードが終了したとき、またはモードが解除されたときに実行されます。 アクティブの間 - この場合、レールは選択に戻ります。 UI では実行されません** 分解;プラグインがすでに追跡しているディスポーザーがそれをカバーします。
addRailMode はディスポーザを返し、すべてのモードで動作します。ボタンは次の場所にのみ描画されます。 レールがあります。これはfullとlightを意味します。
ビューポートの駆動
ミニマップ、概要、「ジャンプ」コントロールなど、グラフ内を移動するものはすべて、 2 つのレンダラー メソッド:
// The extent of everything drawn, in graph coordinates (null when there's nothing).
const bounds = graph.renderer.getContentBounds()
// Put a graph-space point in the middle of the canvas.
graph.renderer.setViewport({ x: 120, y: -40 })
graph.renderer.setViewport({ x: 0, y: 0, scale: 1.5, animate: true })setViewport は、スケールを渡さない限りスケールをそのままにするため、次のプリミティブになります。 パンニング。現在のビューが の位置を読み取るには、キャンバスの角を反転するのではなく、 ズーム変換に到達します。これはレンダラーに依存しません。
const rect = graph.UIManager.layout.canvas.getBoundingClientRect()
const topLeft = graph.renderer.screenToGraphCoordinates(rect.left, rect.top)
const bottomRight = graph.renderer.screenToGraphCoordinates(rect.right, rect.bottom)fitAndCenter() (すべてに適合)、zoomIn() / zoomOut()、 focusElement(nodeOrEdge) は、一般的なケースのショートカットのままです。
ミニマップ
ファーストパーティのプラグイン: キャンバスの隅にドッキングされたグラフ全体のキャッシュされた概要。 画面上にあるものを示す四角形。 クリック でビューが中央に再配置されます。 長方形をドラッグしてパンします。面の隅にある非常に小さなトグルで折りたたむことができます そのボタンだけを選択して、元に戻します。
full モードはあなたのために 1 つをマウントします — これはヘッダーと同様、そのモードのクロムの一部です。 サイドバーとモードレール。他のモードでは、それはあなた次第です。
// full mode: already there, nothing to install
new Pivotick(container, data, { UI: { mode: 'full' } })
// any other mode: ask for it, with `UI.minimap` …
new Pivotick(container, data, { UI: { mode: 'light', minimap: true } })
// … or as the plugin it is
import { Pivotick, minimap } from 'pivotick'
new Pivotick(container, data, { UI: { mode: 'light' }, plugins: [minimap()] })UI.minimap はプラグインと同じ {@link MinimapOptions} を受け取ります。 { minimap: { position: 'top-left' } } は、フル モードがもたらす 1 つの設定を行います。 UI.minimap: false はそれを抑制します。自分の minimap() を plugins にパスすることも勝ちです — フル モードは 2 番目のモードをマウントするのではなく脇に置いておきます。 plugins: [minimap({ … })] は以前とまったく同じように動作し続けます。
<!-- browser build: it hangs off the global, like Node and Edge -->
<script>new Pivotick(el, data, { plugins: [Pivotick.minimap()] })</script>オプション
| オプション | 種類 | デフォルト | 何をするのか |
|---|---|---|---|
position | 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' | 'bottom-right' | どのコーナーにドッキングするか。'bottom-right' は、full モードで内蔵クロムが解放される唯一のコーナーです。 |
width | number | 200 | 幅は CSS ピクセル単位、境界線を含みます。 |
height | number | 派生した | 高さ (CSS ピクセル単位)。省略しましたが、キャンバスのアスペクト比 (70 ~ 400px に固定) に従い、長方形は実際のビューポートの形状を維持します。 |
collapsed | boolean | 'auto' | false、または full モード マウントの場合は 'auto' | どの状態で開くか。トグルは常に存在します。ここからが始まりです。 'auto' については、邪魔にならないようにする を参照してください。 |
詳細レベルと 再描画の頻度がグラフに適応します。
それが描くもの
ノードはレンダラーが指定した色のドットであり、エッジはその下のヘアラインです。 メモ(独自のサイズを持つ唯一のコンテンツ)は、半透明として一定の縮尺で描画されます。 キャンバス上のノード上にブロックを独自の色で配置します。隠れたものと フィルタリングされたコンテンツは除外されます。数千ノードを超えると、画像は密度が高くなります 代わりにマップ (ノードごとに 1 つのスタンプ、エッジなし) を使用すると、何万ものデータよりも読み取りやすくなります。 重なり合うドット。ノートはどちらの方法でも描画されます。すべてキャッシュされ、次の場合にのみ再ラスタライズされます。 絵が本当に変わりました - ノードがドロップされ、ノートが移動され、レイアウトが固定され、フィルターが追加されました 適用されるため、グラフがどんなに大きくてもパンとズームは自由に行えます。
HTML カード (shape: 'none' の html) にはミニマップが読み取ることができる色がないため、そのドットは シェイプである最小の描画の色、つまり基本スタイル、または tiers ではそのような層が初めてです。何もない場合、または transparent 色がある場合、ドットは描画されます。 ミニマップ独自のインク (--pvt-minimap-ink)。ドットはノードがカバーする範囲に合わせてサイズ設定されるため、 カードまたは renderNode ノードは、size サイズのドットではなく、カード サイズのドットを取得します。
邪魔にならないようにする
要求したミニマップは、配置した場所に残ります。 1 つの full モードがあなたに代わってマウントします は要求されていないため、collapsed: 'auto' が開き、キャンバスが考慮されます。 キャンバスが少なくともミニマップの幅と高さ以上ある間は開いたままになり、自動的に折りたたまれます。 その下のトグルに移動します。それ以来、キャンバスを追い続けます - 折り畳まれます サイドバーが上に開いたり、ウィンドウが狭くなったりすると、部屋が狭くなったときに戻ってきます。
誰かがそれを折りたたむか、トグルまたはスイッチによって元に戻す瞬間 setCollapsed() — それは停止します: 明示的な選択は固定され、その後のサイズ変更のオーバーライドは行われません それ。最初から 'auto' をオプトアウトするには、明示的な collapsed: true / false を渡します。
トグルの矢印は、ミニマップがドッキングされる隅、つまり折り畳まれる方向を指します。 離れて、折りたたむと反転します。折り畳むと、何も描かれません。 長方形なので、邪魔にならない間は費用はかかりません。それを開くと再ラスタライズされます それまでにキャンバスがどのようになっていても構いません。 setCollapsed(boolean) と isCollapsed() Minimap インスタンスは、コードから同じことを実行します。
何を描くのか、そしてそれにかかる費用は
ミニマップは、コンテンツ境界を現在のビューポートとともにマップします。 長方形は常に表示され、正確なサイズになります。ズームアウトするとグラフが縮小します。 長方形がフレームから滑り落ちるのではなく、フレームの内側に収まります。
グラフをオフスクリーンのビットマップに保持し、画像が表示されたときにのみ再ラスタライズします。 実際に変更された場合: データ変更時、フィルタがノードを非表示または復元したとき、ノードが ドラッグ後、レイアウトが安定するまでの 10 回のシミュレーション ティックごと、およびサイズ変更時にドロップされます。 パンとズームにより 1 つの画像と 1 つの長方形 が再描画されるため、移動コストは同じです グラフにノードが 20 個あるのか、50,000 個あるのか。
意図的に、サイズに応じてディテールが劣化します。
| グラフ | として描かれます |
|---|---|
| ≤ 1500 ノード | レンダラーが解決した色のノードごとのドット、およびヘアライン エッジ (4000 エッジを超えた部分) |
| 1500 個を超えるノード | 単一インク内のノードごとに 1 つのスタンプ、アルファの累積 - 密な領域は密度マップとして読み取られ、ノードごとのスタイルはまったく解決されません |
full、light、viewer モードで動作し、full がそれをマウントします。 聞かれなくても。 static では、インタラクションがないことが約束されていますが、マウントされておらず、 そこにインストールすると警告が表示されます。
実際のギャラリー カードについては、ミニマップ ギャラリー カードをご覧ください。