UNPKG

4.87 kBJavaScriptView Raw
1import * as util from '../util';
2import * as is from '../is';
3import Set from '../set';
4
5// represents a node or an edge
6let Element = function( cy, params, restore = true ){
7 if( cy === undefined || params === undefined || !is.core( cy ) ){
8 util.error( 'An element must have a core reference and parameters set' );
9 return;
10 }
11
12 let group = params.group;
13
14 // try to automatically infer the group if unspecified
15 if( group == null ){
16 if( params.data && params.data.source != null && params.data.target != null ){
17 group = 'edges';
18 } else {
19 group = 'nodes';
20 }
21 }
22
23 // validate group
24 if( group !== 'nodes' && group !== 'edges' ){
25 util.error( 'An element must be of type `nodes` or `edges`; you specified `' + group + '`' );
26 return;
27 }
28
29 // make the element array-like, just like a collection
30 this.length = 1;
31 this[0] = this;
32
33 // NOTE: when something is added here, add also to ele.json()
34 let _p = this._private = {
35 cy: cy,
36 single: true, // indicates this is an element
37 data: params.data || {}, // data object
38 position: params.position || { x: 0, y: 0 }, // (x, y) position pair
39 autoWidth: undefined, // width and height of nodes calculated by the renderer when set to special 'auto' value
40 autoHeight: undefined,
41 autoPadding: undefined,
42 compoundBoundsClean: false, // whether the compound dimensions need to be recalculated the next time dimensions are read
43 listeners: [], // array of bound listeners
44 group: group, // string; 'nodes' or 'edges'
45 style: {}, // properties as set by the style
46 rstyle: {}, // properties for style sent from the renderer to the core
47 styleCxts: [], // applied style contexts from the styler
48 styleKeys: {}, // per-group keys of style property values
49 removed: true, // whether it's inside the vis; true if removed (set true here since we call restore)
50 selected: params.selected ? true : false, // whether it's selected
51 selectable: params.selectable === undefined ? true : ( params.selectable ? true : false ), // whether it's selectable
52 locked: params.locked ? true : false, // whether the element is locked (cannot be moved)
53 grabbed: false, // whether the element is grabbed by the mouse; renderer sets this privately
54 grabbable: params.grabbable === undefined ? true : ( params.grabbable ? true : false ), // whether the element can be grabbed
55 pannable: params.pannable === undefined ? (group === 'edges' ? true : false) : ( params.pannable ? true : false ), // whether the element has passthrough panning enabled
56 active: false, // whether the element is active from user interaction
57 classes: new Set(), // map ( className => true )
58 animation: { // object for currently-running animations
59 current: [],
60 queue: []
61 },
62 rscratch: {}, // object in which the renderer can store information
63 scratch: params.scratch || {}, // scratch objects
64 edges: [], // array of connected edges
65 children: [], // array of children
66 parent: params.parent && params.parent.isNode() ? params.parent : null, // parent ref
67 traversalCache: {}, // cache of output of traversal functions
68 backgrounding: false, // whether background images are loading
69 bbCache: null, // cache of the current bounding box
70 bbCacheShift: { x: 0, y: 0 }, // shift applied to cached bb to be applied on next get
71 bodyBounds: null, // bounds cache of element body, w/o overlay
72 overlayBounds: null, // bounds cache of element body, including overlay
73 labelBounds: { // bounds cache of labels
74 all: null,
75 source: null,
76 target: null,
77 main: null
78 },
79 arrowBounds: { // bounds cache of edge arrows
80 source: null,
81 target: null,
82 'mid-source': null,
83 'mid-target': null
84 }
85 };
86
87 if( _p.position.x == null ){ _p.position.x = 0; }
88 if( _p.position.y == null ){ _p.position.y = 0; }
89
90 // renderedPosition overrides if specified
91 if( params.renderedPosition ){
92 let rpos = params.renderedPosition;
93 let pan = cy.pan();
94 let zoom = cy.zoom();
95
96 _p.position = {
97 x: (rpos.x - pan.x) / zoom,
98 y: (rpos.y - pan.y) / zoom
99 };
100 }
101
102 let classes = [];
103 if( is.array( params.classes ) ){
104 classes = params.classes;
105 } else if( is.string( params.classes ) ){
106 classes = params.classes.split( /\s+/ );
107 }
108 for( let i = 0, l = classes.length; i < l; i++ ){
109 let cls = classes[ i ];
110 if( !cls || cls === '' ){ continue; }
111
112 _p.classes.add(cls);
113 }
114
115 this.createEmitter();
116
117 let bypass = params.style || params.css;
118 if( bypass ){
119 util.warn('Setting a `style` bypass at element creation should be done only when absolutely necessary. Try to use the stylesheet instead.');
120
121 this.style(bypass);
122 }
123
124 if( restore === undefined || restore ){
125 this.restore();
126 }
127
128};
129
130export default Element;