test: layout mindmap (#5540)

* test: layout mindmap

* fix: type

* refactor: adjust demo and snapshots

---------

Co-authored-by: Aaron <yangtao.yangtao@antgroup.com>
This commit is contained in:
Joel Alan 2024-03-15 23:30:00 +08:00 committed by GitHub
parent 494779ce0b
commit 7f2e6a58c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 8381 additions and 369 deletions

View File

@ -27,6 +27,10 @@ export * from './layout-fruchterman-cluster';
export * from './layout-fruchterman-fix';
export * from './layout-grid';
export * from './layout-mds';
export * from './layout-mindmap-h';
export * from './layout-mindmap-h-custom-side';
export * from './layout-mindmap-h-left';
export * from './layout-mindmap-h-right';
export * from './layout-radial-basic';
export * from './layout-radial-configuration-translate';
export * from './layout-radial-prevent-overlap';

View File

@ -0,0 +1,60 @@
import type { NodeData } from '@/src';
import { Graph, Utils } from '@/src';
import data from '@@/dataset/algorithm-category.json';
import type { STDTestCase } from '../types';
export const layoutMindmapHCustomSide: STDTestCase = async (context) => {
const graph = new Graph({
...context,
data: Utils.treeToGraphData(data),
autoFit: 'view',
node: {
style: (model) => {
const x = +model.style!.x!;
return {
labelText: model.id,
size: 26,
labelPlacement: x > 0 ? 'right' : 'left',
labelMaxWidth: 200,
labelTextAlign: x > 0 ? 'start' : 'end',
lineWidth: 1,
stroke: '#5F95FF',
fill: '#EFF4FF',
ports: [{ placement: 'right' }, { placement: 'left' }],
};
},
},
edge: {
style: {
type: 'cubic-horizontal',
},
},
layout: {
type: 'mindmap',
direction: 'H',
getHeight: () => {
return 16;
},
getWidth: () => {
return 16;
},
getVGap: () => {
return 10;
},
getHGap: () => {
return 50;
},
getSide: (d: NodeData) => {
if (d.id === 'Classification') {
return 'left';
}
return 'right';
},
},
behaviors: ['collapse-expand', 'drag-canvas', 'zoom-canvas'],
});
await graph.render();
return graph;
};

View File

@ -0,0 +1,55 @@
import { Graph, Utils } from '@/src';
import data from '@@/dataset/algorithm-category.json';
import type { STDTestCase } from '../types';
export const layoutMindmapHLeft: STDTestCase = async (context) => {
const graph = new Graph({
...context,
data: Utils.treeToGraphData(data),
autoFit: 'view',
node: {
style: (model) => {
return {
labelText: model.id,
size: 26,
labelPlacement: 'left',
labelMaxWidth: 200,
labelTextAlign: 'end',
lineWidth: 1,
stroke: '#5F95FF',
fill: '#EFF4FF',
ports: [{ placement: 'right' }, { placement: 'left' }],
};
},
},
edge: {
style: {
type: 'cubic-horizontal',
},
},
layout: {
type: 'mindmap',
direction: 'H',
getHeight: () => {
return 16;
},
getWidth: () => {
return 16;
},
getVGap: () => {
return 10;
},
getHGap: () => {
return 100;
},
getSide: () => {
return 'left';
},
},
behaviors: ['collapse-expand', 'drag-canvas', 'zoom-canvas'],
});
await graph.render();
return graph;
};

View File

@ -0,0 +1,54 @@
import { Graph, Utils } from '@/src';
import data from '@@/dataset/algorithm-category.json';
import type { STDTestCase } from '../types';
export const layoutMindmapHRight: STDTestCase = async (context) => {
const graph = new Graph({
...context,
data: Utils.treeToGraphData(data),
autoFit: 'view',
node: {
style: (model) => {
return {
labelText: model.id,
size: 26,
labelPlacement: 'right',
labelMaxWidth: 200,
lineWidth: 1,
stroke: '#5F95FF',
fill: '#EFF4FF',
ports: [{ placement: 'right' }, { placement: 'left' }],
};
},
},
edge: {
style: {
type: 'cubic-horizontal',
},
},
layout: {
type: 'mindmap',
direction: 'H',
getHeight: () => {
return 16;
},
getWidth: () => {
return 16;
},
getVGap: () => {
return 10;
},
getHGap: () => {
return 100;
},
getSide: () => {
return 'right';
},
},
behaviors: ['collapse-expand', 'drag-canvas', 'zoom-canvas'],
});
await graph.render();
return graph;
};

View File

@ -0,0 +1,53 @@
import { Graph, Utils } from '@/src';
import data from '@@/dataset/algorithm-category.json';
import type { STDTestCase } from '../types';
export const layoutMindmapH: STDTestCase = async (context) => {
const graph = new Graph({
...context,
data: Utils.treeToGraphData(data),
autoFit: 'view',
node: {
style: (model) => {
const x = +model.style!.x!;
return {
labelText: model.id,
size: 26,
labelPlacement: x > 0 ? 'right' : 'left',
labelMaxWidth: 200,
labelTextAlign: x > 0 ? 'start' : 'end',
lineWidth: 1,
stroke: '#5F95FF',
fill: '#EFF4FF',
ports: [{ placement: 'right' }, { placement: 'left' }],
};
},
},
edge: {
style: {
type: 'cubic-horizontal',
},
},
layout: {
type: 'mindmap',
direction: 'H',
getHeight: () => {
return 16;
},
getWidth: () => {
return 16;
},
getVGap: () => {
return 10;
},
getHGap: () => {
return 50;
},
},
behaviors: ['collapse-expand', 'drag-canvas', 'zoom-canvas'],
});
await graph.render();
return graph;
};

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 56 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 56 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 56 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 56 KiB

View File

@ -0,0 +1,28 @@
import { layoutMindmapH, layoutMindmapHCustomSide, layoutMindmapHLeft, layoutMindmapHRight } from '@@/demo/case';
import { createDemoGraph } from '@@/utils';
describe('mindmap', () => {
it('h custom side', async () => {
const graph = await createDemoGraph(layoutMindmapHCustomSide);
await expect(graph).toMatchSnapshot(__filename, 'h-custom-side');
graph.destroy();
});
it('h left', async () => {
const graph = await createDemoGraph(layoutMindmapHLeft);
await expect(graph).toMatchSnapshot(__filename, 'h-left');
graph.destroy();
});
it('h', async () => {
const graph = await createDemoGraph(layoutMindmapH);
await expect(graph).toMatchSnapshot(__filename, 'h');
graph.destroy();
});
it('h right', async () => {
const graph = await createDemoGraph(layoutMindmapHRight);
await expect(graph).toMatchSnapshot(__filename, 'h-right');
graph.destroy();
});
});

View File

@ -1,169 +0,0 @@
import { Graph, Extensions, extend } from '@antv/g6';
const ExtGraph = extend(Graph, {
edges: {
'cubic-horizontal-edge': Extensions.CubicHorizontalEdge,
},
});
const layoutConfigs = {
Right: {
type: 'mindmap',
direction: 'H',
getHeight: () => {
return 16;
},
getWidth: () => {
return 16;
},
getVGap: () => {
return 10;
},
getHGap: () => {
return 20;
},
getSide: undefined,
},
Left: {
type: 'mindmap',
direction: 'H',
getHeight: () => {
return 16;
},
getWidth: () => {
return 16;
},
getVGap: () => {
return 10;
},
getHGap: () => {
return 20;
},
getSide: () => {
return 'left';
},
},
};
const container = document.getElementById('container');
const width = container.scrollWidth;
const height = container.scrollHeight || 500;
fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/relations.json')
.then((res) => res.json())
.then((data) => {
const graph = new ExtGraph({
container,
width,
height,
transforms: [
{
type: 'transform-v4-data',
activeLifecycle: ['read'],
},
],
modes: {
default: ['drag-canvas', 'zoom-canvas', 'drag-node', 'collapse-expand-tree'],
},
node: (model) => {
return {
id: model.id,
data: {
...model.data,
lodLevels: [],
labelShape: {
text: model.id,
position: 'center',
maxWidth: '120%',
},
labelBackgroundShape: {},
anchorPoints:
model.data.layoutDirection === 'TB'
? [
[0.5, 0],
[0.5, 1],
]
: [
[0, 0.5],
[1, 0.5],
],
animates: {
update: [
{
fields: ['x', 'y'],
duration: 500,
shapeId: 'group',
order: 0,
},
],
hide: [
{
fields: ['opacity'],
duration: 200,
shapeId: 'keyShape',
},
{
fields: ['opacity'],
duration: 200,
shapeId: 'labelShape',
},
],
show: [
{
fields: ['opacity'],
duration: 1000,
shapeId: 'keyShape',
},
{
fields: ['opacity'],
duration: 1000,
shapeId: 'labelShape',
},
],
},
},
};
},
edge: {
type: 'cubic-horizontal-edge',
keyShape: {
opacity: 0.5,
endArrow: true,
},
},
layout: layoutConfigs.Right,
autoFit: 'view',
data: {
type: 'graphData',
value: data,
},
});
const btnContainer = document.createElement('div');
btnContainer.style.position = 'absolute';
container.appendChild(btnContainer);
const tip = document.createElement('span');
tip.innerHTML = '👉 Change configs:';
btnContainer.appendChild(tip);
Object.keys(layoutConfigs).forEach((name, i) => {
const btn = document.createElement('a');
btn.innerHTML = name;
btn.style.backgroundColor = 'rgba(255, 255, 255, 0.8)';
btn.style.padding = '4px';
btn.style.marginLeft = i > 0 ? '24px' : '8px';
btnContainer.appendChild(btn);
btn.addEventListener('click', () => {
const updateNodes = graph.getAllNodesData().map((node) => ({
id: node.id,
data: {
layoutDirection: name,
},
}));
graph.updateData('node', updateNodes);
graph.layout(layoutConfigs[name]);
});
});
window.graph = graph;
});

View File

@ -0,0 +1,64 @@
import { Graph, Utils } from '@antv/g6';
fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/algorithm-category.json')
.then((res) => res.json())
.then((data) => {
const graph = new Graph({
container: 'container',
autoFit: 'view',
data: Utils.treeToGraphData(data),
node: {
style: (model) => {
const x = +model.style!.x!;
return {
labelText: model.id,
size: 26,
labelPlacement: x > 0 ? 'right' : 'left',
labelMaxWidth: 200,
labelTextAlign: x > 0 ? 'start' : 'end',
lineWidth: 1,
stroke: '#5F95FF',
fill: '#EFF4FF',
ports: [
{
placement: 'right',
},
{
placement: 'left',
},
],
};
},
},
edge: {
style: {
type: 'cubic-horizontal',
},
},
layout: {
type: 'mindmap',
direction: 'H',
getHeight: () => {
return 16;
},
getWidth: () => {
return 16;
},
getVGap: () => {
return 10;
},
getHGap: () => {
return 50;
},
getSide: (d) => {
if (d.id === 'Classification') {
return 'left';
}
return 'right';
},
},
behaviors: ['collapse-expand', 'drag-canvas', 'zoom-canvas'],
});
graph.render();
});

View File

@ -0,0 +1,60 @@
import { Graph, Utils } from '@antv/g6';
fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/algorithm-category.json')
.then((res) => res.json())
.then((data) => {
const graph = new Graph({
container: 'container',
autoFit: 'view',
data: Utils.treeToGraphData(data),
node: {
style: (model) => {
return {
labelText: model.id,
size: 26,
labelPlacement: 'left',
labelMaxWidth: 200,
labelTextAlign: 'end',
lineWidth: 1,
stroke: '#5F95FF',
fill: '#EFF4FF',
ports: [
{
placement: 'right',
},
{
placement: 'left',
},
],
};
},
},
edge: {
style: {
type: 'cubic-horizontal',
},
},
layout: {
type: 'mindmap',
direction: 'H',
getHeight: () => {
return 16;
},
getWidth: () => {
return 16;
},
getVGap: () => {
return 10;
},
getHGap: () => {
return 100;
},
getSide: () => {
return 'left';
},
},
behaviors: ['collapse-expand', 'drag-canvas', 'zoom-canvas'],
});
graph.render();
});

View File

@ -1,194 +0,0 @@
import { Graph, Extensions, extend } from '@antv/g6';
const ExtGraph = extend(Graph, {
edges: {
'cubic-horizontal-edge': Extensions.CubicHorizontalEdge,
},
});
const layoutConfigs = {
'Two Side': {
type: 'mindmap',
direction: 'H',
getHeight: () => {
return 16;
},
getWidth: () => {
return 16;
},
getVGap: () => {
return 10;
},
getHGap: () => {
return 100;
},
getSide: undefined,
},
Right: {
type: 'mindmap',
direction: 'H',
getHeight: () => {
return 16;
},
getWidth: () => {
return 16;
},
getVGap: () => {
return 10;
},
getHGap: () => {
return 100;
},
getSide: () => {
return 'right';
},
},
Left: {
type: 'mindmap',
direction: 'H',
getHeight: () => {
return 16;
},
getWidth: () => {
return 16;
},
getVGap: () => {
return 10;
},
getHGap: () => {
return 100;
},
getSide: () => {
return 'left';
},
},
};
const container = document.getElementById('container');
const width = container.scrollWidth;
const height = container.scrollHeight || 500;
fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/algorithm-category.json')
.then((res) => res.json())
.then((data) => {
const graph = new ExtGraph({
container,
width,
height,
transforms: [
{
type: 'transform-v4-data',
activeLifecycle: ['read'],
},
],
modes: {
default: ['drag-canvas', 'zoom-canvas', 'drag-node', 'collapse-expand-tree'],
},
node: (model) => {
const configRelatedToLayout =
model.data.layoutDirection === 'TB'
? {
labelShape: {
text: model.id,
position: 'bottom',
offsetX: 0,
},
anchorPoints: [
[0.5, 0],
[0.5, 1],
],
}
: {
labelShape: {
text: model.id,
position: model.data.childrenIds?.length ? 'left' : 'right',
offsetX: model.data.childrenIds?.length ? -10 : 10,
maxWidth: '300%',
},
anchorPoints: [
[0, 0.5],
[1, 0.5],
],
};
return {
id: model.id,
data: {
...model.data,
labelBackgroundShape: {},
...configRelatedToLayout,
animates: {
update: [
{
fields: ['x', 'y'],
duration: 500,
shapeId: 'group',
order: 0,
},
],
hide: [
{
fields: ['opacity'],
duration: 200,
shapeId: 'keyShape',
},
{
fields: ['opacity'],
duration: 200,
shapeId: 'labelShape',
},
],
show: [
{
fields: ['opacity'],
duration: 1000,
shapeId: 'keyShape',
},
{
fields: ['opacity'],
duration: 1000,
shapeId: 'labelShape',
},
],
},
},
};
},
edge: {
type: 'cubic-horizontal-edge',
},
layout: layoutConfigs['Two Side'],
autoFit: 'view',
data: {
type: 'treeData',
value: data,
},
});
const btnContainer = document.createElement('div');
btnContainer.style.position = 'absolute';
container.appendChild(btnContainer);
const tip = document.createElement('span');
tip.innerHTML = '👉 Change configs:';
btnContainer.appendChild(tip);
Object.keys(layoutConfigs).forEach((name, i) => {
const btn = document.createElement('a');
btn.innerHTML = name;
btn.style.backgroundColor = 'rgba(255, 255, 255, 0.8)';
btn.style.padding = '4px';
btn.style.marginLeft = i > 0 ? '24px' : '8px';
btnContainer.appendChild(btn);
btn.addEventListener('click', () => {
const updateNodes = graph.getAllNodesData().map((node) => ({
id: node.id,
data: {
layoutDirection: name,
},
}));
graph.updateData('node', updateNodes);
graph.layout(layoutConfigs[name]);
});
});
window.graph = graph;
});

View File

@ -0,0 +1,58 @@
import { Graph, Utils } from '@antv/g6';
fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/algorithm-category.json')
.then((res) => res.json())
.then((data) => {
const graph = new Graph({
container: 'container',
autoFit: 'view',
data: Utils.treeToGraphData(data),
node: {
style: (model) => {
const x = +model.style!.x!;
return {
labelText: model.id,
size: 26,
labelPlacement: x > 0 ? 'right' : 'left',
labelMaxWidth: 200,
labelTextAlign: x > 0 ? 'start' : 'end',
lineWidth: 1,
stroke: '#5F95FF',
fill: '#EFF4FF',
ports: [
{
placement: 'right',
},
{
placement: 'left',
},
],
};
},
},
edge: {
style: {
type: 'cubic-horizontal',
},
},
layout: {
type: 'mindmap',
direction: 'H',
getHeight: () => {
return 16;
},
getWidth: () => {
return 16;
},
getVGap: () => {
return 10;
},
getHGap: () => {
return 50;
},
},
behaviors: ['collapse-expand', 'drag-canvas', 'zoom-canvas'],
});
graph.render();
});

View File

@ -0,0 +1,59 @@
import { Graph, Utils } from '@antv/g6';
fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/algorithm-category.json')
.then((res) => res.json())
.then((data) => {
const graph = new Graph({
container: 'container',
autoFit: 'view',
data: Utils.treeToGraphData(data),
node: {
style: (model) => {
return {
labelText: model.id,
size: 26,
labelPlacement: 'right',
labelMaxWidth: 200,
lineWidth: 1,
stroke: '#5F95FF',
fill: '#EFF4FF',
ports: [
{
placement: 'right',
},
{
placement: 'left',
},
],
};
},
},
edge: {
style: {
type: 'cubic-horizontal',
},
},
layout: {
type: 'mindmap',
direction: 'H',
getHeight: () => {
return 16;
},
getWidth: () => {
return 16;
},
getVGap: () => {
return 10;
},
getHGap: () => {
return 100;
},
getSide: () => {
return 'right';
},
},
behaviors: ['collapse-expand', 'drag-canvas', 'zoom-canvas'],
});
graph.render();
});

View File

@ -5,20 +5,36 @@
},
"demos": [
{
"filename": "hMindmap.js",
"filename": "hMindmap.ts",
"title": {
"zh": "脑图树-子节点自动两侧分布",
"en": "Two Side Mindmap Layout"
},
"screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*noXTS5TOPdwAAAAAAAAAAAAADmJ7AQ/original"
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*wRZjTL3fCbEAAAAAAAAAAABkARQnAQ"
},
{
"filename": "graphWithMindmap.js",
"filename": "hRightMindmap.ts",
"title": {
"zh": "图数据使用脑图树",
"en": "Mindmap Layout with Graph Data"
"zh": "脑图树-子节点右侧分布",
"en": "Right Side Mindmap Layout"
},
"screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*VzdkSbUVWfoAAAAAAAAAAAAADmJ7AQ/original"
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*W6OGRLg2UJcAAAAAAAAAAABkARQnAQ"
},
{
"filename": "hLeftMindmap.ts",
"title": {
"zh": "脑图树-子节点左侧分布",
"en": "Left Side Mindmap Layout"
},
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*NNUaTaN9yIgAAAAAAAAAAABkARQnAQ"
},
{
"filename": "hCustomSideMindmap.ts",
"title": {
"zh": "脑图树-自定义子节点分布",
"en": "Custom Mindmap Layout"
},
"screenshot": "https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*Su39QqQr9PYAAAAAAAAAAABkARQnAQ"
}
]
}