Pular para o conteúdo
Pivotick
Main Navigation Início
Primeiros passos
Configuração
Referência da API
GaleriaProjetosExperimente!

Português

English
简体中文
Français
Deutsch

Português

English
简体中文
Français
Deutsch

Aparência

Sidebar Navigation

Primeiros passos

Projetos que usam o Pivotick

Configuração

Funções de retorno

Camadas de arestas

Simplificar

Layout

Renderização

Simulação

Personalizar a interface

Barra lateral

Dica

Menu de contexto

Filtros

Legenda

Tabela de dados

Estilo da interface

Traduzir a interface

Plugins

API Pivotick

Pivôs e enriquecimento

Salvar resultados dos pivôs

Desfazer e histórico

Segurança

Documentação da API

Galeria

Fundamentos

Estilo dos nós

Estilo das arestas

Layouts

Eventos e funções de retorno

Personalização da interface

Edição e criação

Notas e anotações

Filtros, pesquisa e hierarquia

Controle por programação

Temas e desempenho

Pivôs e enriquecimento

Demonstrações completas

Legenda filtrável ​

Um gráfico codificado por cores precisa de uma chave – e uma vez que tenha uma, a chave é o filtro mais rápido na IU. UI.legend encaixa um em um canto da tela: uma amostra, um rótulo e uma contagem de nós por categoria, e clicar em uma linha oculta essa categoria. Apontar para uma linha primeiro ilumina seus nós na tela e escurece o restante, para que uma categoria possa ser encontrada antes de ser desativada.

Uma linha configura: legend: { key: 'type' }. A biblioteca coleta os valores distintos de data.type, lê cada amostra da cor que o renderizador ** já resolveu** e conta os nós por trás dela. Muitas vezes você não precisa de nenhuma linha — com um render.nodeTypeAccessor declarado, uma legenda aparece sozinha assim que a dimensão é mostrada para explicar as cores (veja Legend); esta carta declara o bloco para mostrar os botões. A legenda é puramente descritiva — as cores aqui vêm de ColorPaletteMapper nas opções, exatamente como em Cor por categoria, e a legenda nunca atribui uma. Mude a paleta e a legenda segue.

Clicar em uma linha filtra graph.queryEngine, então é o mesmo que filtra o painel Graph Filters do cabeçalho. Este cartão declara uma faceta type sob a própria chave da legenda, o que torna os dois um único controle: desligue api na legenda, abra o painel (funil, ou Shift+K) e sua seleção múltipla Tipo de serviço já a descartou. resetFilters() — ou Reset do painel — acende novamente cada linha.

Nós sem type não recebem nenhuma linha, e a legenda nunca os esconde: ela só pode atuar nas categorias que lista.

Uma chave raramente é toda a história. Duas teclas ao mesmo tempo empilha uma seção intitulada por dimensão no mesmo cartão encaixado - pressione tipo + zona abaixo: type continua dirigindo a faceta do painel, zone obtém uma seção própria e os dois filtros ** e ** juntos, escondendo-se api e dmz deixam o que não é nenhum dos dois. zone declara suas próprias cores de amostra, porque a tela codifica type em suas cores e uma amostra de amostra para zone seria apenas uma coincidência.

Uma seção também pode digitar edges em vez de nós - scope: 'edge' lista os tipos de relação do gráfico com uma amostra de linha e oculta uma camada inteira quando você clica em uma. Isso precisa de bordas que vêm em tipos, por isso fica no cartão Edge Layers.

Em um cabeçalho de seção: mostrar tudo, invert e uma divisa que dobra essa seção em seu título - alt-click na divisa para dobrar cada seção. Passe o mouse uma linha para iluminar sua categoria na tela; alt-click um para mostrar apenas essa categoria. As alternâncias são registradas no console por meio de legendToggle, que nomeia sua seção.

js
// 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
}
js
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)
        }
    }
}
js
// 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' }
                ]
            }
        ]
    })
}
js
// 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' }
    ]
}
Pager
Próxima páginaPrimeiros passos