Pular para o conteúdo

Opções de filtro ​

No modo full, o cabeçalho carrega um painel Graph Filters (o ícone do funil, ou Shift+K) cujo formulário foi criado para você. Por padrão, a biblioteca deriva esse formulário verificando os dados do nó; UI.filter permite que você assuma isso.

ts
const options = {
    UI: {
        filter: {
            facets: [ /* … */ ],   // declare the facets — the form follows
            excludeKeys: ['uuid'], // or just prune the derived ones
        },
    },
}

UI.filter.enabled: false remove o painel, seu comprimido e Shift+K completamente; graph.queryEngine ainda filtra o código.

A forma aplica-se: uma escolha ou um tique é confirmado no momento em que você o faz, um campo de texto ou padrão uma batida depois que você para de digitar. Não há botão de aplicação, então o painel nunca pode mostrar um filtro que a tela não possui. Reset, ao lado do rótulo da seção, limpa todos os filtros de atributos de uma vez.

Filtrando bordas, não nós

Tudo nesta página seleciona nodes. Para filtrar edges — ocultando todo um tipo de relação sem mover o gráfico — declare UI.filter.edgeFacets em vez disso; eles reutilizam o mesmo vocabulário de facetas e estão documentados em Edge Layers.

Derivação automática (o padrão) ​

Sem nenhum UI.filter, o painel percorre as chaves de dados de cada nó, coleta os valores distintos por chave e escolhe um widget a partir do que encontra:

Como são os valoresWidget
todos os númerosnumberRange (mín./máx.)
3+ cordas curtasmultiselect
1–2 cordas curtasselect
booleanosselect (verdadeiro/falso)
qualquer outra coisatext

Os rótulos são aprimorados a partir da chave (attr-type → Attr Type). Este é um bom padrão de configuração zero para dados exploratórios, mas não há como saber quais chaves são facetas e quais são internas — um uuid se torna um menu suspenso com uma opção por nó, e um longo campo de texto livre se transforma em uma caixa de texto.

excludeKeys ​

A solução barata quando a derivação está quase certa: descarte as teclas que fazem barulho.

ts
UI: { filter: { excludeKeys: ['uuid', 'imageUrl', 'description'] } }

Facetas declaradas ​

Defina facets e o formulário será gerado a partir da sua declaração — exatamente os campos que você lista, na ordem em que os lista, com seus rótulos. A derivação automática é totalmente ignorada, portanto, nada muda conforme os dados mudam.

ts
UI: {
    filter: {
        facets: [
            { key: 'category', label: 'Category', type: 'multiselect',
              options: (graph) => distinct(graph, 'category') },
            { key: 'to_ids',   label: 'IDS flag', type: 'boolean' },
            { key: 'value',    label: 'Value',    type: 'regex' },
        ],
    },
}

O key de uma faceta também é a chave que queryEngine.setFilter(key, …) usa, portanto a filtragem programática e o painel permanecem no mesmo nível.

Tipos de facetas ​

  • text — substring ou correspondência exata, por matchMode.
  • regex — um padrão, compilado sem distinção entre maiúsculas e minúsculas. Um padrão não compilável é relatado no campo e deixa os filtros ativos intactos.
  • select / multiselect — escolha entre options. Passe uma matriz ou uma função resolvida no gráfico ao vivo para que as listas de opções sigam os dados sem que o próprio conjunto de facetas seja alterado.
  • numberRange — um par mínimo/máximo.
  • boolean — um menu suspenso verdadeiro/falso/não definido.

Etiquetas ​

Um label declarado é usado verbatim, então pode vir da sua camada de tradução. Omita-o e a chave será embelezada como na derivação automática.

Facetas computadas: accessor ​

Por padrão, uma faceta é node.getData()[key]. Um accessor lê o que você quiser — incluindo coisas que não estão no nó:

ts
// "this object contains an attribute of type X" — reads the node's children
{ key: 'child_type', label: 'Contains attribute of type', type: 'multiselect',
  options: () => ATTRIBUTE_TYPES,
  accessor: (node) => node.children.map((child) => child.getData()['attr-type']) }

Retornar um array é bom - veja matrizes correspondentes abaixo.

Controle total: predicate ​

Um predicate decide a adesão por si mesmo e vence accessor / matchMode. Ele é executado por nó e por aplicativo de filtro, portanto, mantenha-o barato.

ts
{ key: 'busy', label: 'Busy services', type: 'text',
  predicate: (node, value) => node.getData().load >= Number(value) }

Uma faceta cujo lançamento accessor ou predicate interrompe a correspondência (e avisa uma vez) em vez de reduzir a renderização com ela.

Pedido ​

Os campos seguem a ordem da declaração. Defina order em uma faceta para posicioná-la explicitamente — útil quando as facetas são montadas em vários lugares.

Correspondência ​

matchMode decide como um valor de filtro é comparado:

  • 'exact' padrão — igualdade estrita. Para uma seleção múltipla (uma série de opções), isso é associação: qualquer um.
  • 'partial' — correspondência de substring, String(nodeValue).includes(value).
  • 'all' — e-semântica: todo valor selecionado deve estar presente.

Matrizes correspondentes ​

Quando o valor de um nó é array — data.tags = ['tlp:amber', 'malware'] — um filtro testa membership, não igualdade:

ts
// matches nodes tagged 'malware'; does NOT match a node tagged 'not-malware'
graph.queryEngine.setFilter('tags', { value: 'malware' })

// any-of: amber OR green
graph.queryEngine.setFilter('tags', { value: ['tlp:amber', 'tlp:green'] })

// all: amber AND green
graph.queryEngine.setFilter('tags', { value: ['tlp:amber', 'tlp:green'], matchMode: 'all' })

Com 'partial', qualquer elemento único pode corresponder à substring. Um numberRange em uma matriz corresponde quando qualquer elemento está dentro do intervalo.

Mudança de comportamento

Antes de isso ser suportado, o valor de um nó da matriz caía para String(nodeValue).includes(value) - portanto, um filtro para malware correspondia acidentalmente a um nó marcado como not-malware e um valor de filtro da matriz nunca correspondia. Ambos agora se comportam conforme descrito acima.

Negação ​

negate: true mantém o que o filtro ocultaria. Cada campo no painel possui uma opção é / não é em sua linha de rótulo que o define; um campo alterado para não é é desenhado em vermelho e suas escolhas estão riscadas.

ts
// every type but domain, including types added later
graph.queryEngine.setFilter('type', { value: ['domain'], negate: true })

// nothing tagged malware
graph.queryEngine.setFilter('tags', { value: ['malware'], negate: true })

Ele lê o contrário para cada widget: uma lista é nenhum de, um campo de texto não contém (com 'partial'), um padrão não corresponde a, um intervalo fora. Com 'all' é *nem todos *. A resposta da faceta predicate é invertida.

Um nó com nenhum valor para a chave é mantido, pois também não é um domínio. Portanto, um filtro e sua negação sempre dividem o gráfico em dois, cada nó exatamente de um lado. Um valor que não restringe nada (uma lista vazia, uma string em branco, um intervalo aberto, um padrão inutilizável) ainda assim não restringe nada.

Os campos verdadeiro/falso não têm opção: não é verdadeiro é é falso. Os filtros de borda (setEdgeFilter) também levam negate. Uma seção legend que compartilha a chave de uma faceta mantém um filtro negado negado quando você clica nele.

Ocultando nós não conectados ​

Filtrar as relações deixa os nós para trás. Desative uma edge layer e um nó cuja única relação estava nela permanece na tela sem nada anexado - o que é deliberado, porque uma camada é uma lente. Quando você do deseja que esses nós desapareçam, essa é uma regra do lado do nó:

ts
const options = {
    UI: {
        filter: { hideDisconnected: true },
    },
}

Um nó está oculto quando não tem nenhuma borda visível restante, contada após as camadas e os filtros do nó terem se manifestado. Um autoloop conta como uma relação; uma nota fixada em um nó não.

A mesma opção está no menu desdobrável View como Hide unconnected, em todos os gráficos, desativada, a menos que a opção ative-a - para que um usuário possa limpar os órfãos, alterne para a esquerda ou coloque de volta aqueles que você escondeu. Enquanto está escondido, a linha diz quantos.

Este move o gráfico

Todo o resto nesta página, e cada camada de borda, deixa o layout em paz. Um nó oculto sai da simulação, então o restante é reinstalado. Essa é a troca por uma tela organizada e é por isso que a regra está desativada por padrão.

Duas coisas que deliberadamente não faz:

  • Os interiores dos clusters são deixados de lado. Os clusters rotineiramente agrupam nós sem relações entre eles, portanto, aplicar a regra dentro de um deles abriria uma caixa vazia.
  • Nada está protegido. Desligue todas as camadas e nada estará conectado, então nada será desenhado. A mudança é o caminho de volta.
ts
graph.queryEngine.setHideDisconnected(true)  // same as the switch
graph.queryEngine.isHideDisconnected()
graph.queryEngine.getDisconnectedNodeCount() // what the switch row reports

Reaplicando após as alterações de dados ​

Os filtros são aplicados quando um filtro muda — e não quando os dados do gráfico mudam. Adicione a aresta que faltava em um nó e ela permanecerá oculta até que algo seja recalculado:

ts
graph.updateData(newNodes, newEdges)
graph.queryEngine.reapply()   // recompute now

Vale a pena saber antes de ligar: derivar novamente a visibilidade ** desfaz um manual graph.hideNode()**, do qual nada lembra. queryEngine.excludeNode() é o esconderijo que sobrevive — é o que o menu de contexto e as ações em massa usam, e apenas Mostrar nó o inverte.

Onde o painel obtém seus valores ​

O filtro valores sempre flui através de graph.queryEngine, independentemente da forma como o formulário é construído - portanto, a contagem de filtros ativos do cabeçalho, a lista Nós ocultos e a propagação para um subgráfico de cluster expandido continuam funcionando. As facetas declaradas também são transmitidas ao subgráfico de um cluster, portanto, uma faceta accessor / predicate filtra os filhos exatamente como filtra os nós de nível superior.

A tela legend é uma terceira via para o mesmo mecanismo: clicar em uma linha de legenda oculta essa categoria. Dê à legenda o key de uma faceta select / multiselect declarada e os dois acionam o filtro one, para que o controle do painel e a legenda permaneçam sincronizados.

A data table é a quarta: seu botão Apply to graph oculta os elementos que seus filtros de coluna deixam de fora. Esse push fica sob uma chave reservada própria, portanto, ele sobrevive a qualquer coisa que o formulário deste painel se aplique e é combinado com tudo o que este painel está filtrando, em vez de substituí-lo. Como o formulário estruturalmente não pode mostrar uma chave reservada, o painel cresce uma linha From the table nomeando o que o push está escondendo - e o único outro lugar de onde ele pode ser limpo, uma vez que o dock é dobrado.

Consulte o cartão da galeria Filter / query engine para obter um exemplo ao vivo e FilterFacet para o tipo completo.