跳转到内容

界面选项 ​

Pivotick 在图表顶部提供灵活的 UI 层,允许您控制用户与节点、边和画布交互的方式。使用 UI 选项,您可以:

  • 配置 UI 的整体 mode(完整、查看器、静态等)。
  • 自定义 sidebar 和面板以显示属性或额外信息。
  • 为节点和边定义 tooltips,并使用可选的自定义渲染器。
  • 为节点、边和画布配置 上下文菜单。
  • 声明 filter 面板的构面,或者让它们从您的数据中派生。
  • 将 legend 停靠在画布上 - 颜色的键,兼作过滤器,当您的颜色由声明的节点类型解释时,它会单独出现。
  • 根据您按需获取的数据,异步填充这些表面 ****。
  • 关闭您的集成没有用的任何功能。
  • 将库自己的文本转换为用户的语言:请参阅翻译 UI。

用户界面模式 ​

mode 选项控制图形 UI 的整体行为和交互级别。

  • full默认:完整的 UI,启用所有面板、菜单和交互。
  • light:启用基本交互的最小 UI。
  • viewer:仅允许导航图形(平移、缩放、拖动),而不显示任何 UI 面板。
  • static:静态图,没有UI面板或交互;该图是只读的。

对于 Pivotick 的图像样式用法,请使用以下内容:

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

其他UI组件可以通过各自的命名空间进行配置

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

full模式控制面 ​

在full模式下,镶边是模式驱动的布局:左侧模式导轨(选择/创建/查看/物理),用于活动指针模式的上下文工具面板,两个设置弹出窗口 - View(画布背景和开关)和Physics(布局 + 模拟)— 顶栏(搜索、过滤、注释、撤消/重做)、选择侧边栏(属性、构面、邻居和批量操作行)以及右侧视口Rail(适合居中、缩放、设置、全屏),以及位于空闲右下角的迷你地图,当画布太小而无法节省空间时(UI.minimap: false无法放下它),它会自行折叠起来。 light模式掉落侧边栏和小地图; viewer 仅保留视口导轨; static是一块裸露的画布。

从角落镀铬迁移

浮动的 GraphControls 和 GraphToolbar 覆盖层已被移除。布局和物理移至物理弹出按钮 (UIManager.physicsFlyout) - 它们在 1.5.0 中包含在视图弹出按钮 (UIManager.viewFlyout) 中,现在包含画布背景和网格开关。在工具面板 (UIManager.toolPanel) 和模式轨 (UIManager.modeRail) 中实时选择/创建工具。 UI.selectionMenu 选项已消失 - 使用 contextMenu 进行每个节点操作,使用侧边栏批量操作行进行多选操作。 UIManager.graphNaviation更名为graphNavigation。 UI.modeRail 选项及其禁用的 Explore / Enrich 插槽已被删除 - 使用 addRailMode 注册实模式。参见CHANGELOG。

Rail 内置了四种模式,但不是它可以容纳的唯一模式:插件添加了自己的 addRailMode,这就是构建了解 your 数据含义的探索或丰富模式的方式。

关闭功能 ​

UI 模式决定图表获得多少镶边。 Chrome 中的每一项功能也可以一次关闭一项,这就是集成如何删除其后端或用户不需要的功能的方式。

关闭的功能需要一切:按钮、面板、上下文菜单条目和键盘快捷键都在一起,所以没有留下任何东西可以点击或按下并悄悄拒绝。

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

开关 ​

选项搭配什么
UI.topBar.enabled顶部条带,其保留的高度,其控件拥有的快捷方式(Shift+J,Shift+K,Shift+N,Mod+Z)以及任何主机操作。使用下面的开关放下一颗药丸并保留其余的。
UI.search.enabled搜索丸,它的节点选择器和Shift+J。
UI.filter.enabledFilter Graph 药丸、其面板和 Shift+K。 graph.queryEngine 仍然从代码中过滤。
UI.notes.enabled注释药丸和面板、Shift+N、添加注释工具、画布菜单的添加注释、N、注释上下文菜单和noteManager.addNote(拒绝)。
UI.history.enabled撤消/重做按钮、历史记录下拉列表和 Mod+Z / Mod+Shift+Z。 graph.history 继续录音。
UI.inspector.enabled节点菜单的“检查属性”条目和I。
UI.notifications.enabled干杯。 graph.notifier.* 变为无操作返回undefined。
UI.sidebar.enabled整个侧柱,以及它所占用的宽度。
UI.propertiesPanel.enabled侧边栏的属性面板及其分隔符。
UI.neighborsPanel.enabled侧边栏的相邻面板及其分隔符。
UI.viewFlyout.enabled查看栏按钮及其面板。
UI.physicsFlyout.enabled物理轨道按钮及其面板。
UI.tooltip.enabled悬停工具提示,包括固定的工具提示。还需要 { nodes, edges, groups } 或 (element, kind) => boolean,请参阅工具提示。
UI.contextMenu.enabled每个上下文菜单。
UI.navigation.enabled视口导轨:适合、缩放和全屏。
UI.legend: false画布图例,包括它自己衍生的图例。
UI.minimap: false小地图。
UI.emptyState: false空画布 显示卡片。
UI.table: false数据码头及其Shift+T。
UI.pivotMode: false拓展轨道模式,无论注册什么。

写入路径功能在 UI.editors 下具有相同的开关,因此只读集成会删除可供性,而不是否决每次点击:nodeCreator、edgeCreator、nodeEditor、edgeEditor 和 deletion。

渲染器行为在 render 下关闭:zoomEnabled(也使用轨道的缩放按钮,保持适合和居中)、dragEnabled、selectionBox.enabled(选框 ** 和 ** 选择 ▸ 套索工具)、enableNodeExpansion(V 形、其 Enter 和虚线折叠轮廓)、enableFocusMode和interactionEnabled同时显示所有内容。 simulation.enabled stops the layout from running.

创建模式遵循其工具

创建轨道模式仅包含四个工具:添加节点、添加边缘、添加注释和编辑节点。关闭所有四个,模式将离开导轨及其 C 快捷方式,而不是打开到空面板。选择始终保留。

顶部栏中您自己的操作 ​

整个画布上的操作(例如保存画布)属于撤消/重做组旁边的顶部栏中。 UI.topBar.actions 声明以与“搜索”、“过滤器”和“注释”相同的样式绘制药丸,因此重新设计这些样式的主题也会重新设计它们。

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 }]
                    : [],
            }],
        },
    },
}
  • Where. placement: 'end'(默认)将药丸放在撤消重做组之前; 'start'放在左边内置药丸后面。 Pills keep the order they were declared in.
  • 它说的是什么。text、title、visible和enabled采用图形的值或函数。每次数据更改后,在 graph.UIManager.refreshTopBar() 上,并且一旦 onclick 返回的 Promise 解决后,都会再次读取这些函数。虽然这个承诺已经兑现,但药丸已被禁用,因此缓慢的保存不能启动两次。
  • 它得到什么。onclick(event, ctx)接收图形和两个打开库模态的帮助器:ctx.promptData({ fields })在取消时解析为值或null,ctx.confirm({ body })仅在确认按钮上解析true。 ctx.refresh() 重读每一个动作。
  • 插入符号。 使用 menu,药丸将成为拆分按钮:标签运行 onclick,并且插入符号打开行,其行格式与 上下文菜单(无子菜单)相同。函数形式被赋予相同的ctx,并在每次刷新和每次打开时调用;虽然它不返回任何行,但该药丸没有插入符号。 Escape or a click elsewhere closes the rows.
  • 快捷方式。shortcut在药丸上画一个徽章。它只是一个标签:您自己注册绑定。

插件添加了一个带有 ctx.addTopBarAction(action) 的药丸,它返回一个处理器(参见 Plugins)。药丸遵循条带:没有 viewer 或 static 模式,也没有 UI.topBar.enabled: false 模式。

空画布 ​

没有节点和注释的图表会在画布中间显示一张卡片,因此没有任何可绘制内容的源不会被读取为无法加载的图表。它会说“画布上还没有任何内容”,除非你给它别的东西要说:

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

卡遵循数据。添加一个节点或注释会将其删除,然后手动删除最后一个或通过撤消带来它们的摄取,将其恢复。过滤器隐藏的节点仍然计数:图形变窄,而不是空的。

render 每次卡片出现时都会运行,而不是在卡片出现时每次更改时运行。 initial 是true,直到图表包含一个节点,因此清空整个画布的分析师可以被告知除空源之外的其他信息。返回的字符串呈现为纯文本,并且render可能是async,就像下面的钩子一样。

该卡片使用了镀铬的表面和边框,因此它遵循主题。它允许画布的手势通过,因此平移、缩放和画布菜单可以在其上工作,但交互内容除外:按钮、链接、表单控件或带有 tabindex 的任何内容都有自己的点击。 UI.emptyState: false什么也没显示。

异步内容 ​

每个消费者提供的内容挂钩都可能返回 Promise 而不是内容本身。涵盖侧边栏的 mainHeader.render、propertiesPanel.render / nodePropertiesMap / edgePropertiesMap、neighborsPanel.render、额外面板的 title 和render、工具提示的、render、renderNodeExtra、renderEdgeExtra和属性图,以及空画布的render。

这种情况存在于以下情况:节点的数据是记录的引用,而不是记录本身,并且有趣的内容位于 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
            },
        },
    },
}

添加async,转发signal,库会处理剩下的事情:

占位符当承诺悬而未决时,一个主题骨架占据了这个位置。
交换解析时,内容将替换适当的占位符。
陈旧在其槽消失后到达的结果 - 您将鼠标悬停在另一个节点上,更改了选择,刷新了面板 - 是dropped。只有表面的最新渲染才能提交,无论它们解析的顺序如何。
取消当渲染被取代或图表被拆除时,ctx.signal 会中止,因此转发的 fetch 会被取消而不是泄漏。
失败被拒绝的 Promise 会呈现一个紧凑的错误行,而不是永远留下一个旋转器。中止的渲染并不是失败,也不会显示任何内容。

渲染上下文 ​

每个内容挂钩都会接收 RenderContext 作为其 last 参数。现有的同步钩子只是忽略它。

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

自定义占位符 ​

UI.asyncContent 覆盖待处理和失败时显示的内容。两者都接受一个字符串、一个 HTMLElement 或一个曲面函数:

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

surface是'tooltip'、'properties'、'neighbors'、'mainHeader'、'extraPanel'或'emptyState'之一。

同步钩子未受影响

直接返回内容的行为与往常一样 - 相同的调用、相同的框架、没有占位符和包装元素。现有集成没有任何变化。

什么不能是异步的

两组有意保持同步:

  • HeaderMapEntry.title / subtitle 提供自动调整标题槽和节点搜索(resolveNodeByName),两者现在都需要文本。如果您需要在标头中获取详细信息,请使用异步mainHeader.render。
  • PropertyEntry.name / value — 改为获取行:异步 nodePropertiesMap 解析一次,然后返回普通条目,而不是在每个单元格中放置一个旋转器。

每帧渲染器挂钩(render.renderNode、renderLabel、renderCluster 和 NodeStyle.html)也是仅同步的:它们在每个节点、每个刻度的绘制路径内运行。如果您需要异步节点decoration,请获取节点的数据并让同步渲染器读取它。