From 5b6f5491a6991e8dc55799e3424f37cd8dfa80d8 Mon Sep 17 00:00:00 2001 From: Yanyan-Wang Date: Wed, 24 Jun 2020 16:08:50 +0800 Subject: [PATCH] fix: force layout with addItem and relayout. closes: #1275. --- CHANGELOG.md | 1 + src/graph/controller/event.ts | 2 - src/graph/controller/layout.ts | 2 +- src/layout/force.ts | 8 ++- src/types/index.ts | 2 +- stories/Layout/component/force-layout.tsx | 87 +++++++++++++++++++++++ stories/Layout/layout.stories.tsx | 4 +- 7 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 stories/Layout/component/force-layout.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 616aad3976..e5e4e36010 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - feat: Floyd Warshall shortest path algorithm; - feat: built-in arrows; - feat: built-in markers; +- fix: force layout with addItem and relayout. #### 3.5.7 - feat: shouldBegin for click-select behavior; diff --git a/src/graph/controller/event.ts b/src/graph/controller/event.ts index c8084bf297..374634a2cd 100644 --- a/src/graph/controller/event.ts +++ b/src/graph/controller/event.ts @@ -236,12 +236,10 @@ export default class EventController { const canvas: Canvas = graph.get('canvas'); each(EVENTS, event => { - console.log(' event', event); canvas.off(event, canvasHandler); }); each(extendEvents, event => { - console.log('extend event', event); event.remove(); }); diff --git a/src/graph/controller/layout.ts b/src/graph/controller/layout.ts index d17743ba95..332a6b7a3c 100644 --- a/src/graph/controller/layout.ts +++ b/src/graph/controller/layout.ts @@ -419,7 +419,7 @@ export default class LayoutController { layoutMethod.forceSimulation.stop(); } graph.emit('beforelayout'); - layoutMethod.execute(); + layoutMethod.execute(reloadData); if (this.layoutType !== 'force' && !layoutMethod.enableTick) { graph.emit('afterlayout'); } diff --git a/src/layout/force.ts b/src/layout/force.ts index 8e4f77a185..1cb52ce840 100644 --- a/src/layout/force.ts +++ b/src/layout/force.ts @@ -57,6 +57,7 @@ export default class ForceLayout extends BaseLayout { /** 是否正在布局 */ private ticking: boolean | undefined = undefined; + private edgeForce: any; public getDefaultCfg() { return { @@ -104,7 +105,7 @@ export default class ForceLayout extends BaseLayout { /** * 执行布局 */ - public execute() { + public execute(reloadData?: boolean) { const self = this; const nodes = self.nodes; const edges = self.edges; @@ -147,6 +148,7 @@ export default class ForceLayout extends BaseLayout { if (self.linkDistance) { edgeForce.distance(self.linkDistance); } + self.edgeForce = edgeForce; simulation.force('link', edgeForce); } if (self.workerEnabled && !isInWorker()) { @@ -188,6 +190,10 @@ export default class ForceLayout extends BaseLayout { console.warn(e); } } else { + if (reloadData) { + simulation.nodes(nodes); + self.edgeForce.links(edges); + } if (self.preventOverlap) { self.overlapProcess(simulation); } diff --git a/src/types/index.ts b/src/types/index.ts index df75fcead1..91485e32ba 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -125,7 +125,7 @@ export interface ModeOption { onlyChangeComboSize?: boolean; includeEdges?: boolean; direction?: 'x' | 'y'; - offset: number; + offset?: number; shouldUpdate?: (e: IG6GraphEvent) => boolean; shouldBegin?: (e: IG6GraphEvent) => boolean; shouldEnd?: (e: IG6GraphEvent) => boolean; diff --git a/stories/Layout/component/force-layout.tsx b/stories/Layout/component/force-layout.tsx new file mode 100644 index 0000000000..10e886b8df --- /dev/null +++ b/stories/Layout/component/force-layout.tsx @@ -0,0 +1,87 @@ +import React, { useEffect } from 'react'; +import G6 from '../../../src'; +import { IGraph } from '../../../src/interface/graph'; + +let graph: IGraph = null; + +const ForceLayout = () => { + const container = React.useRef(); + useEffect(() => { + if (!graph) { + + const graph = new G6.Graph({ + container: container.current as string | HTMLElement, + width: 500, + height: 500, + layout: { + type: 'force', + }, + defaultNode: { + size: 15, + color: '#5B8FF9', + style: { + lineWidth: 2, + fill: '#C6E5FF', + }, + }, + defaultEdge: { + size: 1, + color: '#e2e2e2', + }, + modes: { + default: ['drag-canvas'] + } + }); + fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/relations.json') + .then(res => res.json()) + .then(data => { + graph.data({ + nodes: data.nodes, + edges: data.edges.map(function (edge, i) { + edge.id = 'edge' + i; + return Object.assign({}, edge); + }), + }); + + graph.render(); + + const forceLayout = graph.get('layoutController').layoutMethod; + graph.on('node:dragstart', function (e) { + graph.layout() + refreshDragedNodePosition(e); + }); + graph.on('node:drag', function (e) { + forceLayout.execute(); + refreshDragedNodePosition(e); + }); + graph.on('node:dragend', function (e) { + e.item.get('model').fx = null; + e.item.get('model').fy = null; + }); + + graph.on('canvas:click', e => { + graph.addItem('node', { + id: 'newnode', + label: 'xx', + x: 0, + y: 0 + }) + graph.addItem('edge', { + source: 'newnode', + target: 'Myriel' + }) + graph.layout() + }); + }); + + const refreshDragedNodePosition = (e) => { + const model = e.item.get('model'); + model.fx = e.x; + model.fy = e.y; + } + } + }); + return
; +}; + +export default ForceLayout; diff --git a/stories/Layout/layout.stories.tsx b/stories/Layout/layout.stories.tsx index 51c6c09652..431111e044 100644 --- a/stories/Layout/layout.stories.tsx +++ b/stories/Layout/layout.stories.tsx @@ -7,6 +7,7 @@ import FruchtermanWorker from './component/fruchterman-worker-layout'; import AddNodeLayout from './component/addNodeLayout' import ChangeData from './component/changeData' import ComboForceLayout from './component/combo-force-layout'; +import ForceLayout from './component/force-layout'; export default { title: 'Layout' }; @@ -17,4 +18,5 @@ storiesOf('Layout', module) .add('add node and layout', () => ) .add('change data', () => ) .add('combo force layout', () => ) - .add('Fruchterman worker layout', () => ); + .add('Fruchterman worker layout', () => ) + .add('force layout', () => );