File size: 4,867 Bytes
bc20498
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import * as util from '../util';
import * as is from '../is';
import Set from '../set';

// represents a node or an edge
let Element = function( cy, params, restore = true ){
  if( cy === undefined || params === undefined || !is.core( cy ) ){
    util.error( 'An element must have a core reference and parameters set' );
    return;
  }

  let group = params.group;

  // try to automatically infer the group if unspecified
  if( group == null ){
    if( params.data && params.data.source != null && params.data.target != null ){
      group = 'edges';
    } else {
      group = 'nodes';
    }
  }

  // validate group
  if( group !== 'nodes' && group !== 'edges' ){
    util.error( 'An element must be of type `nodes` or `edges`; you specified `' + group + '`' );
    return;
  }

  // make the element array-like, just like a collection
  this.length = 1;
  this[0] = this;

  // NOTE: when something is added here, add also to ele.json()
  let _p = this._private = {
    cy: cy,
    single: true, // indicates this is an element
    data: params.data || {}, // data object
    position: params.position || { x: 0, y: 0 }, // (x, y) position pair
    autoWidth: undefined, // width and height of nodes calculated by the renderer when set to special 'auto' value
    autoHeight: undefined,
    autoPadding: undefined,
    compoundBoundsClean: false, // whether the compound dimensions need to be recalculated the next time dimensions are read
    listeners: [], // array of bound listeners
    group: group, // string; 'nodes' or 'edges'
    style: {}, // properties as set by the style
    rstyle: {}, // properties for style sent from the renderer to the core
    styleCxts: [], // applied style contexts from the styler
    styleKeys: {}, // per-group keys of style property values
    removed: true, // whether it's inside the vis; true if removed (set true here since we call restore)
    selected: params.selected ? true : false, // whether it's selected
    selectable: params.selectable === undefined ? true : ( params.selectable ? true : false ), // whether it's selectable
    locked: params.locked ? true : false, // whether the element is locked (cannot be moved)
    grabbed: false, // whether the element is grabbed by the mouse; renderer sets this privately
    grabbable: params.grabbable === undefined ? true : ( params.grabbable ? true : false ), // whether the element can be grabbed
    pannable: params.pannable === undefined ? (group === 'edges' ? true : false) : ( params.pannable ? true : false ), // whether the element has passthrough panning enabled
    active: false, // whether the element is active from user interaction
    classes: new Set(), // map ( className => true )
    animation: { // object for currently-running animations
      current: [],
      queue: []
    },
    rscratch: {}, // object in which the renderer can store information
    scratch: params.scratch || {}, // scratch objects
    edges: [], // array of connected edges
    children: [], // array of children
    parent: params.parent && params.parent.isNode() ? params.parent : null, // parent ref
    traversalCache: {}, // cache of output of traversal functions
    backgrounding: false, // whether background images are loading
    bbCache: null, // cache of the current bounding box
    bbCacheShift: { x: 0, y: 0 }, // shift applied to cached bb to be applied on next get
    bodyBounds: null, // bounds cache of element body, w/o overlay
    overlayBounds: null, // bounds cache of element body, including overlay
    labelBounds: { // bounds cache of labels
      all: null,
      source: null,
      target: null,
      main: null
    },
    arrowBounds: { // bounds cache of edge arrows
      source: null,
      target: null,
      'mid-source': null,
      'mid-target': null
    }
  };

  if( _p.position.x == null ){ _p.position.x = 0; }
  if( _p.position.y == null ){ _p.position.y = 0; }

  // renderedPosition overrides if specified
  if( params.renderedPosition ){
    let rpos = params.renderedPosition;
    let pan = cy.pan();
    let zoom = cy.zoom();

    _p.position = {
      x: (rpos.x - pan.x) / zoom,
      y: (rpos.y - pan.y) / zoom
    };
  }

  let classes = [];
  if( is.array( params.classes ) ){
    classes = params.classes;
  } else if( is.string( params.classes ) ){
    classes = params.classes.split( /\s+/ );
  }
  for( let i = 0, l = classes.length; i < l; i++ ){
    let cls = classes[ i ];
    if( !cls || cls === '' ){ continue; }

    _p.classes.add(cls);
  }

  this.createEmitter();

  let bypass = params.style || params.css;
  if( bypass ){
    util.warn('Setting a `style` bypass at element creation should be done only when absolutely necessary.  Try to use the stylesheet instead.');

    this.style(bypass);
  }

  if( restore === undefined || restore ){
    this.restore();
  }

};

export default Element;