渲染选项
Pivotick 允许您通过 render 选项自定义节点、边和标签的渲染方式。
警告
此处定义的所有样式仅在 render.type 设置为 svg 时适用。
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
type | 'svg' | 'canvas' | 'svg' | 渲染方法。 'svg' 使用SVG 元素,'canvas' 使用HTML 画布(实验性 - 未完全实现)。 |
renderNode | (node: Node) => HTMLElement | string | void | undefined | 节点的自定义渲染器。 |
renderLabel | (edge: Edge) => HTMLElement | string | void | undefined | 边缘标签的自定义渲染器。 |
defaultNodeStyle | NodeStyle | defaultNodeStyle | 默认样式应用于所有节点。 |
defaultEdgeStyle | EdgeStyle | defaultEdgeStyle | 默认样式应用于所有边缘。 |
defaultLabelStyle | LabelStyle | defaultLabelStyle | 默认样式应用于所有边缘标签。 |
markerStyleMap | Record<string, MarkerStyle> | defaultMarkerStyle | 边缘标记的自定义样式('arrow'、'diamond'等)。见MarkerStyle |
nodeTypeAccessor | (node: Node) => string | undefined | undefined | 访问节点类型的函数,与 nodeStyleMap 一起使用。 |
nodeStyleMap | Record<string, NodeStyle> | {} | 将节点类型(从nodeTypeAccessor)映射到样式。 |
edgeTypeAccessor | (edge: Edge) => string | undefined | undefined | 边的 kind,与 edgeStyleMap 一起使用并用作 layer 键。 |
edgeStyleMap | Record<string, Partial<EdgeStyle>> | undefined | 将边缘类型(从 edgeTypeAccessor)映射到样式。请参阅边缘层。 |
minZoom | number | 0.1 | 最小缩放级别。 |
maxZoom | number | 10 | 最大缩放级别。 |
minFitScale | number | undefined | 拟合的最低缩放比例。在此缩放下会打开一个太大而无法容纳的图表,以 fitAnchor 为中心,小地图显示其余部分。 |
fitAnchor | string | undefined | 以 minFitScale 为中心的拟合节点的 ID。视图停止在图表的边缘,因此一侧的锚点停留在该侧附近。 |
zoomEnabled | boolean | true | 启用缩放。 false 还采用视口导轨的缩放按钮,保持合适和居中。 |
selectionBox | SelectionBox | undefined | 区域选择: enabled: false 放置拖动选框 ** 和 ** 选择 ▸ 套索工具。 |
enableNodeExpansion | boolean | true | 扩展集群:false 采用 V 形、Enter 快捷方式以及虚线折叠轮廓。选定的子节点仍然点亮其闭合的簇。 |
渲染类型
小费
Pivotick 使您可以灵活地控制渲染,从简单的默认值到完全自定义的渲染。这是一个快速概述:
无论卡片形状如何,都会对您的卡片进行测量
Pivotick 测量您返回的内容以调整其 <foreignObject> 的大小并提供力布局的碰撞半径。该卡是在图书馆自己的缩小到适合的盒子内测量的,因此您 ** 而不是 ** 必须使根自行调整大小:width: 100% 会根据其自己的内容而不是占位符进行解析。
接下来的三个渲染示例使用以下数据:
const data = {
nodes: [
{ id: 1, data: { label: 'A', type: 'hub' } },
{ id: 2, data: { label: 'B', type: 'spoke' } }
],
edges: [{ from: 1, to: 2 }]
}const options = {
render: {
defaultNodeStyle: {
shape: 'circle',
color: '#007acc',
size: 12,
strokeColor: '#fff',
strokeWidth: 2,
fontFamily: 'system-ui',
textColor: '#fff'
},
defaultEdgeStyle: {
markerStart: (edge: Edge) => edge.getData().mstart,
markerEnd: 'arrow',
curveStyle: 'straight',
},
}
}const options = {
render: {
nodeTypeAccessor: (node) => node.getData()?.type,
nodeStyleMap: {
'hub': {
shape: 'hexagon',
color: '#f90',
size: 25,
text: (node) => node.getData()?.label
},
'spoke': {
shape: 'triangle',
color: '#09f'
}
},
},
UI: {
mode: 'static'
}
}const options = {
render: {
renderNode: (node: Node): HTMLElement | string | void => {
const size = 12
const color = '#09f'
const style = [
'display: block',
`width: ${size}px`,
`height: ${size}px`,
`background-color: ${color}`,
'border: 2px solid #fff',
'border-radius: 50%',
'opacity: 1',
].join(';')
return `<span style="${style}"></span>`
}
}
}地图访问器渲染示例
HTML 节点
当 shape、color、icon 和 text 的组合都不起作用时,请向渲染器提供一些标记。有两种方式,区别只是声明的地方:
| 宣布于 | 达到 | |
|---|---|---|
NodeStyle.html | defaultNodeStyle,nodeStyleMap[type],节点自己的样式,styleCb返回 | 一种类型或一个节点 |
render.renderNode | 渲染器选项 | 造型链之前的每个节点 |
html是第一个到达的:它是一个普通样式的通道,因此它通过与color或shape相同的优先级链进行解析,并且可以将卡片给予一种节点,而其余节点保持其形状。
const options = {
render: {
nodeTypeAccessor: (node) => node.getData()?.kind,
nodeStyleMap: {
// A card, and nothing else: `shape: 'none'` is what makes it the whole node.
service: {
shape: 'none',
html: (node) => {
const card = document.createElement('div')
card.className = 'my-service-card'
card.textContent = node.getData()?.name
return card
},
},
// Same graph, ordinary shapes.
host: { shape: 'circle', size: 18, color: '#0891b2' },
},
},
}shape: 'none'
如果没有它,形状就是仍然被画在你的卡片后面, 和size是允许的最小节点——这是你想要的位于彩色圆盘上的卡片的结果,而不是你想要的节点卡片的结果。shape: 'none'不绘制形状,而是将节点的碰撞半径和边缘锚点交给卡片。
它是一个与其他形状值一样的形状值,因此它的组成是:仅标签节点是 shape: 'none',带有 text,没有卡片,仅图标节点是 shape: 'none',带有 iconClass。完全没有内容的无形节点是不可见的 - 但仍然存在,仍然可拖动,并且仍然可以在 2 × size 上选择。
不关闭什么卡
text是一个单独的通道,因此卡片和节点标签被绘制在一起。如果你的卡片有自己的标题,请设置 text: '' — 继承的值不能用 undefined 清除,这会落入样式映射表所说的内容。
尺码
您的卡片会被测量并且节点会向其生长,因此它永远不会被剪裁,碰撞力将真实的卡片隔开,边缘落在卡片的边界上,而不是落在它周围的圆圈上。您无需执行任何操作即可完成此操作 - 返回 width: 100% 根就可以了,因为测量发生在收缩到适合的盒子内。
有两个值得了解的后果:
- 测量是异步(卡片在屏幕上之前无法测量),因此节点的半径是其第一帧或第二帧的样式
size,然后成为卡片的半径。当它落地时,布局会被轻推一次。 - 一张卡在渲染时被测量一次。如果其内容稍后自行更改大小,请重新渲染节点以重新测量它。
仅梳理部分节点
两个回调都可能为节点返回 nothing,这会将节点返回到样式链 — 像往常一样的形状、样式映射条目、图标和标签。因此,单个全局renderNode可以卡出值得拥有的节点:
renderNode: (node) => node.getData()?.featured ? buildCard(node) : undefined仅受信任的标记
无论您返回什么,都会按原样插入。使用 textContent 构建它,或者转义它 - 不要将节点数据插入到标记字符串中。请参阅安全指南。
全节点标签
比它所拥有的房间长的节点标签会用中间的省略号 (Supe…abel) 缩短。设置 textTruncate: false 来完整绘制它 - 作为默认值、每个节点类型或每个节点:
const options = {
render: {
defaultNodeStyle: { textTruncate: false },
},
}在两者之间,textMaxWidth 以您选择的宽度(以图形单位(缩放 1 时CSS 像素)为单位)限制标签,而不是节点为其提供的空间。适合的标签会被完整绘制,较长的标签会被缩短并使用中间的省略号来达到该宽度:
const options = {
render: {
defaultNodeStyle: { textTruncate: true, textMaxWidth: 160 },
},
}标签字体大小
默认情况下,节点标签绘制在max(12, size × 0.45)处,因此它随节点一起增长。当节点的大小取决于其绘制的内容而不是其重要程度(例如图像缩略图)时,请设置 textFontSize(图形单位)以使其标签与其邻居保持一致:
const options = {
render: {
nodeStyleMap: {
image: { size: 80, imagePath: (node) => node.getData()?.url, textFontSize: 12 },
},
},
}标签仍然位于节点旁边,内置预算仍然从节点获取其宽度(因此较小的字体适合更多字符),并且 缩放门 根据您设置的大小来判断它。
与节点的其余部分一样,上限随着缩放而缩放,并且它可以是节点的函数。当textTruncate为false时忽略。
完整或带帽的标签通常会溢出节点的形状,因此它与浮动标签一样绘制在同一主题的药丸上,以在画布上保持可读性。将其与 textVerticalShift: 1(或 textHorizontalShift)配对,将整个标签移出节点。边缘标签永远不会被截断。
text 是节点上的标签,而不是节点的替代品。 是的节点,其文本应该绘制为节点,通过html,renderNode或tier - 这些是节点的绘图,缩放使它们保持不变minLabelFontSize做标签。
节点徽章
当图表有用时,color、shape、size和iconClass通常都携带着某些东西。 badges 是一个自己的通道 - 固定在节点边缘的小指标,不花费其他任何指标:
const options = {
render: {
defaultNodeStyle: {
badges: (node) => {
const { notes, disputed } = node.getData()
return [
notes && { text: String(notes), color: '#2563eb', title: `${notes} notes` },
disputed && { iconClass: 'fa fa-exclamation', color: '#b94a48', title: 'Disputed' },
].filter(Boolean)
},
},
},
}为其本机工具提示提供一个徽章 text(一个计数,或一个或两个字符)、一个 iconClass、iconUnicode 或 svgIcon,以及一个 title。如果您同时提供两者,text 获胜。较长的文本将徽章变成药丸,超过三个字符它会呈现 99+。
他们去哪里
省略 position,徽章从 'ne' 顺时针填充空闲角。说出其中一个 ('ne' | 'nw' | 'se' | 'sw') 并一字不差地予以尊重,包括重叠部分。
四个适合普通节点,两个适合一个有子节点的节点。 当节点折叠时,展开/折叠控件位于东北方,当节点展开时,展开/折叠控件位于东南方,因此在任何可展开节点上 两个 东角都被保留 - 否则每个徽章都会在集群打开时改变角。超出适合范围的徽章会折叠到 +n 中,工具提示会为它们命名。
徽章随着地板和天花板之间的节点缩放,因此它们在小节点上保持清晰,而不会在大节点上膨胀,并且它们位于形状的真实边缘上 - 正方形或框架图片的角,圆的 45° 点。
点击次数
徽章是可命中测试的,但默认情况下是透明的:没有处理程序,它的点击会失败并选择下面的节点,因此徽章永远不会是死点。
{ text: '3', onClick: (event, node, badge) => openNotes(node) }给徽章一个onClick——或者为它们共享的行为声明callbacks.onBadgeClick——它会获取指针光标并消耗其点击,使节点保持未选中状态。双方都开火了,徽章自己先开。按下徽章仍然可以向任一方向拖动节点,并且交互总线上的 badgeClick 侦听器可以 cancel() 两者。
适用范围
徽章仅描述它们所在的节点****。如果您想要的话,折叠集群不会聚合其子级 — 在您自己的 badges 函数中遍历 node.children,因为只有您知道事实是否相加、获胜或两者都不是。
缩放后的细节
一张近看很清晰的图画在概览上是无法辨认的,而一个适合概览的点也无法说明它是什么。 tiers 让一个节点携带多个绘图,并根据节点当前渲染的大小在它们之间进行选择。
const options = {
render: {
defaultNodeStyle: {
tiers: [
// Small: a coloured dot.
{ width: 32, height: 32, style: { shape: 'circle', size: 16 } },
// Once there is room for it: a labelled chip.
{ width: 140, height: 44, style: { shape: 'none', html: buildChip } },
],
},
},
}等级按最小的顺序排在第一位,最丰富的等级获胜。当没有这样做时,节点将以其基本样式进行绘制,因此您已经拥有的样式是地板:声明没有 tiers 的图形在各个方面都不受影响。
层继承了什么
层合并到基本样式上,因此它未命名的通道将被继承。绘图是例外:iconUnicode、iconClass、svgIcon、imagePath 和 html 是一个槽位,因此命名其中任何一个的层将直接替换底座的绘图(及其 imageFit)。具有卡层的静止字形只需要卡:
const options = {
render: {
defaultNodeStyle: {
svgIcon: buildGlyph,
tiers: [
{ width: 140, height: 44, style: { shape: 'none', html: buildChip } },
],
},
},
}没有命名图形的层,仅命名 size、color 或 text,例如,保留基础字形。
要删除该层不会以其他方式替换的通道,请将其设置为null,这意味着该层绘制该通道根本不。例如,strokeColor: null 会掉落底座的轮廓。 undefined不能代表:它的意思是“我不会命名这个频道”,这正是基地的价值得以生存的方式。
这是 null 以这种方式工作的唯一层。样式链中的其他位置 null 仍然会落到下面的层,因为直接从节点数据传回 null 的 styleCb 是普通形状,并且始终意味着“使用默认值”。
要使节点不成形,请使用 shape: 'none' 而不是清除 shape。
什么选择层级
渲染大小:节点的足迹(以CSS像素为单位),即footprint × zoom。一旦达到其 minRenderedSize,层就会参与,默认为该层自己的 width,因此 { width: 140 } 读作“一旦有空间绘制节点的 140 个像素就参与”。
缩放比例本身是不行的。它乘以所发明的布局的坐标,因此相同的比例意味着不同的图形上的不同的外观尺寸,并且在一个数据集上调整的阈值在下一个数据集上将是错误的。
已参与的层将一直保留,直到渲染大小降至其阈值的 85%。每个节点共享一个阈值,因此如果没有该带,停放在一个节点上的画布将作为一个整体闪烁。
足迹保持原状
节点在布局中保留的框在其绘图发生变化时不会发生变化。它是 layoutSize,并且默认为声明的最宽层的一半,因此声明层可以为图形提供正确的间距,而无需第二个数字。当层交换时,没有任何东西会移动:在已经正确大小的盒子内绘图发生变化,并且力量永远看不到差异。
出于同样的原因,width 和 height 是声明的而不是测量的。布局必须在第一个刻度之前知道足迹,并且测量卡仅在绘制后报告其尺寸。
自行设置layoutSize,使图形的间距比最宽的层更紧或更宽。请注意,仅当层的宽度等于占地面积时,才会按其设计尺寸绘制层;较窄的则按比例更早地啮合,并且按比例绘制得更小。如果重要的话,给它一个明确的minRenderedSize。
焦点图
focusTier 是节点悬停或自行选择时使用的绘图,无论缩放如何。这是一个节点讲述其自身一切的地方,因此阅读一个节点并不意味着放大它。
const options = {
render: {
defaultNodeStyle: {
tiers: [/* … */],
focusTier: { shape: 'none', html: buildDetailCard },
},
},
}它合并在节点的 base 样式上,而不是在活动层上,因此芯片层的 shape 或 html 不会泄漏到其中。它在屏幕上保持恒定的尺寸:绘图根据缩放进行反比例缩放,因此 280×150 的卡片无论距离图形有多远,都是 280×150 CSS 像素。而且它永远不会接触节点的几何形状,因此边缘不断落在下面的层上,并且悬停不会移动任何东西。
焦点图将节点的 badges 佩戴在其自己的边缘上,其屏幕尺寸与卡片相同。节点自己的徽章在显示时被隐藏,因此不会绘制两次。给focusTier一个自己的badges,以在卡片上显示不同的集合。
只有自己选择的节点才会被提升。五十个节点的框选择将是一堵重叠的卡片墙。
render.focusTierTrigger 表示何时触发:'both'(默认)、'hover'、'selection' 或 'off'。当您嵌入其他人提供的样式预设并希望在不编辑它的情况下抑制其焦点绘制时,请使用'off'。
当层级已经显示时
有时,焦点绘制与缩放层之一相同:悬停在芯片中的静止字形,一旦图形放大到足够远,也会绘制芯片。在那里,悬停会在屏幕上已有的芯片上绘制第二个较小的芯片。 focusTierYieldsAt 将索引命名为tiers,从中焦点绘图停止触发:
defaultNodeStyle: {
tiers: [{ width: 140, height: 44, style: { shape: 'none', html: chipFor } }],
focusTier: { shape: 'none', html: chipFor },
focusTierYieldsAt: 0,
}当节点绘制在该层或更丰富的层时,将鼠标悬停并进行单独选择即可使其保持原样。它遵循活动层,而不是缩放级别,因此它使用与交换相同的阈值。在卡片打开的情况下放大,会随着层的淡入而将其淡出,而缩小则可在不移动指针的情况下将其恢复。在焦点绘图比任何层都多的节点上将其保留为未设置,并且没有 tiers 的节点会忽略它。
工具提示仍然火爆
焦点卡不会取代工具提示。两者是独立的,工具提示可能包含卡片不包含的内容。
交换本身
节点从一幅图交叉淡入淡出到下一幅图,而不是剪切到它。传出的绘图保存在自己的图层上,并且两个图层相互淡出,因此节点在交换过程中永远不会缺席,只是在重叠的地方短暂地变得柔和。
render.detailTransition 是需要多长时间,以毫秒为单位。它默认为 160 并涵盖缩放决定的每个图形:层交叉、焦点图形和标签交叉 minLabelFontSize。将其设置为0以替换单帧中的绘图:
const options = {
render: {
detailTransition: 0,
defaultNodeStyle: { tiers: [/* … */] },
},
}屏幕上的每个节点都会在同一时刻交叉,因此交叉开始的淡入淡出次数与节点变化的次数一样多。在 210 个节点(每个节点持有一张 140×44 卡)上进行测量,淡入淡出的整个长度以 60 fps 运行;在交叉已经花费的单帧上,其成本约为 26 毫秒,并且该数字不会随着持续时间而增长。在该框架比过渡更重要的图表上将其关闭。
无论选项如何,prefers-reduced-motion 都会自行关闭它。
标签尺寸为可读尺寸
标签骑在图表上并随之缩放,因此视图越远,它绘制的就越小。图表以适合选择的任何比例打开,并且该比例随着图表的增长而下降:经过几百个节点,打开的框架是无人能读的文本,绘制在它所命名的图表上。
render.minLabelFontSize 是渲染尺寸,以 CSS 像素为单位,低于该尺寸不绘制标签。默认为9。
const options = {
render: {
minLabelFontSize: 9,
},
}测试是fontSize × zoom,以渲染像素而不是缩放比例为单位:缩放比例乘以发明的布局坐标,因此相同的值意味着下一个数据集上不同的表观大小。
它是整个画布、边缘标签和节点标签等的一个数字。它们之间的区别已经存在于字体大小中:边缘标签在 defaultLabelStyle.fontSize(默认为 12)处绘制,而节点的标签是从节点 max(12, size × 0.45) 派生的,因此大节点将其标签保持为比小节点更低的缩放比例。节点样式的 textFontSize 替换派生的大小。
0 关闭门并在每次缩放时绘制每个标签。
什么算作标签
库放置的文本:边的 label、节点的 text 以及 render.renderLabel 返回的内容。节点的html、renderNode或等级卡是其绘图,而tiers是在绘图之间进行选择。
正在显示的标签会一直保持到其渲染大小降至阈值的 85%,因此停放在线上的视图会稳定下来而不是闪烁。以一种尺寸绘制的每个标签都会一起回答,无论它属于哪个元素。
单独选择****的边缘显示其标签,无论缩放、反缩放,因此它是可读的,而不是它隐藏的两个像素。边缘没有工具提示,也没有面板,因此它的标签是唯一回答“这是什么”的东西。节点不需要这些:它已经通过其工具提示、侧边栏及其 focusTier 绘图进行了回答。
隐藏标签不仅是不可见的,而且也不在图表中——这就是成本所在。标签会在每个模拟刻度上重新定位,并且在单独通过的大图表上的成本超过一帧。门之后剩下的就是行程,这是便宜的。
它不做什么
高于阈值,标签仍然可以相互重叠。边缘标签通常比它所命名的边缘更宽,并且该比例不会随着缩放而改变。此选项是为了易读性,而不是整理。
应用程序编程接口
Pivotick 公开一个渲染器控制器,可让您直接与渲染引擎交互。所有方法网上均可
适合和缩放
graph.renderer.fitAndCenter()graph.renderer.zoomIn()
graph.renderer.zoomOut()