Zum Inhalt springen

Seitenleistenoptionen ​

Die Seitenleiste kann je nach Bildschirmgröße oder Benutzerpräferenz standardmäßig reduziert werden.

Legt fest, ob die Seitenleiste standardmäßig reduziert ist.

  • 'auto' Standard: Die Seitenleiste bleibt geöffnet, es sei denn, es ist nicht genügend Platz auf dem Bildschirm vorhanden. In diesem Fall wird sie automatisch ausgeblendet.
  • true Die Seitenleiste wird minimiert.
  • false Die Seitenleiste wird erweitert.

Die Seitenleiste zeigt Kontextinformationen für Diagrammelemente an. Es verfügt über drei anpassbare Komponenten:

UI.sidebar.enabled: false löscht die gesamte Spalte und gibt ihre Breite an die Arbeitsfläche zurück. Die Eigenschaften- und Nachbarfelder verfügen jeweils über einen Schalter – UI.propertiesPanel.enabled, UI.neighborsPanel.enabled – der dieses Feld und sein Trennzeichen entfernt, während der Rest der Seitenleiste bestehen bleibt. Siehe Funktionen ausschalten.

Klicken Sie hier, um den Code anzuzeigen
js
UI: {
    mode: 'full',
    sidebar: {
        collapsed: false,
    },
    mainHeader: {
        render: (element) => {
            const div = document.createElement('div')
            div.textContent = 'Main Header'
            div.style.fontWeight = 'bold'
            div.style.color = 'darkred'
            div.style.background = 'var(--pvt-bg-color-8)'
            div.style.padding = '4px 8px'
            div.style.borderRadius = '4px'
            return div
        }
    },
    propertiesPanel: {
        render: (element) => {
            const div = document.createElement('div')
            div.textContent = 'Properties Panel'
            div.style.fontWeight = 'bold'
            div.style.color = 'darkred'
            div.style.background = 'var(--pvt-bg-color-8)'
            div.style.padding = '4px 8px'
            div.style.borderRadius = '4px'
            return div
        }
    },
    extraPanels: [
        {
            title: 'Extra panel #1',
            render: (node) => {
                const div = document.createElement('div')
                div.textContent = 'Extra Panel #1'
                div.style.fontWeight = 'bold'
                div.style.color = 'darkred'
                div.style.background = 'var(--pvt-bg-color-8)'
                div.style.padding = '4px 8px'
                div.style.borderRadius = '4px'
                return div
            },
        },
        {
            title: 'Extra panel #2',
            render: (node) => {
                const div = document.createElement('div')
                div.textContent = 'Extra Panel #2'
                div.style.fontWeight = 'bold'
                div.style.color = 'darkred'
                div.style.background = 'var(--pvt-bg-color-8)'
                div.style.padding = '4px 8px'
                div.style.borderRadius = '4px'
                return div
            },
        },
    ],
    tooltip: {
        enabled: false,
    },
    contextMenu: {
        enabled: false,
    },
},

Hauptheader Schnittstelle ​

Zeigt eine prägnante Zusammenfassung des ausgewählten Knotens oder der ausgewählten Kante, z. B. Titel und Untertitel. Es hilft Benutzern, das aktuell ausgewählte Element schnell zu identifizieren.

Der Hauptkopfbereich kann über Zuordnungsfunktionen angepasst werden. Die Standardzuordnung für einen Knoten ist

ts
{
    title:    node => node.data.label ?? "Could not resolve title"
    subtitle: node => node.data.description ?? ""
}

Sie können diese Zuordnung ändern, indem Sie die benötigten Teile überschreiben:

ts
const options = {
    UI: {
        mainHeader: {
            nodeHeaderMap: {
                title: node => `Node ${node.id}`,
                subtitle: node => node.data.type ?? "",
            }
        }
    }
}
ts
const options = {
    UI: {
        mainHeader: {
            edgeHeaderMap: {
                title: node => `Node ${node.id}`,
                subtitle: node => node.data.type ?? "",
            }
        }
    }
}
ts
const options = {
    UI: {
        mainHeader: {
            render: (element) => {
                const div = document.createElement('div')
                div.textContent = 'Main Header'
                return div 
            }
        }
    }
}

Warnung

Wenn render() bereitgestellt wird, überspringt Pivotick die gesamte Standardzuordnungslogik, es sei denn, es gibt undefined zurück. Ein undefined-Ergebnis (oder ein Versprechen, das zu undefined aufgelöst wird) zeichnet den Standardheader für diese Auswahl: den nodeHeaderMap / edgeHeaderMap-Titel für ein Element, die Auswahlanzahl für mehrere und die Arbeitsflächesumme, wenn nichts ausgewählt ist. Geben Sie null zurück, um die Kopfzeile leer zu lassen.

ts
mainHeader: {
    // A custom header for a lone element, the default counts for everything else.
    render: (element) => (element && !Array.isArray(element)) ? myHeader(element) : undefined,
}

Eigenschaftenbereich Schnittstelle ​

Zeigt detaillierte Eigenschaften des ausgewählten Knotens oder der ausgewählten Kante in der Seitenleiste an. Jede Eigenschaft hat einen Namen und einen Wert, der statisch sein oder dynamisch berechnet werden kann.

Das Standardverhalten besteht darin, alle Schlüssel/Wert-Paare von getData() des Knotens oder der Kante anzuzeigen.

Sie können anpassen, welche Eigenschaften angezeigt werden und wie sie gerendert werden, indem Sie Zuordnungsfunktionen (nodePropertiesMap und edgePropertiesMap) oder einen vollständig benutzerdefinierten Renderer verwenden.

ts
const options = {
    UI: {
        propertiesPanel: {
            nodePropertiesMap: (node: Node) => {
                return [
                    {
                        name: 'Node ID',
                        value: node.id,
                    },
                    {
                        name: (node) => `Type of node`,
                        value: (node) => el ? el.type : 'Unknown'
                    },
                    {
                        name: 'Custom HTML',
                        value: document.createElement('div')
                    }
                ]
            }
        }
    }
}
ts
const options = {
    UI: {
        propertiesPanel: {
            edgePropertiesMap: (node: Node) => {
                return [
                    {
                        name: 'Edge ID',
                        value: node.id,
                    },
                    {
                        name: (node) => `Type of edge`,
                        value: (node) => el ? el.type : 'Unknown'
                    },
                    {
                        name: 'Custom HTML',
                        value: document.createElement('div')
                    }
                ]
            }
        }
    }
}
ts
const options = {
    UI: {
        propertiesPanel: {
            render: (element: Node | Edge | Node[] | Edge[] | null) => {
                const div = document.createElement('div')
                div.textContent = `Element ID: ${element?.id}`
                div.style.fontWeight = 'bold'
                return div
            }
        }
    }
}
ts
const options = {
    UI: {
        propertiesPanel: {
            nodePropertiesMap: (node: Node) => {
                return Object.entries(node.getData())
                    .filter(([key, value]) => key && value)
                    .map(([key, value]) => ({ name: key, value }))
            }
        }
    }
}

Eine Eigenschaftenzuordnung kann mehrere Einträge mit demselben Namen zurückgeben, beispielsweise einen Tag-Eintrag pro Tag. Bei einer Mehrfachauswahl zählt jeder Wert dann die Knoten, die ihn tragen, „Behalten/Ausschließen“ stimmt mit allen Einträgen eines Knotens überein und jeder Wert erhält einen eigenen Balken, da sich die Werte überschneiden.

ts
nodePropertiesMap: (node) => node.getData().tags.map((tag) => ({ name: 'Tag', value: tag }))

Tipp

Wenn render() bereitgestellt wird, überspringt Pivotick die gesamte Standardzuordnungslogik, es sei denn, es gibt undefined zurück. Ein undefined-Ergebnis (oder ein Versprechen, das zu undefined aufgelöst wird) zeichnet das Standardpanel für diese Auswahl: die nodePropertiesMap / edgePropertiesMap-Zeilen für ein Element und die aggregierte Tabelle mit ihren Beibehalten-/Ausschlussfiltern für mehrere. Geben Sie null zurück, um das Feld leer zu lassen.

ts
const options = {
    UI: {
        propertiesPanel: {
            // A custom view for a lone node, the default aggregated table for everything else.
            render: (element) => (element instanceof Node) ? myNodeView(element) : undefined,
        }
    }
}

Nachbarn-Panel Schnittstelle ​

Zeigt die Verbindungen des ausgewählten Knotens an: ein kleines Diagramm seiner Nachbarn, Verbindungsstatistiken und eine Liste.

Das Nachbardiagramm wird standardmäßig mit den Renderoptionen des Hauptdiagramms gezeichnet. Stile, die für eine vollständige Arbeitsfläche geeignet sind, wie z. B. Knotendetailebenen oder eine Fokuskarte, können ein Panel dieser Größe überfüllen, daher nimmt graph eigene Überschreibungen an:

  • graph.render wird über die Renderoptionen des Hauptdiagramms zusammengeführt. Die eigenen Einstellungen des Panels (kein Ziehen, kein Zoom, keine Knotenerweiterung) gelten weiterhin. Ein maxZoom begrenzt hier auch, wie weit das Diagramm hineingezoomt wird, sodass ein Knoten mit einem Nachbarn nicht vergrößert wird.
  • graph.layout wird über dem radialen Layout des Panels zusammengeführt. Die Wurzel ist immer der ausgewählte Knoten.
ts
const options = {
    UI: {
        neighborsPanel: {
            graph: {
                render: {
                    // Plain small nodes: no tiers, no focus card.
                    nodeStyleMap: { event: { shape: 'circle', size: 10 } },
                    maxZoom: 1,
                },
                layout: { radialGap: 80 },
            },
        },
    },
}

Zusätzliche Panels Schnittstelle ​

Ermöglicht das Hinzufügen vollständig benutzerdefinierter Panels mit dynamischem oder statischem Inhalt. Diese Panels eignen sich ideal zum Anzeigen zusätzlicher Kontextinformationen, benutzerdefinierter Steuerelemente oder interaktiver Widgets im Zusammenhang mit dem ausgewählten Element.

Jedes zusätzliche Panel verfügt über ein optionales title und ein render(), die beide statisch (String/HTMLElement) oder eine Funktion der aktuellen Auswahl sein können. Ein zurückgegebenes string wird als text gerendert; Geben Sie eine HTMLElement zurück, um Ihr eigenes Markup zu rendern. Zurück null, um den Panelkörper leer zu lassen.

ts
const options = {
    UI: {
        extraPanels: [
            {
                title: "Info",
                render: "This is a static extra panel content"
            }
        ]
    }
}
ts
// The selection is a Node, an Edge, an array of either, or null — this example
// only cares about a single element:
const single = (element) => (element && !Array.isArray(element)) ? element : null

const options = {
    UI: {
        extraPanels: [
            {
                // Both are called with the live selection, on every selection change.
                title: (element) => single(element) ? `Node #${single(element).id}` : 'Nothing selected',
                render: (element) => {
                    const div = document.createElement('div')
                    div.textContent = single(element)?.getData().description ?? 'No description'
                    return div
                }
            }
        ]
    }
}

Die Auswahl, mit der ein Panel gerendert wird ​

title und render werden bei jeder Auswahländerung erneut aufgerufen, mit dem, was aktuell ausgewählt ist:

AuswahlArgument
Ein Knoten / eine Kantedie Node oder Edge
Mehrere Knoten/Kantena Node[] / Edge[]
Nichts ausgewähltnull

Ein Panel wird nur angezeigt, während etwas ausgewählt ist, es sei denn, es setzt alwaysVisible: true – aber ein reaktives Panel wird in beiden Fällen neu gerendert, sodass es niemals Inhalte enthält, die eine veraltete Auswahl beschreiben.

Legen Sie reactive: false für ein Panel fest, das die Auswahl nicht beschreibt und teuer in der Erstellung ist: Es wird dann einmal gerendert und nur durch ein explizites refreshPanel() neu erstellt.

Registrieren von Panels zur Laufzeit ​

UI.extraPanels ist die deklarative Form derselben Registrierung. Alles, was Sie dort deklarieren können, können Sie auch zu jedem Zeitpunkt im Leben des Diagramms über UIManager registrieren – und entfernen:

ts
const graph = new Pivotick(container, data, options)

// Register a panel that depends on the graph itself. Returns a disposer.
const dispose = graph.UIManager.addPanel({
    id: 'unlinked-items',
    title: 'Unlinked items',
    alwaysVisible: true,
    order: -1,                              // sorts above the option-declared panels
    render: (selection) => tray.render(selection),
})

// Your own data changed (a save landed) rather than the selection —
// ask for a re-render instead of hand-patching the panel's DOM.
graph.UIManager.refreshPanel('unlinked-items')

// Gone for good (equivalent to calling `dispose()`):
graph.UIManager.removePanel('unlinked-items')
Methode
addPanel(panel)Registrieren Sie ein Panel; gibt einen Entsorger zurück. id wird automatisch generiert, wenn es weggelassen wird. Funktioniert, bevor und nachdem das Diagramm fertig ist, und über install eines Plugins (als ctx.addPanel).
removePanel(id)Entfernen Sie das Panel und sein DOM.
refreshPanel(id?)Rendern Sie ein Panel oder alle neu. Aktualisiert auch reactive: false Panels.
getPanels()Die registrierten Panels in der Reihenfolge der Anzeige.

Panels werden nach order sortiert (aufsteigend, Standard 0) und die Registrierungsreihenfolge bleibt bei demselben Wert, sodass UI.extraPanels von oben nach unten liest und Laufzeitpanels danach angehängt werden.

Das eigene title / render eines Panels erhält ein zweites Argument – ein Handle für sich selbst – sodass es seine eigenen Aktualisierungen durchführen kann, ohne nach dem Diagramm greifen zu müssen:

ts
render: (selection, panel) => {
    const button = document.createElement('button')
    button.textContent = 'Reload'
    button.onclick = () => panel.refresh()   // …or panel.remove()
    return button
}

Nur in der Seitenleiste

Panels werden in der Seitenleiste angezeigt, die im full-Modus vorhanden ist. Die Registrierung gelingt in jedem Modus – das Panel kann einfach nirgendwo gerendert werden, bis eine Seitenleiste dies tut.

Ein Panel asynchron füllen ​

title und render können beide async sein, ebenso wie render / nodePropertiesMap / edgePropertiesMap im Eigenschaftenfenster und render in der Hauptüberschrift. Das Panel zeigt einen Platzhalter, während das Versprechen aussteht:

ts
graph.UIManager.addPanel({
    id: 'sightings',
    title: 'Sightings',
    render: async (selection, panel, { signal }) => {
        if (!(selection instanceof Node)) return 'Select a node'
        const res = await fetch(`/sightings/${selection.id}`, { signal })
        return renderSightings(await res.json())
    },
})

Beachten Sie die Reihenfolge der Argumente: Das Panel-Handle bleibt an zweiter Stelle und RenderContext ist immer last.

Da ein Panel bei jeder Auswahländerung neu gerendert wird, wird ein Abruf routinemäßig ersetzt, bevor er aufgelöst wird. Die Bibliothek erledigt das für Sie: Das signal des alten Renderings wird abgebrochen, und ein Ergebnis, das nach dem Verschieben der Auswahl eintrifft, wird abgelegt, anstatt in ein Panel zu zeichnen, das einen anderen Knoten beschreibt. Gleiches gilt für refreshPanel() und für das Entfernen der Blende. Den vollständigen Vertrag finden Sie unter asynchroner Inhalt.