Opções da interface
Pivotick fornece uma camada de UI flexível na parte superior do seu gráfico, permitindo controlar como os usuários interagem com nós, bordas e tela. Usando as opções UI, você pode:
- Configure o mode geral da UI (completo, visualizador, estático, etc.).
- Personalize barra lateral e painéis para mostrar propriedades ou informações extras.
- Defina tooltips para nós e arestas, com renderizadores personalizados opcionais.
- Configure menus de contexto para nós, arestas e tela.
- Declare as facetas do painel filter ou deixe que elas sejam derivadas de seus dados.
- Encaixe um legend na tela — uma chave para suas cores que funciona como um filtro e que aparece sozinha quando suas cores são explicadas por um tipo de nó declarado.
- Preencha qualquer uma dessas superfícies de forma assíncrona, a partir dos dados que você busca sob demanda.
- Desligue qualquer recurso que sua integração não tenha utilidade.
- Coloque o texto da própria biblioteca no idioma dos seus usuários: consulte Traduzindo a UI.
Modo UI
A opção mode controla o comportamento geral e o nível de interação da IU do gráfico.
fullpadrão: UI completa com todos os painéis, menus e interações habilitados.light: UI mínima com interações essenciais habilitadas.viewer: Permite apenas navegar no gráfico (panorâmica, zoom, arrastar) sem exibir nenhum painel da UI.static: Gráfico estático, sem painéis de UI ou interações; o gráfico é somente leitura.
Para uso de estilo de imagem de Pivotick, use o seguinte:
const container = document.getElementById('graph-container')
const options = {
UI: {
mode: 'viewer'
},
}
const graph = Pivotick(container, options)Outro componente de UI pode ser configurado através de seu respectivo namespace
const options = {
UI: {
sidebar: {},
mainHeader: {},
propertiesPanel: {},
extraPanels: [],
tooltip: {},
contextMenu: {},
filter: {},
}
}A superfície de controle do modo full
No modo full, o cromo é um layout orientado por modo: um mode rail esquerdo (Selecionar / Criar / Visualizar / Física), um painel de ferramentas contextuais para o modo de ponteiro ativo, dois submenus de configurações - View (fundo de tela e interruptores) e Física (layout + simulação) — a barra superior (pesquisa, filtro, notas, desfazer/refazer), a seleção barra lateral (propriedades, facetas, vizinhos e uma linha de ação em massa) e uma janela de visualização ** do lado direito rail** (ajuste e centralização, zoom, configurações, tela cheia) e um minimapa no canto inferior direito livre, que se dobra quando a tela é pequena demais para poupar espaço (UI.minimap: false para soltá-la). O modo light elimina a barra lateral e o minimapa; viewer mantém apenas o trilho da viewport; static é uma tela vazia.
Migrando do canto cromado
As sobreposições flutuantes GraphControls e GraphToolbar foram removidas. Layout e física foram movidos para o submenu Física (UIManager.physicsFlyout) — eles foram enviados para o submenu Visualizar (UIManager.viewFlyout) na versão 1.5.0, que agora contém o plano de fundo da tela e as opções de grade. Selecione/crie ferramentas ao vivo no painel de ferramentas (UIManager.toolPanel) e no modo ferroviário (UIManager.modeRail). A opção UI.selectionMenu desapareceu — use contextMenu para ações por nó e a linha de ação em massa da barra lateral para ações de seleção múltipla. UIManager.graphNaviation foi renomeado para graphNavigation. A opção UI.modeRail e seus slots Explore / Enrich desativados foram removidos — em vez disso, registre um modo real com addRailMode. Veja o CHANGELOG.
Os quatro modos do rail estão integrados, mas não os únicos que ele pode conter: um plugin adiciona o seu próprio com addRailMode, que é como um modo Explorar ou Enriquecer que sabe o que seus significa é construído.
Desativando recursos
O modo UI decide quanto cromo um gráfico recebe. Cada recurso dentro desse Chrome também pode ser desativado um de cada vez, e é assim que uma integração descarta aquilo que seu back-end ou seus usuários não têm utilidade.
Um recurso desativado leva tudo que chega até ele: o botão, o painel, a entrada do menu de contexto e o atalho do teclado, todos juntos, então nada é deixado para trás para clicar ou pressionar e recusar silenciosamente.
const options = {
UI: {
mode: 'full',
notes: { enabled: false },
history: { enabled: false },
inspector: { enabled: false },
editors: { deletion: { enabled: false } },
},
}Os interruptores
| Opção | O que vem com isso |
|---|---|
UI.topBar.enabled | A faixa superior, a altura reservada, os atalhos que seus controles possuem (Shift+J, Shift+K, Shift+N, Mod+Z) e quaisquer ações de host. Use os interruptores abaixo para largar um comprimido e guardar o resto. |
UI.search.enabled | A pílula Search, seu seletor de nós e Shift+J. |
UI.filter.enabled | A pílula Filter Graph, seu painel e Shift+K. graph.queryEngine ainda filtra o código. |
UI.notes.enabled | A pílula e painel Notas, Shift+N, a ferramenta Adicionar nota, Adicionar nota do menu de tela, N, o menu de contexto da nota e noteManager.addNote, que recusa. |
UI.history.enabled | Os botões desfazer/refazer, o menu suspenso do histórico e Mod+Z/Mod+Shift+Z. graph.history continua gravando. |
UI.inspector.enabled | A entrada Inspecionar Propriedades do menu do nó e I. |
UI.notifications.enabled | Brindes. graph.notifier.* torna-se um undefined de retorno autônomo. |
UI.sidebar.enabled | Toda a coluna lateral e a largura que ela ocupava. |
UI.propertiesPanel.enabled | O painel de propriedades da barra lateral e seu separador. |
UI.neighborsPanel.enabled | O painel de vizinhos da barra lateral e seu separador. |
UI.viewFlyout.enabled | O botão Exibir trilho e seu painel. |
UI.physicsFlyout.enabled | O botão do trilho Física e seu painel. |
UI.tooltip.enabled | Dicas de ferramentas suspensas, incluídas as fixadas. Também leva { nodes, edges, groups } ou (element, kind) => boolean, veja Tooltips. |
UI.contextMenu.enabled | Cada menu de contexto. |
UI.navigation.enabled | O trilho da janela de visualização: ajuste, zoom e tela cheia. |
UI.legend: false | A legenda da tela, incluindo aquela que ela derivaria por si só. |
UI.minimap: false | O minimapa. |
UI.emptyState: false | O cartão mostra uma tela vazia. |
UI.table: false | O data dock e seu Shift+T. |
UI.pivotMode: false | O modo trilho Pivot, qualquer que esteja registrado. |
Os recursos de caminho de gravação têm a mesma opção em UI.editors, portanto, uma integração somente leitura remove a capacidade em vez de vetar cada clique: nodeCreator, edgeCreator, nodeEditor, edgeEditor e deletion.
O comportamento do renderizador é desativado em render: zoomEnabled (que também usa os botões de zoom do trilho, mantendo o ajuste e o centro), dragEnabled, selectionBox.enabled (a marca ** e ** a ferramenta Selecionar ▸ Laço), enableNodeExpansion (a divisa, seu Enter e o tracejado contorno recolhido), enableFocusMode e interactionEnabled para tudo de uma vez. simulation.enabled interrompe a execução do layout.
O modo Criar segue suas ferramentas
O modo Criar trilho contém exatamente quatro ferramentas: Adicionar nó, Adicionar aresta, Adicionar nota e Editar nó. Desligue todos os quatro e o modo sai do trilho, junto com seu atalho C, em vez de abrir em um painel vazio. Selecione sempre permanece.
Suas próprias ações na barra superior
Uma ação em toda a tela, como salvá-la, pertence à barra superior ao lado do grupo desfazer-refazer. UI.topBar.actions declara pílulas desenhadas no mesmo estilo de Pesquisa, Filtro e Notas, portanto, um tema que reestiliza essas reestilizações também.
const options = {
UI: {
topBar: {
actions: [{
id: 'save-graph',
text: () => storedId ? 'Update graph' : 'Save as graph',
async onclick(_event, ctx) {
if (storedId) return updateGraph(storedId, ctx.graph)
const values = await ctx.promptData({
fields: [{ key: 'name', label: 'Name', type: 'text' }],
})
if (values) storedId = await createGraph(values.name, ctx.graph)
},
menu: () => storedId
? [{ text: 'Save as new graph…', onclick: saveAsNew }]
: [],
}],
},
},
}- Onde.
placement: 'end'(o padrão) coloca a pílula logo antes do grupo desfazer-refazer;'start'coloca depois dos comprimidos embutidos à esquerda. Os comprimidos mantêm a ordem em que foram declarados. - O que diz.
text,title,visibleeenabledassumem um valor ou função do gráfico. As funções são lidas novamente após cada alteração de dados, emgraph.UIManager.refreshTopBar(), e assim que uma promessa retornada poronclickfor concluída. Enquanto essa promessa estiver fora, a pílula estará desativada, portanto, um salvamento lento não pode ser iniciado duas vezes. - O que obtém.
onclick(event, ctx)recebe o gráfico e dois auxiliares que abrem o modal da biblioteca:ctx.promptData({ fields })resolve para os valores ounullno cancelamento, ectx.confirm({ body })resolvetrueapenas no botão confirmar.ctx.refresh()relê cada ação. - Um sinal de intercalação. Com
menu, o comprimido se torna um botão de divisão: o rótulo executaonclicke um sinal de intercalação abre as linhas, no mesmo formato de linha dos menus de contexto (sem submenus). Um formulário de função é entregue da mesma formactxe é chamado a cada atualização e a cada abertura; embora não retorne nenhuma linha, a pílula não tem sinal de intercalação. Escape ou clique em outro lugar fecha as linhas. - Um atalho.
shortcutdesenha um distintivo na pílula. É apenas uma etiqueta: registe você mesmo a encadernação.
Um plugin adiciona um comprimido com ctx.addTopBarAction(action), que retorna um triturador (veja Plugins). As pílulas seguem a faixa: nenhuma no modo viewer ou static e nenhuma no modo UI.topBar.enabled: false.
Uma tela vazia
Um gráfico sem nó e sem nota mostra um cartão no meio da tela, portanto, uma fonte sem nada para desenhar não é lida como um gráfico que falhou ao carregar. Diz "Nada na tela ainda", a menos que você dê algo mais a dizer:
const options = {
UI: {
emptyState: {
render: ({ initial, graph }) => {
const box = document.createElement('div')
box.textContent = initial ? 'Nothing is related to this record.' : 'The canvas is empty.'
const button = document.createElement('button')
button.textContent = 'Find related'
button.onclick = () => graph.UIManager.openPivotMode()
box.append(button)
return box
},
},
},
}O cartão segue os dados. Adicionar um nó ou uma nota tira-o, e remover o último deles, manualmente ou desfazendo o ingest que os trouxe, traz-o de volta. Os nós que os filtros ocultam ainda contam: o gráfico é reduzido, não vazio.
render é executado cada vez que o cartão aparece, não em todas as alterações enquanto ele está ativo. initial é true até que o gráfico tenha mantido um nó, então um analista que esvaziou uma tela completa pode receber algo diferente do que uma fonte vazia é informada. Uma string retornada é renderizada como texto simples e render pode ser async como os ganchos abaixo.
O cartão usa superfície e borda cromadas, portanto segue o tema. Ele permite a passagem dos gestos da tela, de modo que o movimento panorâmico, o zoom e o menu da tela funcionam nela, exceto no conteúdo interativo: um botão, um link, um controle de formulário ou qualquer coisa com tabindex recebe seus próprios cliques. UI.emptyState: false não mostra absolutamente nada.
Conteúdo assíncrono
Cada gancho de conteúdo fornecido pelo consumidor pode retornar um Promise em vez do conteúdo em si. Isso cobre mainHeader.render, propertiesPanel.render / nodePropertiesMap / edgePropertiesMap, neighborsPanel.render, um painel extra title e render, a dica de ferramenta render, renderNodeExtra, renderEdgeExtra e mapas de propriedades, e a tela vazia render.
Isso existe para o caso em que os dados de um nó são uma referência para um registro em vez do registro em si, e o conteúdo interessante está por trás de uma chamada HTTP:
const options = {
UI: {
tooltip: {
renderNodeExtra: async (node, { signal }) => {
const res = await fetch(`/enrich/${node.getData().uuid}`, { signal })
return renderChips(await res.json()) // an HTMLElement
},
},
},
}Adicione async, encaminhe signal e a biblioteca cuida do resto:
| Espaço reservado | Enquanto a promessa está pendente, um esqueleto temático ocupa o espaço. |
| Trocar | Na resolução, o conteúdo substitui o espaço reservado no lugar. |
| Estabilidade | Um resultado que chega depois que seu slot acabou - você passou o mouse sobre outro nó, alterou a seleção, atualizou o painel - é dropado. Somente a renderização mais recente de uma superfície pode ser confirmada, independentemente da ordem em que for resolvida. |
| Cancelamento | ctx.signal é abortado quando uma renderização é substituída ou o gráfico é destruído, então um fetch encaminhado é cancelado em vez de vazar. |
| Falha | Uma promessa rejeitada renderiza uma linha de erro compacta em vez de deixar um botão giratório para sempre. Uma renderização abortada não é uma falha e não mostra nada. |
O contexto de renderização
Cada gancho de conteúdo recebe um RenderContext como seu argumento last. Os ganchos síncronos existentes simplesmente o ignoram.
render: async (element, { signal, isStale }) => {
const rows = await fetchRows(element, signal)
if (isStale()) return '' // cheap guard for non-abortable work
return renderRows(rows)
}Personalizando o espaço reservado
UI.asyncContent substitui o que é mostrado enquanto pendente e em caso de falha. Ambos aceitam uma string, um HTMLElement ou uma função da superfície:
const options = {
UI: {
asyncContent: {
placeholder: (surface) => surface === 'tooltip' ? 'Loading…' : mySkeleton(),
error: 'Could not load',
},
},
}surface é um de 'tooltip', 'properties', 'neighbors', 'mainHeader', 'extraPanel' ou 'emptyState'.
Ganchos síncronos permanecem intactos
O retorno direto do conteúdo se comporta exatamente como sempre: mesma chamada, mesmo quadro, sem espaço reservado e sem elemento wrapper. Nada muda em uma integração existente.
O que não pode ser assíncrono
Dois grupos permanecem sincronizados propositalmente:
HeaderMapEntry.title/subtitlealimenta o slot de título de ajuste automático * e* pesquisa de nó (resolveNodeByName), ambos os quais precisam do texto agora. Use ummainHeader.renderassíncrono se precisar de detalhes buscados no cabeçalho.PropertyEntry.name/value— em vez disso, busca as linhas: umnodePropertiesMapassíncrono resolve uma vez e depois devolve entradas simples, em vez de colocar um controle giratório em cada célula.
Os ganchos do renderizador por quadro (render.renderNode, renderLabel, renderCluster e NodeStyle.html) também são somente de sincronização: eles são executados dentro do caminho de desenho, por nó, por tick. Se você precisar do nó assíncrono decoration, busque os dados do nó e deixe o renderizador síncrono lê-los.