mirror of
https://gitee.com/antv/g6.git
synced 2024-11-30 10:48:24 +08:00
667 lines
17 KiB
TypeScript
667 lines
17 KiB
TypeScript
import { TreeGraph } from '../../../src';
|
||
import { timerOut } from '../util/timeOut';
|
||
|
||
const div = document.createElement('div');
|
||
div.id = 'tree-spec';
|
||
document.body.appendChild(div);
|
||
|
||
describe('tree graph without animate', () => {
|
||
let graph = new TreeGraph({
|
||
container: div,
|
||
width: 500,
|
||
height: 500,
|
||
animate: false,
|
||
modes: {
|
||
default: ['drag-canvas', 'drag-node'],
|
||
},
|
||
layout: {
|
||
type: 'dendrogram',
|
||
direction: 'LR', // H / V / LR / RL / TB / BT
|
||
nodeSep: 50,
|
||
rankSep: 100,
|
||
},
|
||
});
|
||
|
||
it('layout init & findDataById', () => {
|
||
const data = {
|
||
isRoot: true,
|
||
id: 'Root',
|
||
children: [
|
||
{
|
||
id: 'SubTreeNode1',
|
||
children: [
|
||
{
|
||
id: 'SubTreeNode1.1',
|
||
},
|
||
{
|
||
id: 'SubTreeNode1.2',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'SubTreeNode2',
|
||
},
|
||
],
|
||
};
|
||
graph.data(data);
|
||
graph.render();
|
||
graph.fitView();
|
||
|
||
expect(Object.keys(graph.get('itemMap')).length).toBe(9);
|
||
|
||
const edge = graph.findById('Root:SubTreeNode1');
|
||
expect(edge).not.toBe(undefined);
|
||
|
||
expect(edge.get('source')).toEqual(graph.findById('Root'));
|
||
expect(edge.get('target')).toEqual(graph.findById('SubTreeNode1'));
|
||
|
||
expect(graph.save()).toEqual(data);
|
||
|
||
// findDataById
|
||
const nodeData = graph.findDataById('Root', data);
|
||
expect(nodeData).toEqual(data);
|
||
});
|
||
|
||
it('layout without data & isLayoutAnimating', () => {
|
||
graph.data(null);
|
||
expect(() => {
|
||
graph.render();
|
||
}).toThrowError('data must be defined first');
|
||
|
||
graph.stopLayoutAnimate();
|
||
expect(graph.isLayoutAnimating()).toBe(false);
|
||
});
|
||
|
||
it('changeData', () => {
|
||
const data = {
|
||
isRoot: true,
|
||
id: 'Root',
|
||
children: [
|
||
{
|
||
id: 'SubTreeNode1',
|
||
children: [
|
||
{
|
||
id: 'SubTreeNode1.1',
|
||
},
|
||
{
|
||
id: 'SubTreeNode1.2',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'SubTreeNode3',
|
||
},
|
||
{
|
||
id: 'SubTreeNode4',
|
||
children: [{ id: 'SubTreeNode4.1' }],
|
||
},
|
||
],
|
||
};
|
||
graph.changeData(data);
|
||
expect(graph.save()).toEqual(data);
|
||
|
||
expect(Object.keys(graph.get('itemMap')).length).toBe(13);
|
||
expect(graph.findById('SubTreeNode2')).toBe(undefined);
|
||
expect(graph.findById('SubTreeNode3')).not.toBe(undefined);
|
||
expect(graph.findById('SubTreeNode4')).not.toBe(undefined);
|
||
|
||
const edge = graph.findById('SubTreeNode4:SubTreeNode4.1');
|
||
expect(edge).not.toBe(undefined);
|
||
expect(edge.get('source')).toEqual(graph.findById('SubTreeNode4'));
|
||
expect(edge.get('target')).toEqual(graph.findById('SubTreeNode4.1'));
|
||
});
|
||
|
||
it('add child', () => {
|
||
const parent = graph.findById('SubTreeNode3');
|
||
|
||
const child = {
|
||
id: 'SubTreeNode3.1',
|
||
x: 100,
|
||
y: 100,
|
||
type: 'rect',
|
||
children: [{ x: 150, y: 150, id: 'SubTreeNode3.1.1' }],
|
||
};
|
||
graph.on('afteraddchild', function (e) {
|
||
expect(
|
||
e.item.getModel().id === 'SubTreeNode3.1' || e.item.getModel().id === 'SubTreeNode3.1.1',
|
||
).toBe(true);
|
||
expect(
|
||
e.item.get('parent').getModel().id === 'SubTreeNode3' ||
|
||
e.item.get('parent').getModel().id === 'SubTreeNode3.1',
|
||
).toBe(true);
|
||
expect(
|
||
e.parent.getModel().id === 'SubTreeNode3' || e.parent.getModel().id === 'SubTreeNode3.1',
|
||
).toBe(true);
|
||
});
|
||
|
||
graph.addChild(child, parent);
|
||
|
||
const children = parent.get('model').children;
|
||
expect(children).not.toBe(undefined);
|
||
expect(children.length).toBe(1);
|
||
expect(children[0].id).toEqual('SubTreeNode3.1');
|
||
|
||
expect(graph.findById('SubTreeNode3.1')).not.toBe(undefined);
|
||
expect(graph.findById('SubTreeNode3:SubTreeNode3.1')).not.toBe(undefined);
|
||
expect(graph.findById('SubTreeNode3.1.1')).not.toBe(undefined);
|
||
expect(graph.findById('SubTreeNode3.1:SubTreeNode3.1.1')).not.toBe(undefined);
|
||
});
|
||
|
||
it('remove child & remove nonexistent child', () => {
|
||
graph.removeChild('SubTreeNode3.1');
|
||
|
||
const parent = graph.findById('SubTreeNode3');
|
||
const children = parent.get('model').children;
|
||
|
||
expect(children.length).toBe(0);
|
||
expect(graph.findById('SubTreeNode3.1')).toBe(undefined);
|
||
expect(graph.findById('SubTreeNode3:SubTreeNode3.1')).toBe(undefined);
|
||
expect(graph.findById('SubTreeNode3.1.1')).toBe(undefined);
|
||
expect(graph.findById('SubTreeNode3.1:SubTreeNode3.1.1')).toBe(undefined);
|
||
|
||
const none = graph.removeChild('none-child');
|
||
expect(none).toBe(undefined);
|
||
});
|
||
|
||
it('collapse & expand with layout', () => {
|
||
const parent = graph.findById('SubTreeNode1');
|
||
let child = graph.findById('SubTreeNode1.1');
|
||
let collapsed = true;
|
||
graph.on('afterrefreshlayout', () => {
|
||
if (collapsed) {
|
||
expect(parent.getModel().collapsed).toBe(true);
|
||
expect(child.destroyed).toBe(true);
|
||
} else {
|
||
child = graph.findById('SubTreeNode1.1');
|
||
expect(parent.getModel().collapsed).toBe(false);
|
||
expect(child.get('model').x).not.toEqual(parent.get('model').x);
|
||
expect(!!child.getModel().collapsed).toBe(false);
|
||
expect(child.get('model').y).not.toEqual(parent.get('model').y);
|
||
}
|
||
});
|
||
graph.addBehaviors('collapse-expand', 'default');
|
||
graph.emit('node:click', { item: parent });
|
||
timerOut(() => {
|
||
collapsed = false;
|
||
graph.emit('node:click', { item: parent });
|
||
}, 600);
|
||
// graph.destroy();
|
||
});
|
||
|
||
it('collapse & expand with layout with parameter trigger=dblclick', () => {
|
||
graph = new TreeGraph({
|
||
container: div,
|
||
width: 500,
|
||
height: 500,
|
||
animate: false,
|
||
modes: {
|
||
default: ['drag-canvas', 'drag-node'],
|
||
},
|
||
layout: {
|
||
type: 'dendrogram',
|
||
direction: 'LR', // H / V / LR / RL / TB / BT
|
||
nodeSep: 50,
|
||
rankSep: 100,
|
||
},
|
||
});
|
||
const data = {
|
||
isRoot: true,
|
||
id: 'Root',
|
||
children: [
|
||
{
|
||
id: 'SubTreeNode1',
|
||
children: [
|
||
{
|
||
id: 'SubTreeNode1.1',
|
||
},
|
||
{
|
||
id: 'SubTreeNode1.2',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'SubTreeNode2',
|
||
},
|
||
],
|
||
};
|
||
graph.data(data);
|
||
graph.render();
|
||
const parent = graph.findById('SubTreeNode1');
|
||
parent.getModel().label = 'parent';
|
||
let child = graph.findById('SubTreeNode1.1');
|
||
let collapsed = true;
|
||
graph.addBehaviors(
|
||
[
|
||
{
|
||
type: 'collapse-expand',
|
||
trigger: 'dblclick',
|
||
},
|
||
],
|
||
'default',
|
||
);
|
||
graph.on('afterrefreshlayout', () => {
|
||
if (collapsed) {
|
||
expect(parent.getModel().collapsed).toBe(true);
|
||
expect(child.destroyed).toBe(true);
|
||
} else {
|
||
child = graph.findById('SubTreeNode1.1');
|
||
expect(parent.getModel().collapsed).toBe(false);
|
||
expect(child.get('model').x).not.toEqual(parent.get('model').x);
|
||
expect(!!child.getModel().collapsed).toBe(false);
|
||
expect(child.get('model').y).not.toEqual(parent.get('model').y);
|
||
}
|
||
});
|
||
graph.emit('node:dblclick', { item: parent });
|
||
timerOut(() => {
|
||
collapsed = false;
|
||
graph.emit('node:dblclick', { item: parent });
|
||
}, 600);
|
||
});
|
||
});
|
||
|
||
describe('update child', () => {
|
||
const graph = new TreeGraph({
|
||
container: div,
|
||
width: 500,
|
||
height: 500,
|
||
animate: false,
|
||
modes: {
|
||
default: ['drag-canvas', 'drag-node'],
|
||
},
|
||
layout: {
|
||
type: 'dendrogram',
|
||
direction: 'LR', // H / V / LR / RL / TB / BT
|
||
nodeSep: 50,
|
||
rankSep: 100,
|
||
},
|
||
});
|
||
|
||
const data = {
|
||
isRoot: true,
|
||
id: 'Root',
|
||
children: [
|
||
{
|
||
id: 'SubTreeNode1',
|
||
},
|
||
{
|
||
id: 'SubTreeNode3',
|
||
},
|
||
],
|
||
};
|
||
graph.data(data);
|
||
graph.render();
|
||
|
||
it('updateChild & parent is not undefined', () => {
|
||
const child = {
|
||
id: 'SubTreeNode3.1',
|
||
x: 150,
|
||
y: 150,
|
||
type: 'rect',
|
||
children: [{ x: 250, y: 150, id: 'SubTreeNode3.1.1' }],
|
||
};
|
||
|
||
// 第一种情况,parent存在,添加的数据不存在
|
||
graph.updateChild(child, 'SubTreeNode3');
|
||
// 更新以后,SubTreeNode3 节点后会有子元素
|
||
const subNode = graph.findById('SubTreeNode3');
|
||
const children = subNode.get('children');
|
||
expect(children).not.toBe(undefined);
|
||
expect(children.length).toBe(1);
|
||
|
||
const subNode3 = graph.findById('SubTreeNode3.1');
|
||
const mode = subNode3.getModel();
|
||
expect(mode.x).toBe(182);
|
||
expect(mode.y).toBe(-24);
|
||
expect(mode.type).toEqual('rect');
|
||
expect(subNode3.get('currentShape')).toEqual('rect');
|
||
expect(subNode3.get('children')).not.toBe(undefined);
|
||
expect(subNode3.get('children').length).toBe(1);
|
||
|
||
// 第二种情况,parent存在,添加的数据存在
|
||
const treeGraphData = {
|
||
id: 'SubTreeNode3.1',
|
||
x: 120,
|
||
y: 156,
|
||
type: 'circle',
|
||
};
|
||
graph.updateChild(treeGraphData, 'SubTreeNode3');
|
||
|
||
const node = graph.findById('SubTreeNode3.1');
|
||
const model1 = node.getModel();
|
||
expect(model1.x).toBe(182);
|
||
expect(model1.y).toBe(-24);
|
||
expect(model1.type).toEqual('circle');
|
||
expect(node.get('children').length).toBe(0);
|
||
});
|
||
|
||
it('updateChild & parent is undefined', () => {
|
||
const child = {
|
||
id: 'SubTreeNode3.1',
|
||
x: 150,
|
||
y: 150,
|
||
type: 'rect',
|
||
children: [{ x: 250, y: 150, id: 'SubTreeNode3.1.1' }],
|
||
};
|
||
|
||
// 更新子元素,parent不存在
|
||
graph.updateChild(child);
|
||
|
||
// 之前的数据全都被重置
|
||
expect(graph.findById('Root')).toBe(undefined);
|
||
expect(graph.findById('SubTreeNode3')).toBe(undefined);
|
||
const node = graph.findById('SubTreeNode3.1');
|
||
expect(node).not.toBe(undefined);
|
||
expect(node.get('children')).not.toBe(undefined);
|
||
expect(node.get('children').length).toBe(1);
|
||
graph.destroy();
|
||
});
|
||
});
|
||
|
||
describe('updateLayout, layout', () => {
|
||
const graph = new TreeGraph({
|
||
container: div,
|
||
width: 500,
|
||
height: 500,
|
||
animate: false,
|
||
modes: {
|
||
default: ['drag-canvas', 'drag-node'],
|
||
},
|
||
layout: {
|
||
type: 'dendrogram',
|
||
direction: 'LR', // H / V / LR / RL / TB / BT
|
||
nodeSep: 50,
|
||
rankSep: 100,
|
||
},
|
||
});
|
||
|
||
const data = {
|
||
isRoot: true,
|
||
id: 'Root',
|
||
children: [
|
||
{
|
||
id: 'SubTreeNode1',
|
||
children: [
|
||
{
|
||
id: '1.1',
|
||
},
|
||
{
|
||
id: '1.2',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'SubTreeNode3',
|
||
children: [
|
||
{
|
||
id: '3.1',
|
||
},
|
||
{
|
||
id: '3.2',
|
||
},
|
||
],
|
||
},
|
||
],
|
||
};
|
||
graph.data(data);
|
||
graph.render();
|
||
|
||
it('updateLayout', () => {
|
||
graph.moveTo(100, 200);
|
||
const item = graph.getNodes()[1];
|
||
const model = item.getModel();
|
||
const beforeChangePos = [model.x, model.y];
|
||
graph.updateLayout({
|
||
type: 'compactBox',
|
||
direction: 'LR',
|
||
});
|
||
const afterChangePos = [model.x, model.y];
|
||
expect(beforeChangePos[0]).not.toBe(afterChangePos[0]);
|
||
expect(beforeChangePos[1]).not.toBe(afterChangePos[1]);
|
||
|
||
// changeLayout will be discarded soon.
|
||
graph.changeLayout({
|
||
type: 'mindmap',
|
||
direction: 'H',
|
||
});
|
||
const afterChangePos2 = [model.x, model.y];
|
||
expect(afterChangePos[1]).not.toBe(afterChangePos2[1]);
|
||
|
||
// updateLayout without layout
|
||
graph.updateLayout(null);
|
||
const afterChangePos3 = [model.x, model.y];
|
||
expect(afterChangePos2[0]).toBe(afterChangePos3[0]);
|
||
expect(afterChangePos2[1]).toBe(afterChangePos3[1]);
|
||
});
|
||
|
||
it('refreshLayout', () => {
|
||
data.children.push({
|
||
id: 'newSubTree',
|
||
children: [],
|
||
});
|
||
graph.refreshLayout();
|
||
expect(graph.getNodes().length).toBe(8);
|
||
graph.refreshLayout(true);
|
||
expect(graph.getNodes().length).toBe(8);
|
||
});
|
||
});
|
||
|
||
describe('tree graph with animate', () => {
|
||
const graph3 = new TreeGraph({
|
||
container: div,
|
||
width: 500,
|
||
height: 500,
|
||
animate: true,
|
||
modes: {
|
||
default: ['drag-canvas'],
|
||
},
|
||
layout: {
|
||
type: 'dendrogram',
|
||
direction: 'LR',
|
||
nodeSep: 50,
|
||
rankSep: 100,
|
||
},
|
||
});
|
||
it('layout init', () => {
|
||
const data2 = {
|
||
isRoot: true,
|
||
id: 'Root',
|
||
children: [
|
||
{
|
||
id: 'SubTreeNode1',
|
||
label: 'SubTreeNode1',
|
||
children: [
|
||
{
|
||
id: 'SubTreeNode1.1',
|
||
},
|
||
{
|
||
id: 'SubTreeNode1.2',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'SubTreeNode2',
|
||
},
|
||
],
|
||
};
|
||
graph3.data(data2);
|
||
graph3.render();
|
||
graph3.fitView();
|
||
|
||
const layoutMethod = graph3.get('layoutMethod');
|
||
|
||
expect(layoutMethod).not.toBe(undefined);
|
||
expect(typeof layoutMethod).toEqual('function');
|
||
|
||
expect(Object.keys(graph3.get('itemMap')).length).toEqual(9);
|
||
|
||
const edge = graph3.findById('Root:SubTreeNode1');
|
||
expect(edge).not.toBe(undefined);
|
||
|
||
expect(edge.get('source')).toEqual(graph3.findById('Root'));
|
||
expect(edge.get('target')).toEqual(graph3.findById('SubTreeNode1'));
|
||
expect(graph3.save()).toEqual(data2);
|
||
});
|
||
it('changeData', () => {
|
||
graph3.off();
|
||
const data3 = {
|
||
isRoot: true,
|
||
id: 'Root',
|
||
children: [
|
||
{
|
||
id: 'SubTreeNode1',
|
||
label: 'SubTreeNode1',
|
||
children: [
|
||
{
|
||
id: 'SubTreeNode1.1',
|
||
},
|
||
{
|
||
id: 'SubTreeNode1.2',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
id: 'SubTreeNode3',
|
||
},
|
||
{
|
||
id: 'SubTreeNode4',
|
||
children: [{ id: 'SubTreeNode4.1' }],
|
||
},
|
||
],
|
||
};
|
||
|
||
graph3.on('afteranimate', () => {
|
||
expect(Object.keys(graph3.get('itemMap')).length).toEqual(13);
|
||
|
||
expect(graph3.findById('SubTreeNode2')).toBe(undefined);
|
||
expect(graph3.findById('SubTreeNode3')).not.toBe(undefined);
|
||
expect(graph3.findById('SubTreeNode4')).not.toBe(undefined);
|
||
|
||
const edge = graph3.findById('SubTreeNode4:SubTreeNode4.1');
|
||
|
||
expect(edge).not.toBe(undefined);
|
||
expect(edge.get('source')).toEqual(graph3.findById('SubTreeNode4'));
|
||
expect(edge.get('target')).toEqual(graph3.findById('SubTreeNode4.1'));
|
||
});
|
||
|
||
graph3.changeData(data3);
|
||
|
||
expect(graph3.save()).toEqual(data3);
|
||
});
|
||
it('collapse & expand with parameter trigger=dblclick', (done) => {
|
||
graph3.off();
|
||
graph3.moveTo(100, 150);
|
||
|
||
const parent = graph3.findById('SubTreeNode1');
|
||
let child = graph3.findById('SubTreeNode1.1');
|
||
|
||
let collapsed = undefined;
|
||
graph3.on('afteranimate', () => {
|
||
if (collapsed === undefined) return;
|
||
if (collapsed) {
|
||
expect(parent.getModel().collapsed).toBe(true);
|
||
expect(child.destroyed).toBe(true);
|
||
} else {
|
||
child = graph3.findById('SubTreeNode1.1');
|
||
expect(parent.getModel().collapsed).toBe(false);
|
||
expect(child.get('model').x).not.toEqual(parent.get('model').x);
|
||
expect(!!child.getModel().collapsed).toBe(false);
|
||
expect(child.get('model').y).not.toEqual(parent.get('model').y);
|
||
// done();
|
||
}
|
||
});
|
||
graph3.addBehaviors(
|
||
[
|
||
{
|
||
type: 'collapse-expand',
|
||
trigger: 'dblclick',
|
||
},
|
||
],
|
||
'default',
|
||
);
|
||
timerOut(() => {
|
||
graph3.emit('node:dblclick', { item: parent });
|
||
collapsed = true;
|
||
}, 600);
|
||
|
||
timerOut(() => {
|
||
collapsed = false;
|
||
graph3.emit('node:dblclick', { item: parent });
|
||
done();
|
||
}, 1200);
|
||
});
|
||
it('collapse & expand', () => {
|
||
graph3.off();
|
||
|
||
const parent = graph3.findById('SubTreeNode1');
|
||
let child = graph3.findById('SubTreeNode1.1');
|
||
|
||
let collapsed = true;
|
||
graph3.on('afteranimate', () => {
|
||
if (collapsed) {
|
||
expect(parent.getModel().collapsed).toBe(true);
|
||
expect(child.destroyed).toBe(true);
|
||
} else {
|
||
child = graph3.findById('SubTreeNode1.1');
|
||
expect(parent.getModel().collapsed).toBe(false);
|
||
expect(child.get('model').x).not.toEqual(parent.get('model').x);
|
||
expect(!!child.getModel().collapsed).toBe(false);
|
||
expect(child.get('model').y).not.toEqual(parent.get('model').y);
|
||
}
|
||
});
|
||
graph3.addBehaviors('collapse-expand', 'default');
|
||
graph3.emit('node:click', { item: parent });
|
||
|
||
timerOut(() => {
|
||
collapsed = false;
|
||
graph3.emit('node:click', { item: parent });
|
||
}, 600);
|
||
});
|
||
|
||
// it('test', () => {
|
||
// const data = {
|
||
// isRoot: true,
|
||
// id: 'Root',
|
||
// children: [
|
||
// {
|
||
// id: 'SubTreeNode1',
|
||
// children: [
|
||
// {
|
||
// id: 'SubTreeNode1.1'
|
||
// },
|
||
// {
|
||
// id: 'SubTreeNode1.2'
|
||
// }
|
||
// ]
|
||
// },
|
||
// {
|
||
// id: 'SubTreeNode2'
|
||
// }
|
||
// ]
|
||
// };
|
||
// const graph2 = new TreeGraph({
|
||
// container: div,
|
||
// width: 500,
|
||
// height: 500,
|
||
// animate: false,
|
||
// modes: {
|
||
// default: [ 'drag-canvas', 'drag-node' ]
|
||
// },
|
||
// layout: {
|
||
// type: 'dendrogram',
|
||
// direction: 'LR', // H / V / LR / RL / TB / BT
|
||
// nodeSep: 50,
|
||
// rankSep: 100
|
||
// }
|
||
// });
|
||
// graph2.data(data);
|
||
// graph2.render();
|
||
|
||
// const pos = [0, 0];
|
||
// graph2.on('node:click', () => {
|
||
// pos[0] += 10;
|
||
// pos[1] += 10;
|
||
// graph2.moveTo(pos[0], pos[1]);
|
||
// });
|
||
// });
|
||
});
|