Hull 轮廓包围
上一篇
History 历史记录
下一篇
Legend 图例
Loading...
轮廓包围(Hull)用于处理和表示一组点的凸多边形或凹多边形包围盒。它可以将一组节点包裹在一个最小的几何形状中,帮助用户更好地理解和分析数据集。
轮廓包围插件主要适用于以下场景:
以下是一个简单的 Hull 插件初始化示例:
const graph = new Graph({plugins: [{type: 'hull',key: 'my-hull', // 指定唯一标识符,便于后续动态更新members: ['node-1', 'node-2'], // 需要包裹的节点 ID 列表concavity: Infinity, // 默认为凸包},],});
createGraph({data: {nodes: [{id: 'node-0',data: { cluster: 'a' },style: { x: 555, y: 151 },},{id: 'node-1',data: { cluster: 'a' },style: { x: 532, y: 323 },},{id: 'node-2',data: { cluster: 'a' },style: { x: 473, y: 227 },},{id: 'node-3',data: { cluster: 'a' },style: { x: 349, y: 212 },},{id: 'node-4',data: { cluster: 'b' },style: { x: 234, y: 201 },},{id: 'node-5',data: { cluster: 'b' },style: { x: 338, y: 333 },},{id: 'node-6',data: { cluster: 'b' },style: { x: 365, y: 91 },},],edges: [{source: 'node-0',target: 'node-2',},{source: 'node-1',target: 'node-2',},{source: 'node-2',target: 'node-3',},{source: 'node-3',target: 'node-4',},{source: 'node-3',target: 'node-5',},{source: 'node-3',target: 'node-6',},],},node: {style: { labelText: (d) => d.id },palette: { field: 'cluster', color: ['#7e3feb', '#ffa940'] },},behaviors: ['drag-canvas', 'drag-element'],plugins: ['grid-line',{type: 'hull',key: 'hull-a',members: ['node-0', 'node-1', 'node-2', 'node-3'],labelText: 'hull-a',fill: '#7e3feb',stroke: '#7e3feb',fillOpacity: 0.1,strokeOpacity: 1,labelFill: '#fff',labelPadding: 2,labelBackgroundFill: '#7e3feb',labelBackgroundRadius: 5,},],},{ width: 600, height: 450 },(gui, graph) => {const options = {type: 'hull',members: ['node-0', 'node-1', 'node-2', 'node-3'],concavity: Infinity,corner: 'rounded',padding: 10,// stylefill: '#7e3feb',stroke: '#7e3feb',fillOpacity: 0.1,strokeOpacity: 1,// labellabel: true,labelCloseToPath: true,labelAutoRotate: true,labelOffsetX: 0,labelOffsetY: 0,labelPlacement: 'bottom',};const optionFolder = gui.addFolder('Hull Options');optionFolder.add(options, 'type').disable();optionFolder.add(options, 'concavity', 0, 200, 1);optionFolder.add(options, 'corner', ['rounded', 'smooth', 'sharp']);optionFolder.add(options, 'padding', 0, 20, 1);optionFolder.addColor(options, 'fill');optionFolder.addColor(options, 'stroke');optionFolder.add(options, 'fillOpacity', 0, 1, 0.1);optionFolder.add(options, 'strokeOpacity', 0, 1, 0.1);optionFolder.add(options, 'label');optionFolder.add(options, 'labelCloseToPath');optionFolder.add(options, 'labelAutoRotate');optionFolder.add(options, 'labelOffsetX', 0, 20, 1);optionFolder.add(options, 'labelOffsetY', 0, 20, 1);optionFolder.add(options, 'labelPlacement', ['left', 'right', 'top', 'bottom', 'center']);optionFolder.onChange(({ property, value }) => {graph.updatePlugin({key: 'hull-a',[property]: value,});graph.render();});const apiConfig = {member: 'node-1',};const apiFolder = gui.addFolder('Hull API');const instance = graph.getPluginInstance('hull-a');apiFolder.add(apiConfig,'member',new Array(7).fill(0).map((_, index) => `node-${index}`),);apiFolder.add({ addMember: () => instance.addMember(apiConfig.member) }, 'addMember').name('add member');apiFolder.add({ removeMember: () => instance.removeMember(apiConfig.member) }, 'removeMember').name('remove member');apiFolder.add({ removeMember: () => alert('Members in Hull-a: ' + instance.getMember()) }, 'removeMember').name('get member');},);
属性 | 描述 | 类型 | 默认值 | 必选 |
---|---|---|---|---|
type | 插件类型 | string | hull | ✓ |
key | 插件唯一标识符,用于后续更新 | string | - | |
members | Hull 内的元素,包括节点和边 | string[] | - | ✓ |
concavity | 凹度,数值越大凹度越小;默认为 Infinity 代表为 Convex Hull | number | Infinity | |
corner | 拐角类型,可选值为 rounded | smooth | sharp | string | rounded | |
padding | 内边距 | number | 10 | |
label | 是否显示标签 | boolean | true | |
labelPlacement | 标签位置 | left | right | top | bottom | center | bottom | |
labelBackground | 是否显示背景 | boolean | false | |
labelPadding | 标签内边距 | number | number[] | 0 | |
labelCloseToPath | 标签是否贴合轮廓 | boolean | true | |
labelAutoRotate | 标签是否跟随轮廓旋转,仅在 closeToPath 为 true 时生效 | boolean | true | |
labelOffsetX | x 轴偏移量 | number | 0 | |
labelOffsetY | y 轴偏移量 | number | 0 | |
labelMaxWidth | 文本的最大宽度,超出会自动省略 | number | 0 |
完整的标签样式见此链接
concavity 属性用于控制 Hull 的凹度。当设置为 Infinity 时,生成的是凸包;否则会生成凹包。
// 凸包示例const graph = new Graph({plugins: [{type: 'hull',concavity: Infinity, // 凸包members: ['node-1', 'node-2'],},],});// 凹包示例const graph = new Graph({plugins: [{type: 'hull',concavity: 50, // 凹包members: ['node-1', 'node-2'],},],});
最简单的方式是直接使用预设配置:
const graph = new Graph({plugins: [{type: 'hull',members: ['node-1', 'node-2'], // 需要包裹的节点 ID 列表},],});
效果如下:
createGraph({autoFit: 'view',data: {nodes: [{id: 'node-0',data: { cluster: 'a' },style: { x: 555, y: 151 },},{id: 'node-1',data: { cluster: 'a' },style: { x: 532, y: 323 },},{id: 'node-2',data: { cluster: 'a' },style: { x: 473, y: 227 },},{id: 'node-3',data: { cluster: 'a' },style: { x: 349, y: 212 },},{id: 'node-4',data: { cluster: 'b' },style: { x: 234, y: 201 },},{id: 'node-5',data: { cluster: 'b' },style: { x: 338, y: 333 },},{id: 'node-6',data: { cluster: 'b' },style: { x: 365, y: 91 },},],edges: [{source: 'node-0',target: 'node-2',},{source: 'node-1',target: 'node-2',},{source: 'node-2',target: 'node-3',},{source: 'node-3',target: 'node-4',},{source: 'node-3',target: 'node-5',},{source: 'node-3',target: 'node-6',},],},plugins: [{type: 'hull',members: ['node-1', 'node-2'], // 需要包裹的节点 ID 列表},],behaviors: ['zoom-canvas', 'drag-canvas'],},{ width: 300, height: 150 },);
您可以根据需要自定义 Hull 的样式,例如调整颜色、透明度等属性。
const graph = new Graph({plugins: [{type: 'hull',members: ['node-1', 'node-2', 'node-3'],stroke: '#ff000033', // 红色半透明边框fill: '#7e3feb', // 浅紫色填充fillOpacity: 0.2,lineWidth: 2,padding: 15, // 更大的内边距},],});
效果如下:
createGraph({autoFit: 'view',data: {nodes: [{id: 'node-0',data: { cluster: 'a' },style: { x: 555, y: 151 },},{id: 'node-1',data: { cluster: 'a' },style: { x: 532, y: 323 },},{id: 'node-2',data: { cluster: 'a' },style: { x: 473, y: 227 },},{id: 'node-3',data: { cluster: 'a' },style: { x: 349, y: 212 },},{id: 'node-4',data: { cluster: 'b' },style: { x: 234, y: 201 },},{id: 'node-5',data: { cluster: 'b' },style: { x: 338, y: 333 },},{id: 'node-6',data: { cluster: 'b' },style: { x: 365, y: 91 },},],edges: [{source: 'node-0',target: 'node-2',},{source: 'node-1',target: 'node-2',},{source: 'node-2',target: 'node-3',},{source: 'node-3',target: 'node-4',},{source: 'node-3',target: 'node-5',},{source: 'node-3',target: 'node-6',},],},plugins: [{type: 'hull',members: ['node-1', 'node-2', 'node-3'],stroke: '#ff000033', // 红色半透明边框fill: '#7e3feb', // 浅紫色填充fillOpacity: 0.2,lineWidth: 2,padding: 15, // 更大的内边距},],behaviors: ['zoom-canvas', 'drag-canvas'],},{ width: 300, height: 150 },);
您可以配置标签的位置、背景、偏移量等属性,以增强可视化效果。
const graph = new Graph({plugins: [{type: 'hull',members: ['node-1', 'node-2'],label: true, // 显示标签labelText: 'hull-a',labelPlacement: 'top', // 标签位置labelBackground: true, // 显示标签背景labelPadding: 5, // 标签内边距},],});
效果如下:
createGraph({autoFit: 'center',data: {nodes: [{id: 'node-0',data: { cluster: 'a' },style: { x: 555, y: 151 },},{id: 'node-1',data: { cluster: 'a' },style: { x: 532, y: 323 },},{id: 'node-2',data: { cluster: 'a' },style: { x: 473, y: 227 },},{id: 'node-3',data: { cluster: 'a' },style: { x: 349, y: 212 },},{id: 'node-4',data: { cluster: 'b' },style: { x: 234, y: 201 },},{id: 'node-5',data: { cluster: 'b' },style: { x: 338, y: 333 },},{id: 'node-6',data: { cluster: 'b' },style: { x: 365, y: 91 },},],edges: [{source: 'node-0',target: 'node-2',},{source: 'node-1',target: 'node-2',},{source: 'node-2',target: 'node-3',},{source: 'node-3',target: 'node-4',},{source: 'node-3',target: 'node-5',},{source: 'node-3',target: 'node-6',},],},plugins: [{type: 'hull',members: ['node-1', 'node-2'],label: true, // 显示标签labelText: 'hull-a',labelPlacement: 'top', // 标签位置labelBackground: true, // 显示标签背景labelPadding: 5, // 标签内边距},],behaviors: ['zoom-canvas', 'drag-canvas'],},{ width: 300, height: 150 },);