Tableau de données
UI.table divise un data dock du bas du canevas : les nœuds et les bords du graphique sous la forme d'une grille triable et sélectionnable. Cela existe parce qu'une disposition des forces est structurellement mauvaise dans trois domaines que les gens font constamment : lire des valeurs exactes, sélectionner à grande échelle et déterminer par où commencer.
La boucle prévue est table à trouver, canevas à comprendre, barre latérale à lire : triez par degré pour repérer les hubs, maj-cliquez sur les vingt premiers et agissez dessus avec les actions groupées de la barre latérale.
const options = {
UI: { mode: 'full' },
}C'est tout ce qu'il faut. En mode full, le dock se trouve en bas plié sur sa barre d'en-tête ; cliquez sur son chevron — ou appuyez sur Shift+T — pour afficher le tableau. UI.table: false le supprime entièrement.
Il n'y a délibérément aucun bouton dans la barre d'outils pour cela. La barre est le contrôle : les pilules dans la barre supérieure ouvrent toutes quelque chose sur la toile, tandis que le dock est une région divisée qui vous montre déjà son propre chevron.
Le dock est uniquement en mode full : il s'agit d'une ligne de grille à côté de la barre latérale, et les autres modes promettent un canevas sans autant de chrome.
La table ne change rien de ce que vous lui avez demandé
Le dock ne mute rien. Il reflète le graphique et pilote la sélection ; le masquage et l'épinglage restent avec les actions groupées de la barre latérale, et la restauration d'un nœud caché reste avec le panneau de filtrage. Ce que le dock ajoute, c'est un bien meilleur instrument pour construire la sélection sur laquelle ceux-ci agissent.
La seule chose qu'il peut changer est ce que le canevas affiche, et uniquement sur demande : le bouton Appliquer au graphique masque les éléments que vos filtres de colonne oublient. Jusqu'à ce que vous appuyiez dessus, le rétrécissement d'une colonne est une lecture et non un filtrage.
Il répertorie tout le graphique
Le tableau ne reflète pas le canevas. Il répertorie tous les nœuds - et dans l'onglet Bords, chaque bord - y compris ceux actuellement masqués, et la première colonne Visibility indique où se trouve chacun :
| Valeur | Styles | Signification |
|---|---|---|
visible | silencieux, sans teinte | Sur la toile maintenant |
filtered | puce d'ambre | Caché par un filtre — un filtre de nœud, ou pour un bord son layer étant désactivé. Changez le filtre pour le récupérer |
excluded | puce rouge | Un nœud caché à la main ; restaurez-le à partir de la liste des nœuds cachés du panneau de filtrage |
nested | contour en pointillés | Un nœud à l'intérieur d'un cluster que le canevas a fermé, ou un bord avec une extrémité en un : sa ligne est tracée vers le cluster. Rien ne le filtrait ; ouvrez le cluster pour le voir |
endpoint | contour neutre | Un bord dont la fin a été filtrée. Rien n'a été fait au bord lui-même |
Chaque état diffère en termes de poids, de bordure ainsi que de couleur, de sorte que la colonne se lit sans se fier à la teinte. La rangée entière d'un élément caché recule également, gardant un œil sur ce qui est réellement dessiné.
Un bord lit endpoint de préférence à filtered, car c'est la raison pour laquelle vous devez d'abord corriger : alors qu'un nœud qu'il touche a disparu, la réactivation de sa couche ne peut pas ramener le bord.
C'est délibéré. "23 nœuds cachés" est une affirmation que vous devriez pouvoir inspecter, et une table qui supprime silencieusement les lignes que vous recherchez est pire que pas de table. Triez par Visibility pour voir exactement ce qu'un filtre a supprimé.
Nœuds à l'intérieur des clusters
Le contenu d'un cluster reçoit également des lignes, comme pairs des propres nœuds du graphique, avec une colonne Cluster donnant le chemin d'où ils proviennent (Team B / Squad, le plus à l'extérieur en premier) et une colonne Children indiquant la taille de chaque cluster. Les deux colonnes apparaissent chaque fois que le graphique comporte des clusters. Le commutateur Nœuds imbriqués de l'en-tête supprime à nouveau ces lignes si vous ne voulez que le niveau supérieur, et UI.table.nested: false ne les propose jamais du tout.
Ils sont volontairement répertoriés à plat plutôt qu'en retrait sous leur cluster : le tableau existe pour répondre aux questions que le canevas ne peut pas répondre : quels nœuds sont les hubs, lesquels dépassent un seuil - et cela ne continue de fonctionner que si un tri ou un filtre atteint chaque ligne de manière égale. Un arbre ne peut trier que les frères et sœurs.
Ce qu'il faut savoir, c'est qu'un nœud imbriqué n'est pas dessiné par ce graphe. Un cluster ouvert restitue son propre sous-graphe, donc :
Visibilitylitnestedlorsque tout cluster au-dessus du nœud est fermé, etvisibleune fois qu'ils sont tous ouverts. Ce n'est jamaisfiltered— aucun filtre ne l'a mis là.Degreecompte les arêtes réelles du nœud. Pendant que son cluster est fermé, le canevas les attire vers le cluster, il s'agit donc du décompte du nœud plutôt que d'une description de l'image.- Cliquer sur la ligne sélectionne le nœud, afin que la barre latérale puisse l'afficher – souvent le seul moyen d'y accéder. La toile entoure l'amas fermé qui la représente. Un double-clic ouvre ce cluster, un niveau par pression. Avec
render.enableNodeExpansion: false, le cluster reste fermé et la vue se centre dessus.
Tri et rétrécissement
Cliquez sur n’importe quel en-tête de colonne pour trier ; cliquez à nouveau pour inverser. Les colonnes filtrables développent un contrôle dans l'en-tête qui rétrécit les lignes — chaque colonne de l'ensemble dérivé en a un, et une colonne que vous vous déclarez en obtient une en demandant filterable: true.
Le contrôle que vous obtenez suit le type de la colonne, vous pouvez donc demander à une colonne ce à quoi elle est réellement capable de répondre :
type | Contrôle | Matchs |
|---|---|---|
numberRange | une paire Min / Max | à l'intérieur de l'intervalle ; chaque extrémité peut être laissée vide |
select · multiselect · boolean | un dropdown des valeurs contenues dans la colonne | cette valeur exactement, ou l'appartenance lorsque la cellule est une liste |
text · regex · non typé | une zone de texte **** | sous-chaîne insensible à la casse |
La liste déroulante est construite à partir des propres valeurs de la colonne plutôt qu'à partir d'une liste d'options déclarée, elle ne propose donc jamais de choix qui reviendrait vide. Au-dessus de 50 valeurs distinctes, il est laissé de côté pour la zone de texte - une liste déroulante aussi longue n'est pas un contrôle que quiconque peut utiliser.
Un filtre de lignes n'est pas le filtre du graphique. Cela change ce que vous lisez ** : le canevas est intact et la colonne Visibility continue de rapporter la vérité à côté, donc les deux peuvent être en désaccord sans que l'un ou l'autre ne se trompe. Pousser votre rétrécissement sur la toile est un acte distinct et explicite – voir ci-dessous.
Le nombre du quai reflète les deux : 40 nodes devient 12 of 40 nodes une fois que vous réduisez.
Application des filtres au graphique
Appliquer au graphique, dans la barre d'outils du dock, masque les éléments laissés de côté par vos filtres de colonnes. C'est le pont entre les deux types de filtrage : réduisez les lignes jusqu'à ce que le tableau répertorie ce qui vous intéresse, puis appuyez une fois dessus et le canevas affiche la même chose.
Il s'agit d'une simple pression, pas d'un lien en direct, et le bouton indique dans lequel des trois états vous vous trouvez :
| Bouton | Signification |
|---|---|
Apply to graph, éteint | Rien n'est poussé. Désactivé jusqu'à ce qu'un filtre de colonne rétrécisse réellement quelque chose. |
Clear, lit | Le graphique est filtré et il correspond à vos filtres. Appuyez pour le restaurer. |
Apply to graph, lit | Le graphique est filtré par une poussée plus tôt et vos filtres ont évolué. Appuyez pour le mettre à jour. |
Deux propriétés méritent d’être connues, car c’est elles qui rendent la poussée prévisible :
- Il masque exactement les lignes que les filtres ont laissées de côté — ne jamais "afficher uniquement celles-ci". Ainsi, un nœud ajouté après le push reste sur le canevas. Ce que vous avez poussé est une déclaration concernant un instant, pas une question permanente. L'intérieur d'un cluster ouvert ne se rétrécit que dans la mesure où ses propres rangées faisaient partie de celles laissées de côté ; avec lignes imbriquées désactivées, rien ne les nomme et l'intérieur est intact.
- La colonne
Visibilityfait partie jamais d'une poussée, même si elle rétrécit toujours les lignes comme les autres. Ses valeurs sont sont l'état du filtre du graphique, donc les pousser masquerait tout ce qui se trouve actuellement sur le canevas et serait alors en désaccord avec lui-même.
Pendant qu'un push est en direct, le décompte rapporte les deux moitiés - 12 of 40 nodes · 28 hidden - et le panneau de filtre développe une ligne à partir du tableau qui le nomme et peut l'effacer, donc un push n'est jamais un filtre que vous ne pouvez pas trouver une fois le dock replié.
Le push atterrit comme un filtre unique sous une touche réservée, ce qui signifie qu'il compose avec le panneau de filtres plutôt que de rivaliser avec lui : rien de ce que vous définissez dans la forme propre de ce panneau n'entrave jamais un push, et un push n'efface jamais les filtres du panneau. Les deux sont combinés, donc un nœud doit survivre aux deux.
Passez filterGraph: false pour un dock dont les commandes ne peuvent jamais toucher le canevas :
const options = {
UI: { mode: 'full', table: { filterGraph: false } },
}Sélection de
| Geste | Effet |
|---|---|
| Cliquez sur une ligne | Sélectionnez cet élément |
| Ctrl / Cmd-clic | Ajouter ou supprimer une ligne |
| Maj+clic | Prenez une plage, dans l'ordre actuellement indiqué |
| Tout sélectionner | Chaque ligne actuellement répertoriée – post-tri, post-filtre |
| Double-cliquez | Sélectionnez et centrez la toile dessus |
| Survolez | Mettez en surbrillance l'élément sur la toile |
| Clic droit | Le menu contextuel de l'élément ; une ligne d'une multi-sélection ouvre la fenêtre de la sélection |
Cela fonctionne dans les deux sens : élastiquez un groupe sur le canevas et les lignes correspondantes sont marquées et défilées. La sélection est la même que celle lue par les actions groupées de la barre latérale, de sorte que la boucle se ferme sans aucun câblage supplémentaire.
Les lignes masquées sont sélectionnées comme les autres — c'est le but de les lister.
Colonnes
Sans columns déclaré, le dock s'en charge pour vous, en trois niveaux :
- Déclaré —
UI.table.columnsgagne carrément. - De vos facettes — sinon, si vous avez déclaré
UI.filter.facets, les colonnes sont construites à partir d'elles. Décrivez vos données une fois et le panneau de filtrage et le tableau sont d'accord à ce sujet. - Scanned — sinon les données sont lues, classées par coverage de sorte que les clés bien remplies viennent en premier et la queue clairsemée se trouve à l'extrême droite.
Quoi qu'il en soit, les colonnes prenant en charge les graphiques enveloppent les données. Pour les nœuds, Visibility et Label mènent – une gouttière d'état et le nom, les deux choses que vous parcourez pour trouver une ligne – rejoints par Cluster sur un graphique qui a des clusters, puisqu'un imbriqué row en a besoin pour dire d'où il vient. Les comptes le ferment : Degree, plus Children sur un graphique comportant des clusters. Les décomptes se trouvent à la fin car ils correspondent à l'arithmétique du graphique plutôt qu'aux données propres à l'élément, et ce sont des colonnes étroites à largeur fixe, de sorte que quelques chiffres ne prennent jamais la part de la ligne dont un nom a besoin. Les bords conservent la même gouttière Visibility puis se lisent comme une phrase — Source / Label / Target.
Le tri par défaut est la colonne Label, pas la première : le tri par Visibility à l'ouverture ne vous dit rien alors que chaque ligne indique toujours visible.
Tout est affiché par défaut et la grille défile latéralement plutôt que de laisser tomber quoi que ce soit. Sur les nœuds riches en propriétés, utilisez le sélecteur Columns pour désactiver ce dont vous n'avez pas besoin - ce qui supprime également son contrôle de filtre de l'en-tête.
Les colonnes dérivées sont filtrables. Leurs étiquettes, leurs types et leur alignement sont tous déjà déduits, et le filtre de ligne est déduit de ce même type — donc une table que vous n'avez jamais configurée est une table que vous pouvez toujours affiner. Les colonnes déclarées sont à l'opposé : vous obtenez exactement l'ensemble que vous avez écrit, filterable: false sauf indication contraire.
Les colonnes intégrées
tableColumns contient les colonnes qu'aucune grille générique ne pourrait calculer, car elles concernent la place d'un élément dans le graphique plutôt que ses données :
import { Pivotick, tableColumns } from 'pivotick'
new Pivotick(el, data, {
UI: {
mode: 'full',
table: {
open: true,
// Reference a built-in's key through the object rather than typing it —
// the key itself is namespaced so it can never clash with a data key.
sort: { key: tableColumns.degree.key, direction: 'desc' },
columns: [
tableColumns.visibility,
{ ...tableColumns.degree, label: 'Links' },
tableColumns.label,
{ key: 'severity', label: 'Severity', type: 'numberRange', filterable: true },
],
},
},
})label · degree · degreeIn · degreeOut · visibility · pinned · children · cluster, plus source et target pour les bords. Clonez-en un pour l’ajuster, comme ci-dessus.
Un TableColumn est un FilterFacet avec quelques extras de présentation (width, align, sortable, filterable, hidden, format), c'est pourquoi une facette peut être utilisée comme colonne inchangée.
Exporter
Les boutons CSV et JSON écrivent exactement ce que vous regardez : cet onglet, ces colonnes visibles dans cet ordre, ce tri, ce filtre de ligne. Valeurs brutes, jamais la sortie format d'une colonne, donc le fichier reste lisible par la machine.
Pas tout le graphique - c'est graph.getNodes() pour toute personne possédant du code. Passez export: false pour laisser les boutons de côté.
Téléchargements dans une page intégrée
Une iframe en bac à sable peut bloquer complètement un téléchargement. Lorsque cela se produit, le dock le dit plutôt que de laisser un bouton qui semble ne rien faire.
Échelle
Au-dessus de virtualizeAbove lignes (200 par défaut), les lignes sont fenêtrées : seul ce qui correspond à la fenêtre d'affichage plus une marge est dans le DOM, tandis que la barre de défilement mesure toujours l'ensemble de données. Le tri réorganise le tableau sous-jacent, jamais le DOM, et une reconstruction conserve à la fois votre position de défilement et votre sélection.
En dessous du seuil, chaque ligne est rendue, ce qui simplifie l'inspection du cas ordinaire.
Options
| Options | Valeur par défaut | Ce que ça fait |
|---|---|---|
enabled | true | false (ou UI.table: false) supprime entièrement le dock |
tabs | ['nodes', 'edges'] | Les propres vues de la table. On ne rend aucune bande intérieure |
columns / edgeColumns | dérivé | Voir Colonnes |
open | désarmé | Unset commence plié à la barre ; true commence à être développé ; false ne laisse aucun quai (Shift+T l'apporte toujours) |
collapsed | plié | Plié à sa barre d'en-tête. Avec open: true, 'auto' suit la chambre disponible jusqu'à ce que vous choisissiez vous-même |
height | 0.35 | Un nombre de pixels ou une fraction de la toile. Serré pour que la toile garde un minimum utilisable |
sort | la colonne Label | { key, direction } |
rowActivate | 'select' | 'selectAndCenter' déplace également le canevas ; 'none' rend les lignes inertes |
filterGraph | true | Offre Appliquer au graphique. false pour un dock qui ne pourra jamais filtrer le canevas |
nested | true | Répertoriez le contenu d'un cluster sous forme de lignes distinctes. Voir Nœuds à l'intérieur des clusters |
export | ['csv', 'json'] | false masque les boutons |
virtualizeAbove | 200 | Nombre de lignes au-dessus desquelles les lignes sont fenêtrées |
Le quai contient plus que la table
Le tableau est un volet dans le dock, et tout ce que vous enregistrez en est un autre :
const dispose = graph.UIManager.addDockTab({
label: 'Audit',
render: () => myAuditPane(), // called once, the first time the pane is opened
toolbar: () => [clearButton], // rebuilt on every activation
})La bande du quai indique alors Table │ Audit. La commutation permute le corps et des contrôles d'en-tête, puisque Select all, les exportations et Columns appartiennent à la table et ne signifient rien sur un autre volet. Un volet ne restitue aucune bande – rien ne doit pointer vers un commutateur avec un seul paramètre.
La table n'est pas un cas particulier : elle passe par le même addDockTab, donc un volet que vous enregistrez est son égal plutôt que son invité. order le place (des ordres égaux conservent l'ordre d'enregistrement, et un volet enregistré plus tard - comme c'est toujours le cas pour un plugin - atterrit après celui intégré). Le broyeur retourné l'enlève.
Il y a une région, donc une hauteur et un pli, quel que soit le nombre de volets qu'elle contient. Deux panneaux ne peuvent pas chacun constituer une bande redimensionnable et se battre pour la toile.
Un volet peut donc être ajouté sans être affiché : il rejoint le bandeau, barre pliée comprise, et attend d'être cliqué. activateDockTab est l'acte séparé consistant à en amener un à l'avant, et la seule chose qui déplie le quai.
Deux niveaux de commutation et pourquoi ils sont différents
Nodes et Edges sont les onglets de la table, pas ceux du dock. Il s'agit de deux vues d'un seul volet, elles ne sont donc pas répertoriées à côté de Audit — cela voudrait dire qu'une vue du tableau et un volet séparé sont le même genre de chose.
Les deux niveaux sont dessinés différemment afin qu'ils puissent être placés l'un à côté de l'autre tout en restant lisibles comme un extérieur et un intérieur :
| On dirait | Classe | |
|---|---|---|
Table │ Audit | onglets pleine hauteur, soulignés lorsqu'ils sont actifs, fermés par une règle | pvt-dock-tabs / pvt-dock-tab |
Nodes │ Edges | un petit groupe de pilules segmenté | pvt-dock-views / pvt-dock-view |
Un volet avec ses propres vues fait ce que fait la table : dessinez le commutateur dans son toolbar et appelez refresh() sur sa poignée pour changer de corps. Les classes internes sont publiques, votre commutateur est donc celui intégré plutôt que sa reformulation :
function viewSwitch(current, pick) {
const strip = document.createElement('div')
strip.className = 'pvt-dock-views'
for (const view of VIEWS) {
const button = document.createElement('button')
button.className = 'pvt-dock-view'
button.textContent = view.label
button.classList.toggle('active', view.key === current)
button.addEventListener('click', () => pick(view.key))
strip.appendChild(button)
}
return strip
}
graph.UIManager.addDockTab({
label: 'Audit',
toolbar: (pane) => [viewSwitch(current, (key) => { current = key; pane.refresh() })],
render: () => renderCurrentView(),
})Les deux niveaux prennent leur accent actif de --pvt-theme-primary, donc un consommateur qui conserve le thème conserve le dock avec celui-ci ; remplacez l’une ou l’autre classe pour aller plus loin.
refresh() n'est pas une politesse facultative - le dock conserve l'élément render, donc un volet qui a échangé son propre DOM laisserait le dock rattacher un nœud obsolète la prochaine fois qu'il passerait au premier plan.
Voir la carte de galerie Ajouter un volet de dock pour une version en direct et Plugins pour l'itinéraire du plugin.
UI.dock — les paramètres propres à la région
open, collapsed et height décrivent la region, pas la table, et UI.dock est l'endroit où ils appartiennent :
// A dock holding only a plugin's pane, open on load
UI: { mode: 'full', table: false, dock: { open: true, height: 0.3 } }UI.table comporte toujours les trois mêmes paramètres et l'a toujours fait ; ceux-ci sont honorés et UI.dock gagne là où les deux sont définis. Atteignez UI.dock lorsque la table est éteinte - c'est la seule porte vers un dock qu'un onglet de plugin apporte avec lui.
Contrôle programmatique
graph.openTable()
graph.closeTable()
graph.toggleTable()Chacun est un non-op lorsqu'il n'y a pas de dock (n'importe quel mode sauf full ou UI.table: false). openTable() amène également le volet de la table au premier plan, donc un appel nommé pour la table vous en montre un. Pour conduire la région sans ça :
graph.UIManager.dock?.setOpen(true) // the region
graph.UIManager.activateDockTab('table') // a pane, unfolding the dock if need be
graph.UIManager.getDockTabs() // what is registered, in strip orderLe dock pilote l'API de sélection ordinaire, donc tout ce qui lit une sélection voit ce que la table a construit :
graph.selectElements([nodeA, nodeB]) // replaces the selection
graph.addToSelection([nodeC]) // nodes only
graph.removeFromSelection([nodeA])Redimensionner et plier
Faites glisser le séparateur le long du bord supérieur du dock pour le redimensionner. La toile conserve un sol quoi que vous demandiez : une toile sans hauteur n'est pas un graphique.
Le chevron d'effondrement plie le quai jusqu'à sa barre d'en-tête. Laissé seul, collapsed: 'auto' prend cette décision à votre place et replie le dock sur une disposition trop courte pour lui et pour une toile utilisable ; la première fois que vous le réduisez ou l'agrandissez à la main, ou que vous faites glisser le séparateur, il cesse de décider et vous le laisse.
La barre pliée nomme toujours ses volets et les contrôles actifs y restent - le nombre de lignes du tableau, une revue pivot indiquant qu'elle est en cours de récupération. C'est ce qui permet à une vitre d'arriver alors que le dock est plié et de se faire remarquer sans prendre l'écran pour le dire. Cliquer sur un volet ouvre le dock dessus.
Une vitre qui déplie le quai pour s'afficher rend la région lorsqu'elle est retirée, donc une vitre qui va et vient laisse un quai fermé fermé. Le plier, le redimensionner ou passer à un autre volet met fin à cela : chacune est une décision qui vous appartient concernant la région, et rien ne l'annule en votre nom.
L'ouverture du dock ne déplace jamais le graphique
La simulation s'adapte au conteneur, pas au canevas, donc l'ouverture et la fermeture de Chrome ne peuvent pas modifier une mise en page. Redimensionnez le dock autant que vous le souhaitez : le graphique reste en place et une nouvelle disposition donne le même résultat avec le dock ouvert ou fermé.