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

Adicionar um modo ferroviário ​

O painel esquerdo contém modes, não botões. Selecionar, Criar, Visualizar e Física estão integrados, e cada um mostra apenas suas próprias ferramentas – e é por isso que o trilho permanece com quatro slots de altura, por mais que o gráfico possa fazer. addRailMode() adiciona um quinto.

Este cartão adiciona um modo Explore para percorrer um gráfico de serviço: escolha um nó, selecione seus vizinhos, restrinja a tela a eles e depois volte. Pressione E ou clique na bússola abaixo da divisória.

Onde seu modo chega ​

Os modos registrados ficam abaixo de um divisor, após os integrados, ordenados entre si por order. Um plugin não pode reordenar ou remover os quatro integrados, então tudo acima da linha é igual em todos os gráficos Pivotick, e tudo abaixo dela é seu.

Declare ferramentas, não marcação ​

Os tools de um modo tornam-se linhas no painel contextual, desenhados como Select e Create. Você fornece os verbos; o kind de cada linha diz como ela se comporta:

kindComportamento
'action'executa uma vez e deixa o modo sozinho – todas as três ferramentas aqui
'toggle'arma uma ferramenta: o painel entra em colapso e o botão do trilho se torna aquela ferramenta, da mesma forma que o slot do Select se torna Lasso
'default'a ferramenta na qual o modo repousa e para onde a alternância volta

enabled() é verificado novamente sempre que a seleção muda - é por isso que Selecionar vizinhos e Isolar permanecem acinzentados até você escolher um nó.

Nada aqui é privilegiado ​

Cada ferramenta acima chama uma API pública que você mesmo poderia chamar: getEdges() para percorrer as relações, selectNodes() para selecioná-las, setVisibleNodes() para restringir a tela. O modo apenas dá a eles um lugar para morar – um slot ferroviário, um atalho, um estado armado e um painel.

Qual é a questão: um modo Explorar que sabe o que “vizinho” significa para seus dados é algo que você pode construir e nós não.

Os modos excluem-se mutuamente

Abrir o Explore fecha o View e o Physics e vice-versa – um armazenamento, um modo ativo. Desfaça qualquer que seja o seu modo armado em onExit; ele também é executado se o modo for removido enquanto estiver ativo e o trilho voltar para Selecionar.

Quando um flyout se ajusta melhor ​

Um modo que configura em vez de agir deseja uma sobreposição ampla, não uma faixa de ferramentas estreita. Defina kind: 'flyout', crie uma subclasse do Flyout exportado e passe addRailMode uma fábrica - consulte Contribuindo com um modo ferroviário.

js
// The rail's four modes — Select, Create, View, Physics — are built in. `addRailMode`
// is how you add a fifth. It renders below a divider, after them, and drives the same
// contextual tool panel the built-ins do: declare `tools`, and the arming, the
// enabled/disabled states and the collapse are handled for you.
//
// This card adds an **Explore** mode for walking the graph: reach the neighbours of what
// is selected, isolate a subgraph, and step back out. Nothing here is privileged — every
// tool is public graph API a consumer could call themselves.

const compass = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20"><path fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round" d="M12 21a9 9 0 1 0 0-18a9 9 0 0 0 0 18Z"/><path fill="currentColor" d="M15.5 8.5l-2 5l-5 2l2-5z"/></svg>'
const expandIcon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18"><path fill="currentColor" d="M11 13v3a1 1 0 0 0 2 0v-3h3a1 1 0 0 0 0-2h-3V8a1 1 0 0 0-2 0v3H8a1 1 0 0 0 0 2zm1 9a10 10 0 1 1 0-20a10 10 0 0 1 0 20m0-2a8 8 0 1 0 0-16a8 8 0 0 0 0 16"/></svg>'
const isolateIcon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="18" height="18" fill="none" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"><path d="M16 6H8a2 2 0 0 0-2 2v8m10 26H8a2 2 0 0 1-2-2v-8m26 10h8a2 2 0 0 0 2-2v-8M32 6h8a2 2 0 0 1 2 2v8"/><circle cx="24" cy="24" r="6"/></svg>'
const resetIcon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18"><path fill="currentColor" d="M12 5V2L8 6l4 4V7a5 5 0 1 1-5 5H5a7 7 0 1 0 7-7"/></svg>'

function exploreMode() {
    return {
        name: 'explore-mode',
        install(ctx) {
            const interaction = () => ctx.graph.renderer.getGraphInteraction()
            const selected = () => interaction().getSelectedNode()?.node

            /** Every node one hop from `id`, itself included. */
            const withNeighbours = (id) => {
                const keep = new Set([id])
                for (const edge of ctx.graph.getEdges()) {
                    if (edge.from.id === id) keep.add(edge.to.id)
                    if (edge.to.id === id) keep.add(edge.from.id)
                }
                return keep
            }

            ctx.addRailMode({
                id: 'explore',
                label: 'Explore',
                icon: compass,
                // Pressing E switches to the mode, or toggles its panel when it is
                // already active — exactly what V and C do for Select and Create.
                shortcut: 'E',
                tools: [
                    {
                        // A one-shot action: it runs and leaves the mode as it was.
                        id: 'expand',
                        label: 'Select neighbours',
                        icon: expandIcon,
                        kind: 'action',
                        // Re-checked on every selection change, so the row greys out
                        // when it would do nothing.
                        enabled: () => !!selected(),
                        run: () => {
                            const node = selected()
                            if (!node) return
                            const keep = withNeighbours(node.id)
                            interaction().selectNodes(
                                ctx.graph.getMutableNodes()
                                    .filter(n => keep.has(n.id))
                                    .map(n => ({ node: n, element: n.getGraphElement() }))
                            )
                        },
                    },
                    {
                        id: 'isolate',
                        label: 'Isolate neighbourhood',
                        icon: isolateIcon,
                        kind: 'action',
                        enabled: () => !!selected(),
                        run: () => {
                            const node = selected()
                            if (!node) return
                            const keep = withNeighbours(node.id)
                            ctx.graph.setVisibleNodes(
                                ctx.graph.getMutableNodes().filter(n => keep.has(n.id))
                            )
                        },
                    },
                    {
                        id: 'reset',
                        label: 'Show everything',
                        icon: resetIcon,
                        kind: 'action',
                        run: () => ctx.graph.setVisibleNodes(ctx.graph.getMutableNodes()),
                    },
                ],
            })
        },
    }
}

const options = {
    UI: {
        mode: 'full',
        // Neither is what this card is about, and both crowd a small canvas.
        minimap: false,
        table: false,
    },
    plugins: [exploreMode()],
}
js
const data = {
    nodes: [
        { id: 'api', data: { label: 'api-gateway', kind: 'service' } },
        { id: 'auth', data: { label: 'auth-service', kind: 'service' } },
        { id: 'billing', data: { label: 'billing-service', kind: 'service' } },
        { id: 'search', data: { label: 'search-service', kind: 'service' } },
        { id: 'users-db', data: { label: 'users-db', kind: 'datastore' } },
        { id: 'orders-db', data: { label: 'orders-db', kind: 'datastore' } },
        { id: 'index', data: { label: 'search-index', kind: 'datastore' } },
        { id: 'cache', data: { label: 'edge-cache', kind: 'datastore' } },
        { id: 'mailer', data: { label: 'mailer', kind: 'worker' } },
        { id: 'reindexer', data: { label: 'reindexer', kind: 'worker' } },
    ],
    edges: [
        { from: 'api', to: 'auth' },
        { from: 'api', to: 'search' },
        { from: 'api', to: 'billing' },
        { from: 'api', to: 'cache' },
        { from: 'auth', to: 'users-db' },
        { from: 'billing', to: 'orders-db' },
        { from: 'billing', to: 'mailer' },
        { from: 'search', to: 'index' },
        { from: 'reindexer', to: 'index' },
        { from: 'reindexer', to: 'orders-db' },
    ],
}
Pager
Próxima páginaPrimeiros passos