Ir al contenido

Opciones de interfaz de usuario ​

Pivotick proporciona una capa de interfaz de usuario flexible encima de su gráfico, lo que le permite controlar cómo los usuarios interactúan con los nodos, los bordes y el lienzo. Usando las opciones UI, puedes:

  • Configure el modo general de la interfaz de usuario (completa, visor, estática, etc.).
  • Personalice sidebar y los paneles para mostrar propiedades o información adicional.
  • Defina tooltips para nodos y bordes, con renderizadores personalizados opcionales.
  • Configure menús contextuales para nodos, bordes y el lienzo.
  • Declare las facetas del panel filter o permita que se deriven de sus datos.
  • Coloque una legend en el lienzo: una clave para sus colores que también funciona como filtro y que aparece por sí sola cuando sus colores se explican mediante un tipo de nodo declarado.
  • Complete cualquiera de esas superficies asincrónicamente, a partir de los datos que recupera a pedido.
  • Desactiva cualquier característica que tu integración no sirva para nada.
  • Coloque el texto propio de la biblioteca en el idioma de sus usuarios: consulte Traducción de la interfaz de usuario.

Modo de interfaz de usuario ​

La opción mode controla el comportamiento general y el nivel de interacción de la interfaz de usuario del gráfico.

  • full predeterminado: interfaz de usuario completa con todos los paneles, menús e interacciones habilitados.
  • light: interfaz de usuario mínima con interacciones esenciales habilitadas.
  • viewer: solo permite navegar por el gráfico (desplazar, hacer zoom, arrastrar) sin mostrar ningún panel de interfaz de usuario.
  • static: gráfico estático, sin paneles de interfaz de usuario ni interacciones; el gráfico es de sólo lectura.

Para el uso de estilo de imagen de Pivotick, use lo siguiente:

ts
const container = document.getElementById('graph-container')
const options = {
    UI: {  
        mode: 'viewer'
    },
}
const graph = Pivotick(container, options)

Otros componentes de la interfaz de usuario se pueden configurar a través de su respectivo espacio de nombres.

ts
const options = {
    UI: { 
        sidebar: {},
        mainHeader: {},
        propertiesPanel: {},
        extraPanels: [],
        tooltip: {},
        contextMenu: {},
        filter: {},
    }
}

La superficie de control del modo full ​

En el modo full, el cromo es un diseño basado en modos: un carril de modo ** izquierdo** (Seleccionar / Crear / Ver / Física), un panel de herramientas contextual para los activos modo puntero, dos menús laterales de configuración: Ver (fondo del lienzo y interruptores) y Física (diseño + simulación) — la barra superior (búsqueda, filtro, notas, deshacer/rehacer), la selección barra lateral (propiedades, facetas, vecinos y una fila de acción masiva), y un carril de ventana gráfica del lado derecho (ajuste y centrado, zoom, configuración, pantalla completa) y un minimapa en la esquina inferior derecha libre, que se pliega cuando el lienzo es demasiado pequeño para dejar espacio en la habitación (UI.minimap: false para dejarlo caer). light el modo elimina la barra lateral y el minimapa; viewer mantiene solo el riel de la ventana gráfica; static Es un lienzo desnudo.

Migrando desde la esquina cromada

Se eliminaron las superposiciones flotantes GraphControls y GraphToolbar. Diseño y la física pasó al menú lateral Física (UIManager.physicsFlyout): se enviaron en el Ver menú lateral (UIManager.viewFlyout) en 1.5.0, que ahora contiene el fondo del lienzo y la red cambia. Seleccionar/Crear herramientas en vivo en el panel de herramientas (UIManager.toolPanel) y modo carril (UIManager.modeRail). el La opción UI.selectionMenu desapareció: use contextMenu para acciones por nodo y el fila de acción masiva de la barra lateral para acciones de selección múltiple. UIManager.graphNaviation era renombrado a graphNavigation. La opción UI.modeRail y está deshabilitada Explore / Enrich se eliminaron las ranuras: registre un modo real con addRailMode en su lugar. Ver el CHANGELOG.

Los cuatro modos del riel están integrados, pero no son los únicos que puede contener: un complemento agrega su propio con addRailMode, que es como un modo Explorar o Enriquecer que sabe lo que significan tus datos.

Desactivar funciones ​

El modo UI decide cuánto cromo obtiene un gráfico. Cada característica dentro de ese cromo También se pueden desactivar uno a la vez, que es la forma en que una integración elimina lo que es backend o sus usuarios no tienen ningún uso.

Una característica apagada toma todo que llega a ella: el botón, el panel, la entrada del menú contextual y el método abreviado de teclado van juntos, por lo que no queda nada detrás para hacer clic o presionar y negarse silenciosamente.

ts
const options = {
    UI: {
        mode: 'full',
        notes: { enabled: false },        
        history: { enabled: false },
        inspector: { enabled: false },
        editors: { deletion: { enabled: false } },
    },
}

los interruptores ​

Opción¿Qué va con eso?
UI.topBar.enabledLa franja superior, la altura que reservó, los accesos directos que poseen sus controles (Shift+J, Shift+K, Shift+N, Mod+Z) y cualquier acciones de host. Utilice los interruptores a continuación para dejar caer una pastilla y conservar el resto.
UI.search.enabledLa píldora de búsqueda, su selector de nodos y Shift+J.
UI.filter.enabledLa píldora Filter Graph, su panel y Shift+K. graph.queryEngine todavía filtra del código.
UI.notes.enabledLa píldora y el panel de Notas, Shift+N, la herramienta Agregar nota, Agregar nota del menú del lienzo, N, el menú contextual de notas y noteManager.addNote, que se niega.
UI.history.enabledLos botones deshacer/rehacer, su menú desplegable de historial y Mod+Z/Mod+Shift+Z. graph.history continúa grabando.
UI.inspector.enabledLa entrada Inspeccionar propiedades del menú del nodo y I.
UI.notifications.enabledBrindis. graph.notifier.* se convierte en un no operativo que regresa a undefined.
UI.sidebar.enabledToda la columna lateral y el ancho que ocupaba.
UI.propertiesPanel.enabledEl panel de propiedades de la barra lateral y su separador.
UI.neighborsPanel.enabledEl panel vecino de la barra lateral y su separador.
UI.viewFlyout.enabledEl botón Ver carril y su panel.
UI.physicsFlyout.enabledEl botón del carril Física y su panel.
UI.tooltip.enabledInformación sobre herramientas al pasar el cursor, incluidas las fijadas. También toma { nodes, edges, groups } o (element, kind) => boolean, consulte Información sobre herramientas.
UI.contextMenu.enabledCada menú contextual.
UI.navigation.enabledEl carril de la ventana gráfica: ajuste, zoom y pantalla completa.
UI.legend: falseLa leyenda del lienzo, incluida la que derivaría por sí misma.
UI.minimap: falseEl minimapa.
UI.emptyState: falseLa tarjeta muestra un lienzo vacío.
UI.table: falseEl muelle de datos y su Shift+T.
UI.pivotMode: falseLa modalidad ferroviaria Pivot, cualquiera que esté registrado.

Las funciones de ruta de escritura tienen el mismo interruptor en UI.editors, por lo que una función de solo lectura La integración elimina la posibilidad de acceso en lugar de vetar cada clic: nodeCreator, edgeCreator, nodeEditor, edgeEditor y deletion.

El comportamiento del renderizador se desactiva en render: zoomEnabled (que también toma los botones de zoom del riel, manteniendo el ajuste y el centro), dragEnabled, selectionBox.enabled (el marco y la herramienta Seleccionar ▸ Lazo), enableNodeExpansion (el galón, su Enter y el guión colapsado esquema), enableFocusMode, y interactionEnabled para todo a la vez. simulation.enabled detiene el diseño de correr.

El modo Crear sigue sus herramientas.

El modo Crear carril contiene exactamente cuatro herramientas: Agregar nodo, Agregar borde, Agregar nota y Editar. nodo. Apaga los cuatro y el modo sale del carril, junto con su atajo C, en lugar de abrirse a un panel vacío. Seleccionar siempre permanece.

Tus propias acciones en la barra superior ​

Una acción en todo el lienzo, como guardarlo, pertenece a la barra superior al lado del grupo deshacer-rehacer. UI.topBar.actions declara pastillas dibujadas con el mismo estilo que la Búsqueda, Filtro y Notas, por lo que un tema que cambia el estilo de esos también cambia el estilo de estos.

ts
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 }]
                    : [],
            }],
        },
    },
}
  • Dónde. placement: 'end' (el valor predeterminado) coloca la pastilla justo antes de deshacer-rehacer grupo; 'start' lo coloca después de las pastillas incorporadas a la izquierda. Las pastillas mantienen el orden. fueron declarados en.
  • Lo que dice. text, title, visible y enabled toman un valor o una función de el gráfico. Las funciones se leen de nuevo después de cada cambio de datos, en graph.UIManager.refreshTopBar(), y una vez que se liquida una promesa devuelta por onclick. Mientras esa promesa esté vigente, la píldora estará desactivada, por lo que no se puede iniciar un guardado lento dos veces.
  • Lo que obtiene. onclick(event, ctx) recibe el gráfico y dos ayudantes que abren el modal de la biblioteca: ctx.promptData({ fields }) se resuelve en los valores o null en cancelar y ctx.confirm({ body }) resuelve true solo en el botón de confirmación. ctx.refresh() relee cada acción.
  • Un cursor. Con menu, la pastilla se convierte en un botón dividido: la etiqueta dice onclick, y un cursor abre las filas, en el mismo formato de fila que los menús contextuales (sin submenús). Una forma de función se entrega de la misma manera ctx y se llama en cada actualizar y cada apertura; Si bien no devuelve filas, la píldora no tiene ningún signo de intercalación. escapar o un hacer clic en otro lugar cierra las filas.
  • Un atajo. shortcut dibuja una insignia en la pastilla. Es sólo una etiqueta: registre el atándote a ti mismo.

Un complemento agrega una pastilla con ctx.addTopBarAction(action), que devuelve un triturador (ver Complementos). Las pastillas siguen la tira: ninguna en viewer o static modo, y ninguno con UI.topBar.enabled: false.

Un lienzo vacío ​

Un gráfico sin nodos ni notas muestra una tarjeta en el medio del lienzo, por lo que una fuente sin nada que dibujar no se lee como un gráfico que no se pudo cargar. Dice "Nada en el lienzo todavía" a menos que le des algo más que decir:

ts
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
            },
        },
    },
}

La tarjeta sigue los datos. Agregar un nodo o una nota lo elimina y eliminar el último de ellos, con la mano o deshaciendo la ingesta que los trajo, lo trae de vuelta. Nodos el Los filtros ocultan el recuento aún: el gráfico se reduce, no está vacío.

render se ejecuta cada vez que aparece la tarjeta, no en cada cambio mientras está activa. initial es true hasta que el gráfico haya mantenido un nodo, por lo que un analista que vació un lienzo completo puede que se le diga algo distinto de lo que se le dice a una fuente vacía. Una cadena devuelta se representa como texto sin formato, y render puede ser async como los ganchos a continuación.

La tarjeta utiliza la superficie y el borde del cromo, por lo que sigue el tema. Le permite al los gestos del lienzo, por lo que la panorámica, el zoom y el menú del lienzo funcionan en él, excepto sobre contenido interactivo: un botón, un enlace, un control de formulario o cualquier cosa con un tabindex obtiene sus propios clics. UI.emptyState: false no muestra nada en absoluto.

Contenido asincrónico ​

Cada gancho de contenido proporcionado por el consumidor puede devolver un Promise en lugar del contenido en sí. Eso cubre la barra lateral. mainHeader.render, propertiesPanel.render / nodePropertiesMap / edgePropertiesMap, neighborsPanel.render, un panel adicional title y render, la información sobre herramientas render, renderNodeExtra, renderEdgeExtra y mapas de propiedades, y el lienzos vacíos render.

Esto existe para el caso en el que los datos de un nodo son una referencia a un registro en lugar de que el registro en sí, y el contenido interesante está detrás de una llamada HTTP:

ts
const options = {
    UI: {
        tooltip: {
            renderNodeExtra: async (node, { signal }) => { 
                const res = await fetch(`/enrich/${node.getData().uuid}`, { signal })
                return renderChips(await res.json())       // an HTMLElement
            },
        },
    },
}

Agregue async, reenvíe signal y la biblioteca se encarga del resto:

Marcador de posiciónMientras la promesa está pendiente, un esqueleto temático ocupa la ranura.
IntercambiarAl resolverse, el contenido reemplaza el marcador de posición existente.
EstancamientoUn resultado que llega después de que su espacio ha desaparecido (colocó el cursor sobre otro nodo, cambió la selección, actualizó el panel) es eliminado. Solo se puede confirmar el renderizado más reciente de una superficie, independientemente del orden en que se resuelvan.
Cancelaciónctx.signal se cancela cuando se reemplaza un renderizado o se elimina el gráfico, por lo que un fetch reenviado se cancela en lugar de filtrarse.
FalloUna promesa rechazada genera una línea de error compacta en lugar de dejar una rueda giratoria para siempre. Un renderizado abortado no es un error y no muestra nada.

El contexto de renderizado ​

Cada gancho de contenido recibe un RenderContext como su último argumento. Los ganchos sincrónicos existentes simplemente lo ignoran.

ts
render: async (element, { signal, isStale }) => {
    const rows = await fetchRows(element, signal)
    if (isStale()) return ''            // cheap guard for non-abortable work
    return renderRows(rows)
}

Personalizando el marcador de posición ​

UI.asyncContent anula lo que se muestra mientras está pendiente y en caso de error. ambos acepte una cadena, un HTMLElement o una función de la superficie:

ts
const options = {
    UI: {
        asyncContent: { 
            placeholder: (surface) => surface === 'tooltip' ? 'Loading…' : mySkeleton(),
            error: 'Could not load',
        },
    },
}

surface es uno de 'tooltip', 'properties', 'neighbors', 'mainHeader', 'extraPanel' o 'emptyState'.

Los ganchos sincrónicos están intactos.

El contenido devuelto se comporta directamente exactamente como siempre: la misma llamada, la misma marco, sin marcador de posición ni elemento contenedor. Nada sobre un existente cambios de integración.

¿Qué no puede ser asíncrono?

Dos grupos permanecen sincrónicos a propósito:

  • HeaderMapEntry.title / subtitle alimenta la ranura de título de ajuste automático y búsqueda de nodos (resolveNodeByName), los cuales necesitan el texto ahora. Utilice un async mainHeader.render si necesita obtener detalles en el encabezado.
  • PropertyEntry.name / value - busca las filas en su lugar: un asíncrono nodePropertiesMap resuelve una vez y luego devuelve las entradas simples, en lugar de que poner una ruleta en cada celda.

Los ganchos del renderizador por cuadro (render.renderNode, renderLabel, renderCluster y NodeStyle.html) también son solo de sincronización: se ejecutan dentro de la ruta de dibujo, según nodo, por tick. Si necesita un nodo asíncrono decoración, busque los datos del nodo y deja que el renderizador síncrono lo lea.