From f11669c827737cd120d8d43fd5e6bde35110acfe Mon Sep 17 00:00:00 2001 From: baizn <576375879@qq.com> Date: Fri, 27 Dec 2019 14:57:07 +0800 Subject: [PATCH 1/3] feat: add tree graph unit test --- .eslintignore | 3 +- package.json | 2 +- src/graph/graph.ts | 2 +- src/interface/graph.ts | 2 +- src/shape/nodes/circle.ts | 3 +- tests/unit/graph/tree-graph-spec.ts | 349 ++++++++++++++++++++++++++++ 6 files changed, 356 insertions(+), 5 deletions(-) create mode 100644 tests/unit/graph/tree-graph-spec.ts diff --git a/.eslintignore b/.eslintignore index 922aec4ef6..425e3c7ca3 100644 --- a/.eslintignore +++ b/.eslintignore @@ -7,4 +7,5 @@ node_modules/ demos/ .cache public -bin \ No newline at end of file +bin +esm/ \ No newline at end of file diff --git a/package.json b/package.json index b3f9be5728..94f18a58e8 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "lint": "lint-staged", "tslint": "tslint -c tslint.json 'src/**/*.ts'", "test": "jest", - "test-live": "DEBUG_MODE=1 jest --watch ./tests/unit/graph/controller/customGroup-spec.ts", + "test-live": "DEBUG_MODE=1 jest --watch ./tests/unit/graph/tree-graph-spec.ts", "coverage": "jest --coverage", "ci": "run-s build coverage", "doc": "rimraf apis && typedoc", diff --git a/src/graph/graph.ts b/src/graph/graph.ts index 3bdcab23c9..ae86a75dd8 100644 --- a/src/graph/graph.ts +++ b/src/graph/graph.ts @@ -495,7 +495,7 @@ export default class Graph extends EventEmitter implements IGraph { * 调整视口适应视图 * @param {object} padding 四周围边距 */ - public fitView(padding: Padding): void { + public fitView(padding?: Padding): void { if (padding) { this.set('fitViewPadding', padding); } diff --git a/src/interface/graph.ts b/src/interface/graph.ts index 3f5bea8ad8..858aa5ad41 100644 --- a/src/interface/graph.ts +++ b/src/interface/graph.ts @@ -226,7 +226,7 @@ export interface IGraph extends EventEmitter { * 调整视口适应视图 * @param {Padding} padding 四周围边距 */ - fitView(padding: Padding): void; + fitView(padding?: Padding): void; /** * 伸缩视口到一固定比例 diff --git a/src/shape/nodes/circle.ts b/src/shape/nodes/circle.ts index 5763826a06..3ccb913d1a 100644 --- a/src/shape/nodes/circle.ts +++ b/src/shape/nodes/circle.ts @@ -54,7 +54,8 @@ Shape.registerNode('circle', { const style = this.getShapeStyle(cfg); const icon = deepMix({}, defaultIcon, cfg.icon); const keyShape: IShape = group.addShape('circle', { - attrs: style + attrs: style, + draggable: true }); const { width, height, show } = icon; diff --git a/tests/unit/graph/tree-graph-spec.ts b/tests/unit/graph/tree-graph-spec.ts new file mode 100644 index 0000000000..6c34df5ed8 --- /dev/null +++ b/tests/unit/graph/tree-graph-spec.ts @@ -0,0 +1,349 @@ +import Hierarchy from '@antv/hierarchy'; +import G6 from '../../../src'; + +const div = document.createElement('div'); +div.id = 'tree-spec'; +document.body.appendChild(div); + +function timerGame(callback, time = 50) { + setTimeout(() => { + callback(); + }, time); +} + +describe('tree graph without animate', () => { + const graph = new G6.TreeGraph({ + container: div, + width: 500, + height: 500, + pixelRatio: 2, + 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', () => { + 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); + }); + + 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, shape: 'rect', children: [{ x: 150, y: 150, id: 'SubTreeNode3.1.1' }] }; + + 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', () => { + 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); + }); + + 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 }); + timerGame(() => { + collapsed = false; + graph.emit('node:click', { item: parent }); + }, 600); + }); + + it('collapse & expand with layout with parameter trigger=dblclick', () => { + graph.off(); + const parent = graph.findById('SubTreeNode1'); + 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 }); + timerGame(() => { + collapsed = false; + graph.emit('node:dblclick', { item: parent }); + }, 600); + }); +}); + +describe('tree graph with animate', () => { + const graph = new G6.TreeGraph({ + container: div, + width: 500, + height: 500, + pixelRatio: 2, + animate: true, + modes: { + default: [ 'drag-canvas' ] + }, + layout: { + type: 'dendrogram', + direction: 'LR', + nodeSep: 50, + rankSep: 100 + } + }); + it('layout init', () => { + 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(); + + const layoutMethod = graph.get('layoutMethod'); + + expect(layoutMethod).not.toBe(undefined); + expect(typeof layoutMethod).toEqual('function'); + + expect(Object.keys(graph.get('itemMap')).length).toEqual(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); + }); + it('changeData', () => { + graph.off(); + 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); + + graph.on('afteranimate', () => { + expect(Object.keys(graph.get('itemMap')).length).toEqual(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('collapse & expand', () => { + graph.off(); + + const parent = graph.findById('SubTreeNode1'); + let child = graph.findById('SubTreeNode1.1'); + + let collapsed = true; + graph.on('afteranimate', () => { + 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 }); + + timerGame(() => { + collapsed = false; + graph.emit('node:click', { item: parent }); + }, 600); + }); + it('collapse & expand with parameter trigger=dblclick', () => { + graph.off(); + + const parent = graph.findById('SubTreeNode1'); + let child = graph.findById('SubTreeNode1.1'); + + let collapsed = true; + graph.on('afteranimate', () => { + 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); + // done(); + } + }); + graph.addBehaviors([{ + type: 'collapse-expand', + trigger: 'dblclick' + }], 'default'); + + graph.emit('node:dblclick', { item: parent }); + + timerGame(() => { + collapsed = false; + graph.emit('node:dblclick', { item: parent }); + }, 600); + }); +}); \ No newline at end of file From 2ec9733e5888d4f6cbfa159e45d622b488a4d3c3 Mon Sep 17 00:00:00 2001 From: "xinhui.zxh" Date: Mon, 30 Dec 2019 14:41:36 +0800 Subject: [PATCH 2/3] feat: use father-build --- package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 94f18a58e8..957df2f0ed 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,9 @@ "name": "@antv/g6", "version": "3.3.0", "description": "A Graph Visualization Framework in JavaScript", - "main": "lib/index.js", - "module": "esm/index.js", - "types": "types/index.d.ts", + "main": "dist/g6.js", + "module": "dist/g6.esm.js", + "types": "dist/types/index.d.ts", "browser": "dist/g6.min.js", "files": [ "package.json", @@ -19,9 +19,8 @@ "site:develop": "gatsby develop --open -H 0.0.0.0", "site:build": "npm run site:clean && gatsby build --prefix-paths", "site:clean": "gatsby clean", - "build": "npm run clean && run-p build:*", - "build:esm": "tsc -p tsconfig.json --target ES5 --module ESNext --outDir esm", - "build:cjs": "tsc -p tsconfig.json --target ES5 --module commonjs --outDir lib", + "watch": "father-build --esm --file g6 --watch src/index.ts", + "build": "father-build --esm --cjs --file g6 src/index.ts && npm run build:umd", "build:umd": "webpack --config webpack.config.js --mode production", "clean": "rimraf esm lib dist", "lint": "lint-staged", @@ -53,6 +52,7 @@ "@types/jest": "^24.0.18", "babel-loader": "^8.0.6", "event-simulate": "~1.0.0", + "father-build": "^1.17.1", "gatsby": "^2.17.9", "gh-pages": "^2.1.1", "husky": "^3.0.4", From 5d2eb75c6b4e1c43aff6dedb7518bf944e523aae Mon Sep 17 00:00:00 2001 From: "xinhui.zxh" Date: Tue, 31 Dec 2019 10:09:47 +0800 Subject: [PATCH 3/3] feat: using ttsc to generate declaration --- package.json | 5 ++++- tsconfig.json | 8 +++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 957df2f0ed..cac25bc04a 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,9 @@ "site:build": "npm run site:clean && gatsby build --prefix-paths", "site:clean": "gatsby clean", "watch": "father-build --esm --file g6 --watch src/index.ts", - "build": "father-build --esm --cjs --file g6 src/index.ts && npm run build:umd", + "build": "father-build --esm --cjs --file g6 src/index.ts && npm run build:declaration && npm run build:umd", "build:umd": "webpack --config webpack.config.js --mode production", + "build:declaration": "ttsc --emitDeclarationOnly --outDir ./dist", "clean": "rimraf esm lib dist", "lint": "lint-staged", "tslint": "tslint -c tslint.json 'src/**/*.ts'", @@ -69,9 +70,11 @@ "ts-loader": "^6.2.1", "tslint": "^5.18.0", "tslint-config-prettier": "^1.18.0", + "ttypescript": "^1.5.8", "typedoc": "^0.15.0", "typedoc-plugin-markdown": "^2.2.11", "typescript": "^3.5.3", + "typescript-transform-paths": "^1.1.14", "webpack": "^4.41.4", "webpack-cli": "^3.3.10" }, diff --git a/tsconfig.json b/tsconfig.json index c4a6da78ce..b59687e5c9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,7 +16,13 @@ "paths": { "@g6/*": ["./src/*"], "@g6/types": ["./types"] - } + }, + "plugins": [ + { + "transform": "typescript-transform-paths", + "afterDeclarations": true + } + ] }, "include": ["src"], "typedocOptions": {