mirror of
https://gitee.com/antv/g6.git
synced 2024-11-30 02:38:20 +08:00
feat: fruchterman GPU version.
This commit is contained in:
parent
1c3c49b9fc
commit
26e1ae69bc
31
examples/net/gpuLayout/API.en.md
Normal file
31
examples/net/gpuLayout/API.en.md
Normal file
@ -0,0 +1,31 @@
|
||||
---
|
||||
title: API
|
||||
---
|
||||
|
||||
## center
|
||||
|
||||
**Type**: Array<br />**Example**: [ 0, 0 ]<br />**Default**: The center of the graph<br />**Required**: false<br />**Description**: The center of the layout
|
||||
|
||||
## maxIteration
|
||||
|
||||
**Type**: Number<br />**Default**: 1000<br />**Required**: false<br />**Description**: The maximum iteration number
|
||||
|
||||
## gravity
|
||||
|
||||
**Type**: Number<br />**Default**: 10<br />**Required**: false<br />**Description**: The gravity, which will affect the compactness of the layout
|
||||
|
||||
## speed
|
||||
|
||||
**Type**: Number<br />**Default**: 1<br />**Required**: false<br />**Description**: The moving speed of each iteraction. Large value of the speed might lead to violent swing
|
||||
|
||||
## clustering
|
||||
|
||||
**Type**: Boolean<br />**Default**: false<br />**Required**: false<br />**Description**: Whether to layout by cluster
|
||||
|
||||
## clusterGravity
|
||||
|
||||
**Type**: Number<br />**Default**: 10<br />**Required**: false<br />**Description**: The gravity of each cluster, which will affect the compactness of each cluster. Takes effect only when `clustering` is `true`
|
||||
|
||||
## workerEnabled
|
||||
|
||||
**Type**: Boolean<br />**Default**: false<br />**Required**: false<br />**Description**: Whether to enable the web-worker in case layout calculation takes too long to block page interaction
|
31
examples/net/gpuLayout/API.zh.md
Normal file
31
examples/net/gpuLayout/API.zh.md
Normal file
@ -0,0 +1,31 @@
|
||||
---
|
||||
title: API
|
||||
---
|
||||
|
||||
## center
|
||||
|
||||
**类型**: Array<br />**示例**:[ 0, 0 ]<br />**默认值**:图的中心<br />**是否必须**:false<br />**说明**:布局的中心
|
||||
|
||||
## maxIteration
|
||||
|
||||
**类型**: Number<br />**默认值**:1000<br />**是否必须**:false<br />**说明**:最大迭代次数
|
||||
|
||||
## gravity
|
||||
|
||||
**类型**: Number<br />**默认值**:10<br />**是否必须**:false<br />**说明**:重力的大小,影响布局的紧凑程度
|
||||
|
||||
## speed
|
||||
|
||||
**类型**: Number<br />**默认值**:1<br />**是否必须**:false<br />**说明**:每次迭代节点移动的速度。速度太快可能会导致强烈震荡
|
||||
|
||||
## clustering
|
||||
|
||||
**类型**: Boolean<br />**默认值**:false<br />**是否必须**:false<br />**说明**:是否按照聚类布局
|
||||
|
||||
## clusterGravity
|
||||
|
||||
**类型**: Number<br />**默认值**:10<br />**是否必须**:false<br />**说明**:聚类内部的重力大小,影响聚类的紧凑程度,在 `clustering` 为 `true` 时生效
|
||||
|
||||
## workerEnabled
|
||||
|
||||
**类型**: Boolean<br />**默认值**: false<br />**是否必须**: false<br />**说明**: 是否启用 web-worker 以防布局计算时间过长阻塞页面交互
|
462
examples/net/gpuLayout/demo/basicFruchterman.js
Normal file
462
examples/net/gpuLayout/demo/basicFruchterman.js
Normal file
@ -0,0 +1,462 @@
|
||||
import G6 from '@antv/g6';
|
||||
|
||||
const data = {
|
||||
nodes: [
|
||||
{
|
||||
id: '0',
|
||||
label: '0',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
label: '1',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
label: '2',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
label: '3',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
label: '4',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
label: '5',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
label: '6',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '7',
|
||||
label: '7',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '8',
|
||||
label: '8',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '9',
|
||||
label: '9',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '10',
|
||||
label: '10',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '11',
|
||||
label: '11',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '12',
|
||||
label: '12',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '13',
|
||||
label: '13',
|
||||
cluster: 'b',
|
||||
},
|
||||
{
|
||||
id: '14',
|
||||
label: '14',
|
||||
cluster: 'b',
|
||||
},
|
||||
{
|
||||
id: '15',
|
||||
label: '15',
|
||||
cluster: 'b',
|
||||
},
|
||||
{
|
||||
id: '16',
|
||||
label: '16',
|
||||
cluster: 'b',
|
||||
},
|
||||
{
|
||||
id: '17',
|
||||
label: '17',
|
||||
cluster: 'b',
|
||||
},
|
||||
{
|
||||
id: '18',
|
||||
label: '18',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '19',
|
||||
label: '19',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '20',
|
||||
label: '20',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '21',
|
||||
label: '21',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '22',
|
||||
label: '22',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '23',
|
||||
label: '23',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '24',
|
||||
label: '24',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '25',
|
||||
label: '25',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '26',
|
||||
label: '26',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '27',
|
||||
label: '27',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '28',
|
||||
label: '28',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '29',
|
||||
label: '29',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '30',
|
||||
label: '30',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '31',
|
||||
label: '31',
|
||||
cluster: 'd',
|
||||
},
|
||||
{
|
||||
id: '32',
|
||||
label: '32',
|
||||
cluster: 'd',
|
||||
},
|
||||
{
|
||||
id: '33',
|
||||
label: '33',
|
||||
cluster: 'd',
|
||||
},
|
||||
],
|
||||
edges: [
|
||||
{
|
||||
source: '0',
|
||||
target: '1',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '2',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '3',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '4',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '5',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '7',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '8',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '9',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '10',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '11',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '13',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '14',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '15',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '16',
|
||||
},
|
||||
{
|
||||
source: '2',
|
||||
target: '3',
|
||||
},
|
||||
{
|
||||
source: '4',
|
||||
target: '5',
|
||||
},
|
||||
{
|
||||
source: '4',
|
||||
target: '6',
|
||||
},
|
||||
{
|
||||
source: '5',
|
||||
target: '6',
|
||||
},
|
||||
{
|
||||
source: '7',
|
||||
target: '13',
|
||||
},
|
||||
{
|
||||
source: '8',
|
||||
target: '14',
|
||||
},
|
||||
{
|
||||
source: '9',
|
||||
target: '10',
|
||||
},
|
||||
{
|
||||
source: '10',
|
||||
target: '22',
|
||||
},
|
||||
{
|
||||
source: '10',
|
||||
target: '14',
|
||||
},
|
||||
{
|
||||
source: '10',
|
||||
target: '12',
|
||||
},
|
||||
{
|
||||
source: '10',
|
||||
target: '24',
|
||||
},
|
||||
{
|
||||
source: '10',
|
||||
target: '21',
|
||||
},
|
||||
{
|
||||
source: '10',
|
||||
target: '20',
|
||||
},
|
||||
{
|
||||
source: '11',
|
||||
target: '24',
|
||||
},
|
||||
{
|
||||
source: '11',
|
||||
target: '22',
|
||||
},
|
||||
{
|
||||
source: '11',
|
||||
target: '14',
|
||||
},
|
||||
{
|
||||
source: '12',
|
||||
target: '13',
|
||||
},
|
||||
{
|
||||
source: '16',
|
||||
target: '17',
|
||||
},
|
||||
{
|
||||
source: '16',
|
||||
target: '18',
|
||||
},
|
||||
{
|
||||
source: '16',
|
||||
target: '21',
|
||||
},
|
||||
{
|
||||
source: '16',
|
||||
target: '22',
|
||||
},
|
||||
{
|
||||
source: '17',
|
||||
target: '18',
|
||||
},
|
||||
{
|
||||
source: '17',
|
||||
target: '20',
|
||||
},
|
||||
{
|
||||
source: '18',
|
||||
target: '19',
|
||||
},
|
||||
{
|
||||
source: '19',
|
||||
target: '20',
|
||||
},
|
||||
{
|
||||
source: '19',
|
||||
target: '33',
|
||||
},
|
||||
{
|
||||
source: '19',
|
||||
target: '22',
|
||||
},
|
||||
{
|
||||
source: '19',
|
||||
target: '23',
|
||||
},
|
||||
{
|
||||
source: '20',
|
||||
target: '21',
|
||||
},
|
||||
{
|
||||
source: '21',
|
||||
target: '22',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '24',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '25',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '26',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '23',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '28',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '30',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '31',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '32',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '33',
|
||||
},
|
||||
{
|
||||
source: '23',
|
||||
target: '28',
|
||||
},
|
||||
{
|
||||
source: '23',
|
||||
target: '27',
|
||||
},
|
||||
{
|
||||
source: '23',
|
||||
target: '29',
|
||||
},
|
||||
{
|
||||
source: '23',
|
||||
target: '30',
|
||||
},
|
||||
{
|
||||
source: '23',
|
||||
target: '31',
|
||||
},
|
||||
{
|
||||
source: '23',
|
||||
target: '33',
|
||||
},
|
||||
{
|
||||
source: '32',
|
||||
target: '33',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const width = document.getElementById('container').scrollWidth;
|
||||
const height = document.getElementById('container').scrollHeight || 500;
|
||||
const graph = new G6.Graph({
|
||||
container: 'container',
|
||||
width,
|
||||
height,
|
||||
modes: {
|
||||
default: ['drag-canvas', 'drag-node'],
|
||||
},
|
||||
animate: true,
|
||||
defaultNode: {
|
||||
size: 30,
|
||||
style: {
|
||||
lineWidth: 2,
|
||||
stroke: '#5B8FF9',
|
||||
fill: '#C6E5FF',
|
||||
},
|
||||
},
|
||||
defaultEdge: {
|
||||
size: 1,
|
||||
color: '#e2e2e2',
|
||||
style: {
|
||||
endArrow: {
|
||||
path: 'M 0,0 L 8,4 L 8,-4 Z',
|
||||
fill: '#e2e2e2'
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
graph.data(data);
|
||||
graph.render();
|
||||
|
||||
const gpuLayout = new G6.Layout['fruchtermanGPU']({
|
||||
canvasEl: graph.get('canvas').get('el'),
|
||||
width,
|
||||
height,
|
||||
onLayoutEnd: () => {
|
||||
graph.refreshPositions();
|
||||
}
|
||||
})
|
||||
gpuLayout.init(data);
|
||||
gpuLayout.execute();
|
496
examples/net/gpuLayout/demo/fruchtermanClustering.js
Normal file
496
examples/net/gpuLayout/demo/fruchtermanClustering.js
Normal file
@ -0,0 +1,496 @@
|
||||
import G6 from '@antv/g6';
|
||||
|
||||
const data = {
|
||||
nodes: [
|
||||
{
|
||||
id: '0',
|
||||
label: '0',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
label: '1',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
label: '2',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
label: '3',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
label: '4',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
label: '5',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
label: '6',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '7',
|
||||
label: '7',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '8',
|
||||
label: '8',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '9',
|
||||
label: '9',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '10',
|
||||
label: '10',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '11',
|
||||
label: '11',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '12',
|
||||
label: '12',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '13',
|
||||
label: '13',
|
||||
cluster: 'b',
|
||||
},
|
||||
{
|
||||
id: '14',
|
||||
label: '14',
|
||||
cluster: 'b',
|
||||
},
|
||||
{
|
||||
id: '15',
|
||||
label: '15',
|
||||
cluster: 'b',
|
||||
},
|
||||
{
|
||||
id: '16',
|
||||
label: '16',
|
||||
cluster: 'b',
|
||||
},
|
||||
{
|
||||
id: '17',
|
||||
label: '17',
|
||||
cluster: 'b',
|
||||
},
|
||||
{
|
||||
id: '18',
|
||||
label: '18',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '19',
|
||||
label: '19',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '20',
|
||||
label: '20',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '21',
|
||||
label: '21',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '22',
|
||||
label: '22',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '23',
|
||||
label: '23',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '24',
|
||||
label: '24',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '25',
|
||||
label: '25',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '26',
|
||||
label: '26',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '27',
|
||||
label: '27',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '28',
|
||||
label: '28',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '29',
|
||||
label: '29',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '30',
|
||||
label: '30',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '31',
|
||||
label: '31',
|
||||
cluster: 'd',
|
||||
},
|
||||
{
|
||||
id: '32',
|
||||
label: '32',
|
||||
cluster: 'd',
|
||||
},
|
||||
{
|
||||
id: '33',
|
||||
label: '33',
|
||||
cluster: 'd',
|
||||
},
|
||||
],
|
||||
edges: [
|
||||
{
|
||||
source: '0',
|
||||
target: '1',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '2',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '3',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '4',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '5',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '7',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '8',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '9',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '10',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '11',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '13',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '14',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '15',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '16',
|
||||
},
|
||||
{
|
||||
source: '2',
|
||||
target: '3',
|
||||
},
|
||||
{
|
||||
source: '4',
|
||||
target: '5',
|
||||
},
|
||||
{
|
||||
source: '4',
|
||||
target: '6',
|
||||
},
|
||||
{
|
||||
source: '5',
|
||||
target: '6',
|
||||
},
|
||||
{
|
||||
source: '7',
|
||||
target: '13',
|
||||
},
|
||||
{
|
||||
source: '8',
|
||||
target: '14',
|
||||
},
|
||||
{
|
||||
source: '9',
|
||||
target: '10',
|
||||
},
|
||||
{
|
||||
source: '10',
|
||||
target: '22',
|
||||
},
|
||||
{
|
||||
source: '10',
|
||||
target: '14',
|
||||
},
|
||||
{
|
||||
source: '10',
|
||||
target: '12',
|
||||
},
|
||||
{
|
||||
source: '10',
|
||||
target: '24',
|
||||
},
|
||||
{
|
||||
source: '10',
|
||||
target: '21',
|
||||
},
|
||||
{
|
||||
source: '10',
|
||||
target: '20',
|
||||
},
|
||||
{
|
||||
source: '11',
|
||||
target: '24',
|
||||
},
|
||||
{
|
||||
source: '11',
|
||||
target: '22',
|
||||
},
|
||||
{
|
||||
source: '11',
|
||||
target: '14',
|
||||
},
|
||||
{
|
||||
source: '12',
|
||||
target: '13',
|
||||
},
|
||||
{
|
||||
source: '16',
|
||||
target: '17',
|
||||
},
|
||||
{
|
||||
source: '16',
|
||||
target: '18',
|
||||
},
|
||||
{
|
||||
source: '16',
|
||||
target: '21',
|
||||
},
|
||||
{
|
||||
source: '16',
|
||||
target: '22',
|
||||
},
|
||||
{
|
||||
source: '17',
|
||||
target: '18',
|
||||
},
|
||||
{
|
||||
source: '17',
|
||||
target: '20',
|
||||
},
|
||||
{
|
||||
source: '18',
|
||||
target: '19',
|
||||
},
|
||||
{
|
||||
source: '19',
|
||||
target: '20',
|
||||
},
|
||||
{
|
||||
source: '19',
|
||||
target: '33',
|
||||
},
|
||||
{
|
||||
source: '19',
|
||||
target: '22',
|
||||
},
|
||||
{
|
||||
source: '19',
|
||||
target: '23',
|
||||
},
|
||||
{
|
||||
source: '20',
|
||||
target: '21',
|
||||
},
|
||||
{
|
||||
source: '21',
|
||||
target: '22',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '24',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '25',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '26',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '23',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '28',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '30',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '31',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '32',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '33',
|
||||
},
|
||||
{
|
||||
source: '23',
|
||||
target: '28',
|
||||
},
|
||||
{
|
||||
source: '23',
|
||||
target: '27',
|
||||
},
|
||||
{
|
||||
source: '23',
|
||||
target: '29',
|
||||
},
|
||||
{
|
||||
source: '23',
|
||||
target: '30',
|
||||
},
|
||||
{
|
||||
source: '23',
|
||||
target: '31',
|
||||
},
|
||||
{
|
||||
source: '23',
|
||||
target: '33',
|
||||
},
|
||||
{
|
||||
source: '32',
|
||||
target: '33',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const colors = [
|
||||
'#BDD2FD',
|
||||
'#BDEFDB',
|
||||
'#C2C8D5',
|
||||
'#FBE5A2',
|
||||
'#F6C3B7',
|
||||
'#B6E3F5',
|
||||
'#D3C6EA',
|
||||
'#FFD8B8',
|
||||
'#AAD8D8',
|
||||
'#FFD6E7',
|
||||
];
|
||||
const strokes = [
|
||||
'#5B8FF9',
|
||||
'#5AD8A6',
|
||||
'#5D7092',
|
||||
'#F6BD16',
|
||||
'#E8684A',
|
||||
'#6DC8EC',
|
||||
'#9270CA',
|
||||
'#FF9D4D',
|
||||
'#269A99',
|
||||
'#FF99C3',
|
||||
];
|
||||
|
||||
const nodes = data.nodes;
|
||||
const clusterMap = new Map();
|
||||
let clusterId = 0;
|
||||
nodes.forEach(function(node) {
|
||||
// cluster
|
||||
if (node.cluster && clusterMap.get(node.cluster) === undefined) {
|
||||
clusterMap.set(node.cluster, clusterId);
|
||||
clusterId++;
|
||||
}
|
||||
const cid = clusterMap.get(node.cluster);
|
||||
if (!node.style) {
|
||||
node.style = {};
|
||||
}
|
||||
node.style.fill = colors[cid % colors.length];
|
||||
node.style.stroke = strokes[cid % strokes.length];
|
||||
});
|
||||
const graphDiv = document.getElementById('container');
|
||||
const width = graphDiv.scrollWidth;
|
||||
const height = graphDiv.scrollHeight;
|
||||
const graph = new G6.Graph({
|
||||
container: 'container',
|
||||
width,
|
||||
height,
|
||||
modes: {
|
||||
default: ['drag-canvas', 'drag-node'],
|
||||
},
|
||||
layout: {
|
||||
type: 'fruchterman',
|
||||
gravity: 10,
|
||||
speed: 5,
|
||||
clustering: true,
|
||||
},
|
||||
animate: true,
|
||||
defaultNode: {
|
||||
size: 20,
|
||||
style: {
|
||||
lineWidth: 2,
|
||||
},
|
||||
},
|
||||
defaultEdge: {
|
||||
size: 1,
|
||||
color: '#e2e2e2',
|
||||
style: {
|
||||
endArrow: {
|
||||
path: 'M 0,0 L 8,4 L 8,-4 Z',
|
||||
fill: '#e2e2e2'
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
graph.data(data);
|
||||
graph.render();
|
51
examples/net/gpuLayout/demo/fruchtermanComplexData.js
Normal file
51
examples/net/gpuLayout/demo/fruchtermanComplexData.js
Normal file
@ -0,0 +1,51 @@
|
||||
import G6 from '@antv/g6';
|
||||
|
||||
const width = document.getElementById('container').scrollWidth;
|
||||
const height = document.getElementById('container').scrollHeight || 500;
|
||||
const graph = new G6.Graph({
|
||||
container: 'container',
|
||||
width,
|
||||
height,
|
||||
modes: {
|
||||
default: ['drag-canvas', 'drag-node'],
|
||||
},
|
||||
animate: true,
|
||||
defaultNode: {
|
||||
size: 10,
|
||||
style: {
|
||||
lineWidth: 2,
|
||||
stroke: '#5B8FF9',
|
||||
fill: '#C6E5FF',
|
||||
},
|
||||
},
|
||||
defaultEdge: {
|
||||
size: 1,
|
||||
color: '#e2e2e2',
|
||||
style: {
|
||||
endArrow: {
|
||||
path: 'M 0,0 L 8,4 L 8,-4 Z',
|
||||
fill: '#e2e2e2'
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
fetch('https://gw.alipayobjects.com/os/basement_prod/7bacd7d1-4119-4ac1-8be3-4c4b9bcbc25f.json')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
graph.data(data);
|
||||
graph.render();
|
||||
|
||||
const gpuLayout = new G6.Layout['fruchtermanGPU']({
|
||||
canvasEl: graph.get('canvas').get('el'),
|
||||
width,
|
||||
height,
|
||||
maxIteration: 1000,
|
||||
onLayoutEnd: () => {
|
||||
graph.refreshPositions();
|
||||
}
|
||||
})
|
||||
gpuLayout.init(data);
|
||||
gpuLayout.execute();
|
||||
});
|
538
examples/net/gpuLayout/demo/fruchtermanConfigurationTranslate.js
Normal file
538
examples/net/gpuLayout/demo/fruchtermanConfigurationTranslate.js
Normal file
@ -0,0 +1,538 @@
|
||||
import G6 from '@antv/g6';
|
||||
|
||||
const data = {
|
||||
nodes: [
|
||||
{
|
||||
id: '0',
|
||||
label: '0',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
label: '1',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
label: '2',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
label: '3',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
label: '4',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
label: '5',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
label: '6',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '7',
|
||||
label: '7',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '8',
|
||||
label: '8',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '9',
|
||||
label: '9',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '10',
|
||||
label: '10',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '11',
|
||||
label: '11',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '12',
|
||||
label: '12',
|
||||
cluster: 'a',
|
||||
},
|
||||
{
|
||||
id: '13',
|
||||
label: '13',
|
||||
cluster: 'b',
|
||||
},
|
||||
{
|
||||
id: '14',
|
||||
label: '14',
|
||||
cluster: 'b',
|
||||
},
|
||||
{
|
||||
id: '15',
|
||||
label: '15',
|
||||
cluster: 'b',
|
||||
},
|
||||
{
|
||||
id: '16',
|
||||
label: '16',
|
||||
cluster: 'b',
|
||||
},
|
||||
{
|
||||
id: '17',
|
||||
label: '17',
|
||||
cluster: 'b',
|
||||
},
|
||||
{
|
||||
id: '18',
|
||||
label: '18',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '19',
|
||||
label: '19',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '20',
|
||||
label: '20',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '21',
|
||||
label: '21',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '22',
|
||||
label: '22',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '23',
|
||||
label: '23',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '24',
|
||||
label: '24',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '25',
|
||||
label: '25',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '26',
|
||||
label: '26',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '27',
|
||||
label: '27',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '28',
|
||||
label: '28',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '29',
|
||||
label: '29',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '30',
|
||||
label: '30',
|
||||
cluster: 'c',
|
||||
},
|
||||
{
|
||||
id: '31',
|
||||
label: '31',
|
||||
cluster: 'd',
|
||||
},
|
||||
{
|
||||
id: '32',
|
||||
label: '32',
|
||||
cluster: 'd',
|
||||
},
|
||||
{
|
||||
id: '33',
|
||||
label: '33',
|
||||
cluster: 'd',
|
||||
},
|
||||
],
|
||||
edges: [
|
||||
{
|
||||
source: '0',
|
||||
target: '1',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '2',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '3',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '4',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '5',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '7',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '8',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '9',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '10',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '11',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '13',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '14',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '15',
|
||||
},
|
||||
{
|
||||
source: '0',
|
||||
target: '16',
|
||||
},
|
||||
{
|
||||
source: '2',
|
||||
target: '3',
|
||||
},
|
||||
{
|
||||
source: '4',
|
||||
target: '5',
|
||||
},
|
||||
{
|
||||
source: '4',
|
||||
target: '6',
|
||||
},
|
||||
{
|
||||
source: '5',
|
||||
target: '6',
|
||||
},
|
||||
{
|
||||
source: '7',
|
||||
target: '13',
|
||||
},
|
||||
{
|
||||
source: '8',
|
||||
target: '14',
|
||||
},
|
||||
{
|
||||
source: '9',
|
||||
target: '10',
|
||||
},
|
||||
{
|
||||
source: '10',
|
||||
target: '22',
|
||||
},
|
||||
{
|
||||
source: '10',
|
||||
target: '14',
|
||||
},
|
||||
{
|
||||
source: '10',
|
||||
target: '12',
|
||||
},
|
||||
{
|
||||
source: '10',
|
||||
target: '24',
|
||||
},
|
||||
{
|
||||
source: '10',
|
||||
target: '21',
|
||||
},
|
||||
{
|
||||
source: '10',
|
||||
target: '20',
|
||||
},
|
||||
{
|
||||
source: '11',
|
||||
target: '24',
|
||||
},
|
||||
{
|
||||
source: '11',
|
||||
target: '22',
|
||||
},
|
||||
{
|
||||
source: '11',
|
||||
target: '14',
|
||||
},
|
||||
{
|
||||
source: '12',
|
||||
target: '13',
|
||||
},
|
||||
{
|
||||
source: '16',
|
||||
target: '17',
|
||||
},
|
||||
{
|
||||
source: '16',
|
||||
target: '18',
|
||||
},
|
||||
{
|
||||
source: '16',
|
||||
target: '21',
|
||||
},
|
||||
{
|
||||
source: '16',
|
||||
target: '22',
|
||||
},
|
||||
{
|
||||
source: '17',
|
||||
target: '18',
|
||||
},
|
||||
{
|
||||
source: '17',
|
||||
target: '20',
|
||||
},
|
||||
{
|
||||
source: '18',
|
||||
target: '19',
|
||||
},
|
||||
{
|
||||
source: '19',
|
||||
target: '20',
|
||||
},
|
||||
{
|
||||
source: '19',
|
||||
target: '33',
|
||||
},
|
||||
{
|
||||
source: '19',
|
||||
target: '22',
|
||||
},
|
||||
{
|
||||
source: '19',
|
||||
target: '23',
|
||||
},
|
||||
{
|
||||
source: '20',
|
||||
target: '21',
|
||||
},
|
||||
{
|
||||
source: '21',
|
||||
target: '22',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '24',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '25',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '26',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '23',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '28',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '30',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '31',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '32',
|
||||
},
|
||||
{
|
||||
source: '22',
|
||||
target: '33',
|
||||
},
|
||||
{
|
||||
source: '23',
|
||||
target: '28',
|
||||
},
|
||||
{
|
||||
source: '23',
|
||||
target: '27',
|
||||
},
|
||||
{
|
||||
source: '23',
|
||||
target: '29',
|
||||
},
|
||||
{
|
||||
source: '23',
|
||||
target: '30',
|
||||
},
|
||||
{
|
||||
source: '23',
|
||||
target: '31',
|
||||
},
|
||||
{
|
||||
source: '23',
|
||||
target: '33',
|
||||
},
|
||||
{
|
||||
source: '32',
|
||||
target: '33',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const colors = [
|
||||
'#BDD2FD',
|
||||
'#BDEFDB',
|
||||
'#C2C8D5',
|
||||
'#FBE5A2',
|
||||
'#F6C3B7',
|
||||
'#B6E3F5',
|
||||
'#D3C6EA',
|
||||
'#FFD8B8',
|
||||
'#AAD8D8',
|
||||
'#FFD6E7',
|
||||
];
|
||||
const strokes = [
|
||||
'#5B8FF9',
|
||||
'#5AD8A6',
|
||||
'#5D7092',
|
||||
'#F6BD16',
|
||||
'#E8684A',
|
||||
'#6DC8EC',
|
||||
'#9270CA',
|
||||
'#FF9D4D',
|
||||
'#269A99',
|
||||
'#FF99C3',
|
||||
];
|
||||
|
||||
const nodes = data.nodes;
|
||||
const clusterMap = new Map();
|
||||
let clusterId = 0;
|
||||
nodes.forEach(function(node) {
|
||||
// cluster
|
||||
if (node.cluster && clusterMap.get(node.cluster) === undefined) {
|
||||
clusterMap.set(node.cluster, clusterId);
|
||||
clusterId++;
|
||||
}
|
||||
const cid = clusterMap.get(node.cluster);
|
||||
if (!node.style) {
|
||||
node.style = {};
|
||||
}
|
||||
node.style.fill = colors[cid % colors.length];
|
||||
node.style.stroke = strokes[cid % strokes.length];
|
||||
});
|
||||
const graphDiv = document.getElementById('container');
|
||||
const descriptionDiv = document.createElement('div');
|
||||
descriptionDiv.innerHTML = 'Fruchterman layout, gravity = 1';
|
||||
graphDiv.appendChild(descriptionDiv);
|
||||
const width = graphDiv.scrollWidth;
|
||||
const height = graphDiv.scrollHeight - 30;
|
||||
const graph = new G6.Graph({
|
||||
container: 'container',
|
||||
width,
|
||||
height,
|
||||
modes: {
|
||||
default: ['drag-canvas', 'drag-node'],
|
||||
},
|
||||
layout: {
|
||||
type: 'fruchterman',
|
||||
gravity: 1,
|
||||
speed: 5,
|
||||
},
|
||||
animate: true,
|
||||
defaultNode: {
|
||||
size: 20,
|
||||
style: {
|
||||
lineWidth: 2,
|
||||
},
|
||||
},
|
||||
defaultEdge: {
|
||||
size: 1,
|
||||
color: '#e2e2e2',
|
||||
style: {
|
||||
endArrow: {
|
||||
path: 'M 0,0 L 8,4 L 8,-4 Z',
|
||||
fill: '#e2e2e2'
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
graph.data(data);
|
||||
graph.render();
|
||||
|
||||
layoutConfigTranslation();
|
||||
|
||||
function layoutConfigTranslation() {
|
||||
setTimeout(function() {
|
||||
descriptionDiv.innerHTML = 'Fructherman layout, gravity = 5';
|
||||
graph.updateLayout({
|
||||
gravity: 5,
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
setTimeout(function() {
|
||||
descriptionDiv.innerHTML = 'Fructherman layout, gravity = 10, layout by cluster';
|
||||
graph.updateLayout({
|
||||
gravity: 10,
|
||||
clustering: true,
|
||||
});
|
||||
}, 2500);
|
||||
|
||||
setTimeout(function() {
|
||||
descriptionDiv.innerHTML = 'Fructherman layout, gravity = 20, layout by cluster';
|
||||
graph.updateLayout({
|
||||
gravity: 20,
|
||||
});
|
||||
}, 4000);
|
||||
|
||||
setTimeout(function() {
|
||||
descriptionDiv.innerHTML = 'Fructherman layout, gravity = 50, layout by cluster';
|
||||
graph.updateLayout({
|
||||
gravity: 50,
|
||||
});
|
||||
}, 5500);
|
||||
|
||||
setTimeout(function() {
|
||||
descriptionDiv.innerHTML = 'Fructherman layout, gravity = 80, layout by cluster';
|
||||
graph.updateLayout({
|
||||
gravity: 80,
|
||||
});
|
||||
}, 7000);
|
||||
}
|
40
examples/net/gpuLayout/demo/meta.json
Normal file
40
examples/net/gpuLayout/demo/meta.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"title": {
|
||||
"zh": "中文分类",
|
||||
"en": "Category"
|
||||
},
|
||||
"demos": [
|
||||
{
|
||||
"filename": "basicFruchterman.js",
|
||||
"title": {
|
||||
"zh": "基本 Fruchterman 布局",
|
||||
"en": "Basic Fruchterman Layout"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*1KY7SLEXxqMAAAAAAAAAAABkARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "fruchtermanComplexData.js",
|
||||
"title": {
|
||||
"zh": "Fruchterman 复杂数据",
|
||||
"en": "Fruchterman with Complex Data"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*0sl9RZ7Cp28AAAAAAAAAAABkARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "fruchtermanClustering.js",
|
||||
"title": {
|
||||
"zh": "Fruchterman 聚类布局",
|
||||
"en": "Fruchterman with Clustering"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*WO1OTbNE_ugAAAAAAAAAAABkARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "fruchtermanConfigurationTranslate.js",
|
||||
"title": {
|
||||
"zh": "Fruchterman 布局参数动态变化",
|
||||
"en": "Update the Configurations for Fruchterman"
|
||||
},
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*W9MoQoKaQbYAAAAAAAAAAABkARQnAQ"
|
||||
}
|
||||
]
|
||||
}
|
15
examples/net/gpuLayout/index.en.md
Normal file
15
examples/net/gpuLayout/index.en.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
title: GPU Layout
|
||||
order: 12
|
||||
---
|
||||
|
||||
Fruchterman Reingold Layout is a kind of force-directed layout in theory. The differences are the definitions of attracitve force and repulsive force.
|
||||
|
||||
## Usage
|
||||
|
||||
As the demo below, you can deploy it in `layout` while instantiating Graph. it can also be used for [Subgraph Layout](/zh/docs/manual/middle/layout/#%E5%AD%90%E5%9B%BE%E5%B8%83%E5%B1%80). By tuning the parameters, you can adjust the iteration number, layout compactness, layout by clusters, and so on.
|
||||
|
||||
- Example 1 : Basic Fruchterman layout.
|
||||
- Example 2 : Fruchterman clustering layout.
|
||||
- Example 3 : Translate the layout parameters in dynamic.
|
||||
- Example 4 : Fruchterman layout with web-worker in case layout calculation takes too long to block page interaction.
|
15
examples/net/gpuLayout/index.zh.md
Normal file
15
examples/net/gpuLayout/index.zh.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
title: GPU 图布局
|
||||
order: 12
|
||||
---
|
||||
|
||||
Fruchterman Reingold 布局算法在原理上而言属于力导向布局算法。其引力与斥力的定义方式与经典的 Force Diected 力导向图布局有少许不同。
|
||||
|
||||
## 使用指南
|
||||
|
||||
G6 内置的 Fruchterman 布局可在实例化 Graph 时使用该布局。除此之外,还可以如[子图布局](/zh/docs/manual/middle/layout/#%E5%AD%90%E5%9B%BE%E5%B8%83%E5%B1%80)所示单独使用布局。该布局可以通过配置调整迭代次数、紧凑程度、是否按照聚类布局等。
|
||||
|
||||
- 代码演示 1 :基本的 Fruchterman 布局。
|
||||
- 代码演示 2 :Fruchterman 的聚类布局。
|
||||
- 代码演示 3 :Fruchterman 布局参数动态变化。
|
||||
- 代码演示 4 :Fruchterman 使用 web-worker 以避免阻塞页面。
|
@ -1,4 +1,4 @@
|
||||
// window.g6 = require('./src/index.ts'); // import the source for debugging
|
||||
window.g6 = require('./dist/g6.min.js'); // import the package for webworker
|
||||
window.g6 = require('./src/index.ts'); // import the source for debugging
|
||||
// window.g6 = require('./dist/g6.min.js'); // import the package for webworker
|
||||
window.insertCss = require('insert-css');
|
||||
window.Chart = require('@antv/chart-node-g6');
|
||||
|
@ -3,10 +3,9 @@
|
||||
* @author shiwu.wyy@antfin.com
|
||||
*/
|
||||
|
||||
import { EdgeConfig, IPointTuple, NodeConfig, NodeIdxMap } from '../types';
|
||||
import { BaseLayout } from './layout';
|
||||
import { EdgeConfig, IPointTuple, NodeConfig, NodeIdxMap } from '../../types';
|
||||
import { BaseLayout } from '../layout';
|
||||
import { isNumber } from '@antv/util';
|
||||
import { Point } from '@antv/g-base';
|
||||
import { World } from '@antv/g-webgpu';
|
||||
|
||||
const lineIndexBufferData = [];
|
||||
@ -56,6 +55,7 @@ const convertWebGLCoord2Canvas = (c: number, size: number) => {
|
||||
return ((c + 1) / 2) * size;
|
||||
}
|
||||
|
||||
|
||||
const gCode = `
|
||||
import { globalInvocationID } from 'g-webgpu';
|
||||
|
||||
@ -74,6 +74,12 @@ class Fruchterman {
|
||||
@in
|
||||
u_K2: float;
|
||||
|
||||
@in
|
||||
u_CenterX: float;
|
||||
|
||||
@in
|
||||
u_CenterY: float;
|
||||
|
||||
@in
|
||||
u_Gravity: float;
|
||||
|
||||
@ -86,15 +92,14 @@ class Fruchterman {
|
||||
calcRepulsive(i: int, currentNode: vec4): vec2 {
|
||||
let dx = 0, dy = 0;
|
||||
for (let j = 0; j < VERTEX_COUNT; j++) {
|
||||
if (i != j + 1) {
|
||||
if (i != j) {
|
||||
const nextNode = this.u_Data[j];
|
||||
const xDist = currentNode[0] - nextNode[0];
|
||||
const yDist = currentNode[1] - nextNode[1];
|
||||
const dist = sqrt(xDist * xDist + yDist * yDist) + 0.01;
|
||||
const dist = (xDist * xDist + yDist * yDist) + 0.01;
|
||||
if (dist > 0.0) {
|
||||
const repulsiveF = this.u_K2 / dist;
|
||||
dx += xDist / dist * repulsiveF;
|
||||
dy += yDist / dist * repulsiveF;
|
||||
dx += this.u_K2 * xDist / dist ;
|
||||
dy += this.u_K2 * yDist / dist ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -102,9 +107,10 @@ class Fruchterman {
|
||||
}
|
||||
|
||||
calcGravity(currentNode: vec4): vec2 {
|
||||
const d = sqrt(currentNode[0] * currentNode[0] + currentNode[1] * currentNode[1]);
|
||||
const gf = 0.01 * this.u_K * this.u_Gravity * d;
|
||||
return [gf * currentNode[0] / d, gf * currentNode[1] / d];
|
||||
const vx = currentNode[0] - this.u_CenterX;
|
||||
const vy = currentNode[1] - this.u_CenterY;
|
||||
const gf = 0.01 * this.u_K * this.u_Gravity;
|
||||
return [gf * vx, gf * vy];
|
||||
}
|
||||
|
||||
calcAttractive(currentNode: vec4): vec2 {
|
||||
@ -128,10 +134,10 @@ class Fruchterman {
|
||||
const xDist = currentNode[0] - nextNode[0];
|
||||
const yDist = currentNode[1] - nextNode[1];
|
||||
const dist = sqrt(xDist * xDist + yDist * yDist) + 0.01;
|
||||
const attractiveF = dist * dist / this.u_K;
|
||||
const attractiveF = dist / this.u_K;
|
||||
if (dist > 0.0) {
|
||||
dx -= xDist / dist * attractiveF;
|
||||
dy -= yDist / dist * attractiveF;
|
||||
dx -= xDist * attractiveF;
|
||||
dy -= yDist * attractiveF;
|
||||
}
|
||||
}
|
||||
return [dx, dy];
|
||||
@ -180,6 +186,8 @@ class Fruchterman {
|
||||
currentNode[3]
|
||||
];
|
||||
}
|
||||
//const currentDis = this.u_MaxDisplace;
|
||||
//this.u_MaxDisplace = currentDis * 0.99;
|
||||
}
|
||||
}
|
||||
`;
|
||||
@ -207,7 +215,7 @@ export default class FruchtermanGPULayout extends BaseLayout {
|
||||
/** 重力大小,影响图的紧凑程度 */
|
||||
public gravity: number = 10;
|
||||
/** 速度 */
|
||||
public speed: number = 1;
|
||||
public speed: number = 0.1;
|
||||
/** 是否产生聚类力 */
|
||||
public clustering: boolean = false;
|
||||
/** 聚类力大小 */
|
||||
@ -230,7 +238,7 @@ export default class FruchtermanGPULayout extends BaseLayout {
|
||||
maxIteration: 1000,
|
||||
center: [0, 0],
|
||||
gravity: 10,
|
||||
speed: 1,
|
||||
speed: 0.1,
|
||||
clustering: false,
|
||||
clusterGravity: 10,
|
||||
};
|
||||
@ -277,8 +285,10 @@ export default class FruchtermanGPULayout extends BaseLayout {
|
||||
self.height = window.innerHeight;
|
||||
}
|
||||
const center = self.center;
|
||||
const maxDisplace = self.width / 10;
|
||||
const k = Math.sqrt((self.width * self.height) / (nodes.length + 1));
|
||||
const area = self.height * self.width;
|
||||
const maxDisplace = Math.sqrt(area) / 10;
|
||||
const k2 = area / (nodes.length + 1);
|
||||
const k = Math.sqrt(k2);
|
||||
const gravity = self.gravity;
|
||||
const speed = self.speed;
|
||||
const clustering = self.clustering;
|
||||
@ -332,13 +342,14 @@ export default class FruchtermanGPULayout extends BaseLayout {
|
||||
const compute = world.createComputePipeline({
|
||||
shader: gCode,
|
||||
dispatch: [numParticles, 1, 1],
|
||||
maxIteration: self.maxIteration,
|
||||
maxIteration,
|
||||
onCompleted: (finalParticleData) => {
|
||||
console.log(maxIteration, gravity, center, k, k2, maxDisplace, speed)
|
||||
self.nodes.forEach((node, i) => {
|
||||
const x = finalParticleData[4 * i];
|
||||
const y = finalParticleData[4 * i + 1];
|
||||
node.x = convertWebGLCoord2Canvas(x, self.width);
|
||||
node.y = convertWebGLCoord2Canvas(y, self.height);
|
||||
node.x = x; //convertWebGLCoord2Canvas(x, self.width);
|
||||
node.y = y; //convertWebGLCoord2Canvas(y, self.height);
|
||||
});
|
||||
self.onLayoutEnd && self.onLayoutEnd();
|
||||
// setTimeElapsed(window.performance.now() - timeStart);
|
||||
@ -357,20 +368,32 @@ export default class FruchtermanGPULayout extends BaseLayout {
|
||||
world.setBinding(
|
||||
compute,
|
||||
'u_K',
|
||||
Math.sqrt((numParticles * numParticles) / (numParticles + 1) / 300),
|
||||
k,
|
||||
);
|
||||
world.setBinding(
|
||||
compute,
|
||||
'u_K2',
|
||||
(numParticles * numParticles) / (numParticles + 1) / 300 / 300,
|
||||
k2,
|
||||
);
|
||||
world.setBinding(compute, 'u_Gravity', 50);
|
||||
world.setBinding(compute, 'u_Speed', 0.1);
|
||||
world.setBinding(
|
||||
compute,
|
||||
'u_CenterX',
|
||||
self.width / 2,
|
||||
);
|
||||
world.setBinding(
|
||||
compute,
|
||||
'u_CenterY',
|
||||
self.height / 2,
|
||||
);
|
||||
world.setBinding(compute, 'u_Gravity', gravity);
|
||||
world.setBinding(compute, 'u_Speed', speed);
|
||||
world.setBinding(
|
||||
compute,
|
||||
'u_MaxDisplace',
|
||||
Math.sqrt(numParticles * numParticles) / 10,
|
||||
maxDisplace,
|
||||
);
|
||||
world.setBinding(compute, 'u_CenterX', center[0]);
|
||||
world.setBinding(compute, 'u_CenterY', center[1]);
|
||||
world.setBinding(compute, 'MAX_EDGE_PER_VERTEX', maxEdgePerVetex);
|
||||
world.setBinding(compute, 'VERTEX_COUNT', numParticles);
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import MDS from './mds';
|
||||
import Radial from './radial/radial';
|
||||
import Random from './random';
|
||||
import ComboForce from './comboForce';
|
||||
import FruchtermanGPU from './gpu/fruchterman';
|
||||
|
||||
const layouts = {
|
||||
circular: Circular,
|
||||
@ -30,6 +31,7 @@ const layouts = {
|
||||
mds: MDS,
|
||||
radial: Radial,
|
||||
random: Random,
|
||||
fruchtermanGPU: FruchtermanGPU
|
||||
};
|
||||
|
||||
// 注册布局
|
||||
|
Loading…
Reference in New Issue
Block a user