フィルタリング可能な凡例
色分けされたグラフにはキーが必要です。キーがあれば、そのキーが最も高速になります。 UI でフィルターします。 UI.legend は、キャンバスの隅にスウォッチ、ラベル、および カテゴリごとのノード数が表示され、行をクリックするとそのカテゴリが非表示になります。を指差す 行は最初にキャンバス上のノードを点灯し、残りのノードを暗くします。そのため、カテゴリは次のようになります。 電源が切れる前に発見されました。
1 行で設定します: legend: { key: 'type' }。図書館は特徴的なものを集めています data.type の値、** レンダラーがすでにカラーから各スウォッチを読み取ります ** が解決され、その背後にあるノードをカウントします。多くの場合、行がまったく必要ありません。 render.nodeTypeAccessor を宣言すると、そのディメンションが完了すると凡例が自動的に表示されます。 色を説明するために示されています (凡例を参照)。このカード ノブを表示するブロックを宣言します。この伝説は純粋に説明的なものです。 ここでの色は、オプションの ColorPaletteMapper から取得されます。 カテゴリごとに色分け、および凡例 決して割り当てません。パレットを変更すると、凡例が続きます。
行をクリックすると graph.queryEngine でフィルタリングされるため、same フィルタリングとなります。 ヘッダーの Graph Filters パネルがそれを行います。このカードは以下のtype ファセットを宣言します 凡例独自のキーにより、2 つが 1 つのコントロールになります: api をオフにします。 凡例では、パネル (ファネル、または Shift+K) を開き、その サービス タイプ を複数選択します すでに落としてしまった。 resetFilters() — またはパネルの リセット — 再点灯 すべての行。
type がまったく含まれていないノードは行を取得せず、凡例によってそれらが非表示になることはありません。 リストされているカテゴリにのみ作用します。
1 つの鍵が物語全体を左右することはほとんどありません。 一度に 2 つのキー ごとにタイトル付きセクションをスタックします 同じドッキングされたカード内のディメンション — 以下の タイプ + ゾーン を押します: type は運転を続けます パネルのファセット、zone は独自のセクションを取得し、2 つのフィルター ** と** したがって、api と dmz を非表示にすると、どちらでもないものが残ります。 zone は独自の宣言をします スウォッチの色。キャンバスはその色とサンプルされたスウォッチで type をエンコードするためです。 zone は単なる偶然でしょう。
セクションでは、ノードの代わりに エッジ をキーにすることもできます — scope: 'edge' はグラフのリストを示します リレーションは線見本で種類が指定され、レイヤーをクリックするとレイヤー全体が非表示になります。それには必要なもの エッジには種類があるので、 エッジレイヤー カード。
セクションヘッダー: すべて表示、反転、および折り畳まれる山形 そのセクションをタイトルに合わせて — alt キーを押しながら 山形をクリックして、各セクションを折りたたむ セクション。 カーソルを行に移動すると、キャンバス上のそのカテゴリが点灯します。 alt キーを押しながら 1 をクリックすると、そのカテゴリのみが表示されます。トグルは legendToggle を介してコンソールにログされ、そのセクションに名前が付けられます。
// import { ColorPaletteMapper } from 'pivotick'
// The consumer owns the colours — here a palette mapper over `type`, exactly as in
// the "Color by category" card. The legend never assigns a colour.
const palette = new ColorPaletteMapper('okabe-ito')
// `key` is all a legend needs: it collects the distinct values of `data.type`,
// reads each swatch out of the colour the renderer resolved, counts the nodes
// behind it, and makes every row a filter toggle.
//
// You can also leave `UI.legend` out entirely: with a `render.nodeTypeAccessor`
// declared, a legend appears by itself as soon as that dimension is shown to
// explain the colours. `UI.legend: false` opts out.
const legend = {
key: 'type',
title: 'Service type',
// Every one of these is a default — spelled out here to show the knobs.
position: 'bottom-left',
showCounts: true,
collapsible: true,
filterable: true,
maxVisibleEntries: 12
}const options = {
UI: {
// The legend is chrome: `full` and `light` modes have it, `viewer` and
// `static` don't. Full mode also ships the Graph Filters panel, which the
// legend below shares a filter with.
mode: 'full',
// Off: `full` mode brings a minimap and the data dock, and this card is about
// neither (see the Minimap and Data table cards for those).
minimap: false,
table: false,
legend,
// Declaring a facet under the *same key* the legend uses makes the two one
// control: toggle a swatch and the panel's multiselect follows, and the
// other way round. (The trade-off: an empty multiselect means "no
// constraint" to the panel, so the legend won't let you switch off the last
// remaining category.)
filter: {
facets: [
{
key: 'type', label: 'Service type', type: 'multiselect',
options: (graph) => [...new Set(graph.getNodes().map((node) => node.getData().type))]
.sort().map((value) => ({ label: value, value }))
}
]
}
},
render: {
defaultNodeStyle: {
size: 15,
strokeColor: '#ffffff',
textColor: '#334155',
text: (node) => node.getData()?.name,
textVerticalShift: -1.8,
color: (node) => palette.getColor(node.getData()?.type)
}
}
}// The legend announces every toggle on the data bus, so the choice can be
// persisted, mirrored elsewhere, or logged.
function watchLegend(graph) {
graph.on('legendToggle', ({ section, hidden, visible }) => {
console.log(`legend [${section}]: showing ${visible.join(', ') || '(none)'} — hiding ${hidden.join(', ') || '(none)'}`)
})
}
// Swap the legend at runtime — a graph that started without one gets it built on
// the spot, and `undefined` removes it (clearing its filter with it).
function legendByType(graph) {
graph.setLegend({ key: 'type', title: 'Service type' })
}
function removeLegend(graph) {
graph.setLegend(false)
}
// Declared entries, for when the categories aren't a plain data key: supply the
// label, the colour and the predicate yourself. An array works too; a function is
// re-resolved whenever the data changes.
function legendByTier(graph) {
graph.setLegend({
title: 'Tier',
entries: [
{
id: 'edge', label: 'Edge', color: '#0072B2',
predicate: (node) => node.getData().type === 'web'
},
{
id: 'service', label: 'Services', color: '#E69F00',
predicate: (node) => node.getData().type === 'api'
},
{
id: 'storage', label: 'Storage', color: '#009E73',
predicate: (node) => ['database', 'cache'].includes(node.getData().type)
}
]
})
}
// Two keys at once: `sections` stacks one titled block per dimension in a single
// docked card. Each section filters on its own, and the filters *and* together —
// hide `api` above and `dmz` below and what is left is neither.
function legendByTypeAndZone(graph) {
graph.setLegend({
// `position` belongs to the card, not to a section. Top-left, because a
// two-section card is tall enough to reach the mode rail in the corner the
// single-key legend uses.
position: 'top-left',
sections: [
// Still adopts the declared `type` facet, so this section and the filter
// panel remain one control.
{ key: 'type', title: 'Service type' },
{
key: 'zone',
title: 'Network zone',
// The colours encode `type`, not `zone`, and the legend can only
// sample colours — so this section declares swatches of its own
// rather than showing one that would be a coincidence. `key` still
// supplies the predicate.
entries: [
{ id: 'dmz', label: 'DMZ', color: '#CC79A7' },
{ id: 'internal', label: 'Internal', color: '#56B4E9' }
]
}
]
})
}// A service graph whose `type` drives both the colours and the legend. The counts
// differ per type on purpose — the legend reports them. `zone` is a second
// dimension the colours say nothing about — see the stacked legend below.
const data = {
nodes: [
{ id: 'web-1', data: { name: 'Web app', type: 'web', zone: 'dmz' } },
{ id: 'web-2', data: { name: 'Mobile web', type: 'web', zone: 'dmz' } },
{ id: 'api-1', data: { name: 'Auth API', type: 'api', zone: 'internal' } },
{ id: 'api-2', data: { name: 'Orders API', type: 'api', zone: 'internal' } },
{ id: 'api-3', data: { name: 'Billing API', type: 'api', zone: 'internal' } },
{ id: 'db-1', data: { name: 'Postgres', type: 'database', zone: 'internal' } },
{ id: 'db-2', data: { name: 'Replica', type: 'database', zone: 'internal' } },
{ id: 'cache-1', data: { name: 'Redis', type: 'cache', zone: 'internal' } }
],
edges: [
{ from: 'web-1', to: 'api-1' },
{ from: 'web-1', to: 'api-2' },
{ from: 'web-2', to: 'api-1' },
{ from: 'api-2', to: 'api-3' },
{ from: 'api-1', to: 'cache-1' },
{ from: 'api-2', to: 'db-1' },
{ from: 'api-3', to: 'db-1' },
{ from: 'db-1', to: 'db-2' }
]
}