1 | import * as util from '../util';
|
2 | import Promise from '../promise';
|
3 | import * as math from '../math';
|
4 |
|
5 | const getLayoutDimensionOptions = util.defaults({
|
6 | nodeDimensionsIncludeLabels: false
|
7 | });
|
8 |
|
9 | let elesfn = ({
|
10 |
|
11 | layoutDimensions: function( options ){
|
12 | options = getLayoutDimensionOptions( options );
|
13 |
|
14 | let dims;
|
15 |
|
16 | if( !this.takesUpSpace() ){
|
17 | dims = { w: 0, h: 0 };
|
18 | } else if( options.nodeDimensionsIncludeLabels ){
|
19 | let bbDim = this.boundingBox();
|
20 |
|
21 | dims = {
|
22 | w: bbDim.w,
|
23 | h: bbDim.h
|
24 | };
|
25 | } else {
|
26 | dims = {
|
27 | w: this.outerWidth(),
|
28 | h: this.outerHeight()
|
29 | };
|
30 | }
|
31 |
|
32 |
|
33 | if( dims.w === 0 || dims.h === 0 ){
|
34 | dims.w = dims.h = 1;
|
35 | }
|
36 |
|
37 | return dims;
|
38 | },
|
39 |
|
40 |
|
41 | layoutPositions: function( layout, options, fn ){
|
42 | let nodes = this.nodes().filter(n => !n.isParent());
|
43 | let cy = this.cy();
|
44 | let layoutEles = options.eles;
|
45 | let getMemoizeKey = node => node.id();
|
46 | let fnMem = util.memoize( fn, getMemoizeKey );
|
47 |
|
48 | layout.emit( { type: 'layoutstart', layout: layout } );
|
49 |
|
50 | layout.animations = [];
|
51 |
|
52 | let calculateSpacing = function( spacing, nodesBb, pos ){
|
53 | let center = {
|
54 | x: nodesBb.x1 + nodesBb.w / 2,
|
55 | y: nodesBb.y1 + nodesBb.h / 2
|
56 | };
|
57 |
|
58 | let spacingVector = {
|
59 | x: (pos.x - center.x) * spacing,
|
60 | y: (pos.y - center.y) * spacing
|
61 | };
|
62 |
|
63 | return {
|
64 | x: center.x + spacingVector.x,
|
65 | y: center.y + spacingVector.y
|
66 | };
|
67 | };
|
68 |
|
69 | let useSpacingFactor = options.spacingFactor && options.spacingFactor !== 1;
|
70 |
|
71 | let spacingBb = function(){
|
72 | if( !useSpacingFactor ){ return null; }
|
73 |
|
74 | let bb = math.makeBoundingBox();
|
75 |
|
76 | for( let i = 0; i < nodes.length; i++ ){
|
77 | let node = nodes[i];
|
78 | let pos = fnMem( node, i );
|
79 |
|
80 | math.expandBoundingBoxByPoint( bb, pos.x, pos.y );
|
81 | }
|
82 |
|
83 | return bb;
|
84 | };
|
85 |
|
86 | let bb = spacingBb();
|
87 |
|
88 | let getFinalPos = util.memoize( function( node, i ){
|
89 | let newPos = fnMem( node, i );
|
90 |
|
91 | if( useSpacingFactor ){
|
92 | let spacing = Math.abs( options.spacingFactor );
|
93 |
|
94 | newPos = calculateSpacing( spacing, bb, newPos );
|
95 | }
|
96 |
|
97 | if( options.transform != null ){
|
98 | newPos = options.transform( node, newPos );
|
99 | }
|
100 |
|
101 | return newPos;
|
102 | }, getMemoizeKey );
|
103 |
|
104 | if( options.animate ){
|
105 | for( let i = 0; i < nodes.length; i++ ){
|
106 | let node = nodes[ i ];
|
107 | let newPos = getFinalPos( node, i );
|
108 | let animateNode = options.animateFilter == null || options.animateFilter( node, i );
|
109 |
|
110 | if( animateNode ){
|
111 | let ani = node.animation( {
|
112 | position: newPos,
|
113 | duration: options.animationDuration,
|
114 | easing: options.animationEasing
|
115 | } );
|
116 |
|
117 | layout.animations.push( ani );
|
118 | } else {
|
119 | node.position( newPos );
|
120 | }
|
121 |
|
122 | }
|
123 |
|
124 | if( options.fit ){
|
125 | let fitAni = cy.animation({
|
126 | fit: {
|
127 | boundingBox: layoutEles.boundingBoxAt( getFinalPos ),
|
128 | padding: options.padding
|
129 | },
|
130 | duration: options.animationDuration,
|
131 | easing: options.animationEasing
|
132 | });
|
133 |
|
134 | layout.animations.push( fitAni );
|
135 | } else if( options.zoom !== undefined && options.pan !== undefined ){
|
136 | let zoomPanAni = cy.animation({
|
137 | zoom: options.zoom,
|
138 | pan: options.pan,
|
139 | duration: options.animationDuration,
|
140 | easing: options.animationEasing
|
141 | });
|
142 |
|
143 | layout.animations.push( zoomPanAni );
|
144 | }
|
145 |
|
146 | layout.animations.forEach(ani => ani.play());
|
147 |
|
148 | layout.one( 'layoutready', options.ready );
|
149 | layout.emit( { type: 'layoutready', layout: layout } );
|
150 |
|
151 | Promise.all( layout.animations.map(function( ani ){
|
152 | return ani.promise();
|
153 | }) ).then(function(){
|
154 | layout.one( 'layoutstop', options.stop );
|
155 | layout.emit( { type: 'layoutstop', layout: layout } );
|
156 | });
|
157 | } else {
|
158 |
|
159 | nodes.positions( getFinalPos );
|
160 |
|
161 | if( options.fit ){
|
162 | cy.fit( options.eles, options.padding );
|
163 | }
|
164 |
|
165 | if( options.zoom != null ){
|
166 | cy.zoom( options.zoom );
|
167 | }
|
168 |
|
169 | if( options.pan ){
|
170 | cy.pan( options.pan );
|
171 | }
|
172 |
|
173 | layout.one( 'layoutready', options.ready );
|
174 | layout.emit( { type: 'layoutready', layout: layout } );
|
175 |
|
176 | layout.one( 'layoutstop', options.stop );
|
177 | layout.emit( { type: 'layoutstop', layout: layout } );
|
178 | }
|
179 |
|
180 | return this;
|
181 | },
|
182 |
|
183 | layout: function( options ){
|
184 | let cy = this.cy();
|
185 |
|
186 | return cy.makeLayout( util.extend( {}, options, {
|
187 | eles: this
|
188 | } ) );
|
189 | }
|
190 |
|
191 | });
|
192 |
|
193 |
|
194 | elesfn.createLayout = elesfn.makeLayout = elesfn.layout;
|
195 |
|
196 | export default elesfn;
|