3d-force-graph 1.70.13 → 1.70.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,25 +7,15 @@ var ThreeRenderObjects = require('three-render-objects');
7
7
  var accessorFn = require('accessor-fn');
8
8
  var Kapsule = require('kapsule');
9
9
 
10
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
11
-
12
- var ThreeForceGraph__default = /*#__PURE__*/_interopDefaultLegacy(ThreeForceGraph);
13
- var ThreeRenderObjects__default = /*#__PURE__*/_interopDefaultLegacy(ThreeRenderObjects);
14
- var accessorFn__default = /*#__PURE__*/_interopDefaultLegacy(accessorFn);
15
- var Kapsule__default = /*#__PURE__*/_interopDefaultLegacy(Kapsule);
16
-
17
10
  function styleInject(css, ref) {
18
11
  if (ref === void 0) ref = {};
19
12
  var insertAt = ref.insertAt;
20
-
21
13
  if (!css || typeof document === 'undefined') {
22
14
  return;
23
15
  }
24
-
25
16
  var head = document.head || document.getElementsByTagName('head')[0];
26
17
  var style = document.createElement('style');
27
18
  style.type = 'text/css';
28
-
29
19
  if (insertAt === 'top') {
30
20
  if (head.firstChild) {
31
21
  head.insertBefore(style, head.firstChild);
@@ -35,7 +25,6 @@ function styleInject(css, ref) {
35
25
  } else {
36
26
  head.appendChild(style);
37
27
  }
38
-
39
28
  if (style.styleSheet) {
40
29
  style.styleSheet.cssText = css;
41
30
  } else {
@@ -48,17 +37,14 @@ styleInject(css_248z);
48
37
 
49
38
  function ownKeys(object, enumerableOnly) {
50
39
  var keys = Object.keys(object);
51
-
52
40
  if (Object.getOwnPropertySymbols) {
53
41
  var symbols = Object.getOwnPropertySymbols(object);
54
42
  enumerableOnly && (symbols = symbols.filter(function (sym) {
55
43
  return Object.getOwnPropertyDescriptor(object, sym).enumerable;
56
44
  })), keys.push.apply(keys, symbols);
57
45
  }
58
-
59
46
  return keys;
60
47
  }
61
-
62
48
  function _objectSpread2(target) {
63
49
  for (var i = 1; i < arguments.length; i++) {
64
50
  var source = null != arguments[i] ? arguments[i] : {};
@@ -68,10 +54,8 @@ function _objectSpread2(target) {
68
54
  Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
69
55
  });
70
56
  }
71
-
72
57
  return target;
73
58
  }
74
-
75
59
  function _defineProperty(obj, key, value) {
76
60
  if (key in obj) {
77
61
  Object.defineProperty(obj, key, {
@@ -83,22 +67,17 @@ function _defineProperty(obj, key, value) {
83
67
  } else {
84
68
  obj[key] = value;
85
69
  }
86
-
87
70
  return obj;
88
71
  }
89
-
90
72
  function _toConsumableArray(arr) {
91
73
  return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
92
74
  }
93
-
94
75
  function _arrayWithoutHoles(arr) {
95
76
  if (Array.isArray(arr)) return _arrayLikeToArray(arr);
96
77
  }
97
-
98
78
  function _iterableToArray(iter) {
99
79
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
100
80
  }
101
-
102
81
  function _unsupportedIterableToArray(o, minLen) {
103
82
  if (!o) return;
104
83
  if (typeof o === "string") return _arrayLikeToArray(o, minLen);
@@ -107,15 +86,11 @@ function _unsupportedIterableToArray(o, minLen) {
107
86
  if (n === "Map" || n === "Set") return Array.from(o);
108
87
  if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
109
88
  }
110
-
111
89
  function _arrayLikeToArray(arr, len) {
112
90
  if (len == null || len > arr.length) len = arr.length;
113
-
114
91
  for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
115
-
116
92
  return arr2;
117
93
  }
118
-
119
94
  function _nonIterableSpread() {
120
95
  throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
121
96
  }
@@ -138,11 +113,9 @@ function linkKapsule (kapsulePropName, kapsuleType) {
138
113
  // link method pass-through
139
114
  return function (state) {
140
115
  var kapsuleInstance = state[kapsulePropName];
141
-
142
116
  for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
143
117
  args[_key - 1] = arguments[_key];
144
118
  }
145
-
146
119
  var returnVal = kapsuleInstance[method].apply(kapsuleInstance, args);
147
120
  return returnVal === kapsuleInstance ? this // chain based on the parent object, not the inner kapsule
148
121
  : returnVal;
@@ -158,18 +131,23 @@ var three = window.THREE ? window.THREE // Prefer consumption from global THREE,
158
131
  Vector3: three$1.Vector3
159
132
  };
160
133
 
161
- var CAMERA_DISTANCE2NODES_FACTOR = 170; //
162
- // Expose config from forceGraph
134
+ //
135
+
136
+ var CAMERA_DISTANCE2NODES_FACTOR = 170;
137
+
138
+ //
163
139
 
164
- var bindFG = linkKapsule('forceGraph', ThreeForceGraph__default["default"]);
140
+ // Expose config from forceGraph
141
+ var bindFG = linkKapsule('forceGraph', ThreeForceGraph);
165
142
  var linkedFGProps = Object.assign.apply(Object, _toConsumableArray(['jsonUrl', 'graphData', 'numDimensions', 'dagMode', 'dagLevelDistance', 'dagNodeFilter', 'onDagError', 'nodeRelSize', 'nodeId', 'nodeVal', 'nodeResolution', 'nodeColor', 'nodeAutoColorBy', 'nodeOpacity', 'nodeVisibility', 'nodeThreeObject', 'nodeThreeObjectExtend', 'linkSource', 'linkTarget', 'linkVisibility', 'linkColor', 'linkAutoColorBy', 'linkOpacity', 'linkWidth', 'linkResolution', 'linkCurvature', 'linkCurveRotation', 'linkMaterial', 'linkThreeObject', 'linkThreeObjectExtend', 'linkPositionUpdate', 'linkDirectionalArrowLength', 'linkDirectionalArrowColor', 'linkDirectionalArrowRelPos', 'linkDirectionalArrowResolution', 'linkDirectionalParticles', 'linkDirectionalParticleSpeed', 'linkDirectionalParticleWidth', 'linkDirectionalParticleColor', 'linkDirectionalParticleResolution', 'forceEngine', 'd3AlphaDecay', 'd3VelocityDecay', 'd3AlphaMin', 'ngraphPhysics', 'warmupTicks', 'cooldownTicks', 'cooldownTime', 'onEngineTick', 'onEngineStop'].map(function (p) {
166
143
  return _defineProperty({}, p, bindFG.linkProp(p));
167
144
  })));
168
145
  var linkedFGMethods = Object.assign.apply(Object, _toConsumableArray(['refresh', 'getGraphBbox', 'd3Force', 'd3ReheatSimulation', 'emitParticle'].map(function (p) {
169
146
  return _defineProperty({}, p, bindFG.linkMethod(p));
170
- }))); // Expose config from renderObjs
147
+ })));
171
148
 
172
- var bindRenderObjs = linkKapsule('renderObjs', ThreeRenderObjects__default["default"]);
149
+ // Expose config from renderObjs
150
+ var bindRenderObjs = linkKapsule('renderObjs', ThreeRenderObjects);
173
151
  var linkedRenderObjsProps = Object.assign.apply(Object, _toConsumableArray(['width', 'height', 'backgroundColor', 'showNavInfo', 'enablePointerInteraction'].map(function (p) {
174
152
  return _defineProperty({}, p, bindRenderObjs.linkProp(p));
175
153
  })));
@@ -178,9 +156,11 @@ var linkedRenderObjsMethods = Object.assign.apply(Object, _toConsumableArray(['c
178
156
  })).concat([{
179
157
  graph2ScreenCoords: bindRenderObjs.linkMethod('getScreenCoords'),
180
158
  screen2GraphCoords: bindRenderObjs.linkMethod('getSceneCoords')
181
- }])); //
159
+ }]));
160
+
161
+ //
182
162
 
183
- var _3dForceGraph = Kapsule__default["default"]({
163
+ var _3dForceGraph = Kapsule({
184
164
  props: _objectSpread2(_objectSpread2({
185
165
  nodeLabel: {
186
166
  "default": 'name',
@@ -201,7 +181,6 @@ var _3dForceGraph = Kapsule__default["default"]({
201
181
  "default": true,
202
182
  onChange: function onChange(enable, state) {
203
183
  var controls = state.renderObjs.controls();
204
-
205
184
  if (controls) {
206
185
  controls.enabled = enable;
207
186
  }
@@ -248,11 +227,9 @@ var _3dForceGraph = Kapsule__default["default"]({
248
227
  methods: _objectSpread2(_objectSpread2({
249
228
  zoomToFit: function zoomToFit(state, transitionDuration, padding) {
250
229
  var _state$forceGraph;
251
-
252
230
  for (var _len = arguments.length, bboxArgs = new Array(_len > 3 ? _len - 3 : 0), _key = 3; _key < _len; _key++) {
253
231
  bboxArgs[_key - 3] = arguments[_key];
254
232
  }
255
-
256
233
  state.renderObjs.fitToBbox((_state$forceGraph = state.forceGraph).getGraphBbox.apply(_state$forceGraph, bboxArgs), transitionDuration, padding);
257
234
  return this;
258
235
  },
@@ -261,23 +238,21 @@ var _3dForceGraph = Kapsule__default["default"]({
261
238
  cancelAnimationFrame(state.animationFrameRequestId);
262
239
  state.animationFrameRequestId = null;
263
240
  }
264
-
265
241
  return this;
266
242
  },
267
243
  resumeAnimation: function resumeAnimation(state) {
268
244
  if (state.animationFrameRequestId === null) {
269
245
  this._animationCycle();
270
246
  }
271
-
272
247
  return this;
273
248
  },
274
249
  _animationCycle: function _animationCycle(state) {
275
250
  if (state.enablePointerInteraction) {
276
251
  // reset canvas cursor (override dragControls cursor)
277
252
  this.renderer().domElement.style.cursor = null;
278
- } // Frame cycle
279
-
253
+ }
280
254
 
255
+ // Frame cycle
281
256
  state.forceGraph.tickFrame();
282
257
  state.renderObjs.tick();
283
258
  state.animationFrameRequestId = requestAnimationFrame(this._animationCycle);
@@ -312,11 +287,11 @@ var _3dForceGraph = Kapsule__default["default"]({
312
287
  }, linkedFGMethods), linkedRenderObjsMethods),
313
288
  stateInit: function stateInit(_ref5) {
314
289
  var controlType = _ref5.controlType,
315
- rendererConfig = _ref5.rendererConfig,
316
- extraRenderers = _ref5.extraRenderers;
290
+ rendererConfig = _ref5.rendererConfig,
291
+ extraRenderers = _ref5.extraRenderers;
317
292
  return {
318
- forceGraph: new ThreeForceGraph__default["default"](),
319
- renderObjs: ThreeRenderObjects__default["default"]({
293
+ forceGraph: new ThreeForceGraph(),
294
+ renderObjs: ThreeRenderObjects({
320
295
  controlType: controlType,
321
296
  rendererConfig: rendererConfig,
322
297
  extraRenderers: extraRenderers
@@ -325,11 +300,13 @@ var _3dForceGraph = Kapsule__default["default"]({
325
300
  },
326
301
  init: function init(domNode, state) {
327
302
  // Wipe DOM
328
- domNode.innerHTML = ''; // Add relative container
303
+ domNode.innerHTML = '';
329
304
 
305
+ // Add relative container
330
306
  domNode.appendChild(state.container = document.createElement('div'));
331
- state.container.style.position = 'relative'; // Add renderObjs
307
+ state.container.style.position = 'relative';
332
308
 
309
+ // Add renderObjs
333
310
  var roDomNode = document.createElement('div');
334
311
  state.container.appendChild(roDomNode);
335
312
  state.renderObjs(roDomNode);
@@ -337,21 +314,24 @@ var _3dForceGraph = Kapsule__default["default"]({
337
314
  var renderer = state.renderObjs.renderer();
338
315
  var controls = state.renderObjs.controls();
339
316
  controls.enabled = !!state.enableNavigationControls;
340
- state.lastSetCameraZ = camera.position.z; // Add info space
317
+ state.lastSetCameraZ = camera.position.z;
341
318
 
319
+ // Add info space
342
320
  var infoElem;
343
321
  state.container.appendChild(infoElem = document.createElement('div'));
344
322
  infoElem.className = 'graph-info-msg';
345
- infoElem.textContent = ''; // config forcegraph
323
+ infoElem.textContent = '';
346
324
 
325
+ // config forcegraph
347
326
  state.forceGraph.onLoading(function () {
348
327
  infoElem.textContent = 'Loading...';
349
328
  }).onFinishLoading(function () {
350
329
  infoElem.textContent = '';
351
330
  }).onUpdate(function () {
352
331
  // sync graph data structures
353
- state.graphData = state.forceGraph.graphData(); // re-aim camera, if still in default position (not user modified)
332
+ state.graphData = state.forceGraph.graphData();
354
333
 
334
+ // re-aim camera, if still in default position (not user modified)
355
335
  if (camera.position.x === 0 && camera.position.y === 0 && camera.position.z === state.lastSetCameraZ && state.graphData.nodes.length) {
356
336
  camera.lookAt(state.forceGraph.position);
357
337
  state.lastSetCameraZ = camera.position.z = Math.cbrt(state.graphData.nodes.length) * CAMERA_DISTANCE2NODES_FACTOR;
@@ -362,17 +342,14 @@ var _3dForceGraph = Kapsule__default["default"]({
362
342
  var curNodeDrag = state.graphData.nodes.find(function (node) {
363
343
  return node.__initialFixedPos && !node.__disposeControlsAfterDrag;
364
344
  }); // detect if there's a node being dragged using the existing drag controls
365
-
366
345
  if (curNodeDrag) {
367
346
  curNodeDrag.__disposeControlsAfterDrag = true; // postpone previous controls disposal until drag ends
368
347
  } else {
369
348
  state._dragControls.dispose(); // cancel previous drag controls
370
-
371
349
  }
372
350
 
373
351
  state._dragControls = undefined;
374
352
  }
375
-
376
353
  if (state.enableNodeDrag && state.enablePointerInteraction && state.forceEngine === 'd3') {
377
354
  // Can't access node positions programatically in ngraph
378
355
  var dragControls = state._dragControls = new DragControls_js.DragControls(state.graphData.nodes.map(function (node) {
@@ -382,13 +359,11 @@ var _3dForceGraph = Kapsule__default["default"]({
382
359
  }), camera, renderer.domElement);
383
360
  dragControls.addEventListener('dragstart', function (event) {
384
361
  controls.enabled = false; // Disable controls while dragging
385
- // track drag object movement
386
362
 
363
+ // track drag object movement
387
364
  event.object.__initialPos = event.object.position.clone();
388
365
  event.object.__prevPos = event.object.position.clone();
389
-
390
366
  var node = getGraphObj(event.object).__data;
391
-
392
367
  !node.__initialFixedPos && (node.__initialFixedPos = {
393
368
  fx: node.fx,
394
369
  fy: node.fy,
@@ -398,28 +373,26 @@ var _3dForceGraph = Kapsule__default["default"]({
398
373
  x: node.x,
399
374
  y: node.y,
400
375
  z: node.z
401
- }); // lock node
376
+ });
402
377
 
378
+ // lock node
403
379
  ['x', 'y', 'z'].forEach(function (c) {
404
380
  return node["f".concat(c)] = node[c];
405
- }); // drag cursor
381
+ });
406
382
 
383
+ // drag cursor
407
384
  renderer.domElement.classList.add('grabbable');
408
385
  });
409
386
  dragControls.addEventListener('drag', function (event) {
410
387
  var nodeObj = getGraphObj(event.object);
411
-
412
388
  if (!event.object.hasOwnProperty('__graphObjType')) {
413
389
  // If dragging a child of the node, update the node object instead
414
390
  var initPos = event.object.__initialPos;
415
391
  var prevPos = event.object.__prevPos;
416
392
  var _newPos = event.object.position;
417
393
  nodeObj.position.add(_newPos.clone().sub(prevPos)); // translate node object by the motion delta
418
-
419
394
  prevPos.copy(_newPos);
420
-
421
395
  _newPos.copy(initPos); // reset child back to its initial position
422
-
423
396
  }
424
397
 
425
398
  var node = nodeObj.__data;
@@ -428,8 +401,8 @@ var _3dForceGraph = Kapsule__default["default"]({
428
401
  x: newPos.x - node.x,
429
402
  y: newPos.y - node.y,
430
403
  z: newPos.z - node.z
431
- }; // Move fx/fy/fz (and x/y/z) of nodes based on object new position
432
-
404
+ };
405
+ // Move fx/fy/fz (and x/y/z) of nodes based on object new position
433
406
  ['x', 'y', 'z'].forEach(function (c) {
434
407
  return node["f".concat(c)] = node[c] = newPos[c];
435
408
  });
@@ -441,17 +414,14 @@ var _3dForceGraph = Kapsule__default["default"]({
441
414
  });
442
415
  dragControls.addEventListener('dragend', function (event) {
443
416
  delete event.object.__initialPos; // remove tracking attributes
444
-
445
417
  delete event.object.__prevPos;
418
+ var node = getGraphObj(event.object).__data;
446
419
 
447
- var node = getGraphObj(event.object).__data; // dispose previous controls if needed
448
-
449
-
420
+ // dispose previous controls if needed
450
421
  if (node.__disposeControlsAfterDrag) {
451
422
  dragControls.dispose();
452
423
  delete node.__disposeControlsAfterDrag;
453
424
  }
454
-
455
425
  var initFixedPos = node.__initialFixedPos;
456
426
  var initPos = node.__initialPos;
457
427
  var translate = {
@@ -459,87 +429,81 @@ var _3dForceGraph = Kapsule__default["default"]({
459
429
  y: initPos.y - node.y,
460
430
  z: initPos.z - node.z
461
431
  };
462
-
463
432
  if (initFixedPos) {
464
433
  ['x', 'y', 'z'].forEach(function (c) {
465
434
  var fc = "f".concat(c);
466
-
467
435
  if (initFixedPos[fc] === undefined) {
468
436
  delete node[fc];
469
437
  }
470
438
  });
471
439
  delete node.__initialFixedPos;
472
440
  delete node.__initialPos;
473
-
474
441
  if (node.__dragged) {
475
442
  delete node.__dragged;
476
443
  state.onNodeDragEnd(node, translate);
477
444
  }
478
445
  }
479
-
480
446
  state.forceGraph.d3AlphaTarget(0) // release engine low intensity
481
447
  .resetCountdown(); // let the engine readjust after releasing fixed nodes
482
448
 
483
449
  if (state.enableNavigationControls) {
484
450
  controls.enabled = true; // Re-enable controls
485
-
486
- controls.domElement && controls.domElement.ownerDocument && controls.domElement.ownerDocument.dispatchEvent( // simulate mouseup to ensure the controls don't take over after dragend
451
+ controls.domElement && controls.domElement.ownerDocument && controls.domElement.ownerDocument.dispatchEvent(
452
+ // simulate mouseup to ensure the controls don't take over after dragend
487
453
  new PointerEvent('pointerup', {
488
454
  pointerType: 'touch'
489
455
  }));
490
- } // clear cursor
491
-
456
+ }
492
457
 
458
+ // clear cursor
493
459
  renderer.domElement.classList.remove('grabbable');
494
460
  });
495
461
  }
496
- }); // config renderObjs
462
+ });
497
463
 
498
- state.renderObjs.objects([// Populate scene
464
+ // config renderObjs
465
+ state.renderObjs.objects([
466
+ // Populate scene
499
467
  new three.AmbientLight(0xbbbbbb), new three.DirectionalLight(0xffffff, 0.6), state.forceGraph]).hoverOrderComparator(function (a, b) {
500
468
  // Prioritize graph objects
501
469
  var aObj = getGraphObj(a);
502
470
  if (!aObj) return 1;
503
471
  var bObj = getGraphObj(b);
504
- if (!bObj) return -1; // Prioritize nodes over links
472
+ if (!bObj) return -1;
505
473
 
474
+ // Prioritize nodes over links
506
475
  var isNode = function isNode(o) {
507
476
  return o.__graphObjType === 'node';
508
477
  };
509
-
510
478
  return isNode(bObj) - isNode(aObj);
511
479
  }).tooltipContent(function (obj) {
512
480
  var graphObj = getGraphObj(obj);
513
- return graphObj ? accessorFn__default["default"](state["".concat(graphObj.__graphObjType, "Label")])(graphObj.__data) || '' : '';
481
+ return graphObj ? accessorFn(state["".concat(graphObj.__graphObjType, "Label")])(graphObj.__data) || '' : '';
514
482
  }).hoverDuringDrag(false).onHover(function (obj) {
515
483
  // Update tooltip and trigger onHover events
516
484
  var hoverObj = getGraphObj(obj);
517
-
518
485
  if (hoverObj !== state.hoverObj) {
519
486
  var prevObjType = state.hoverObj ? state.hoverObj.__graphObjType : null;
520
487
  var prevObjData = state.hoverObj ? state.hoverObj.__data : null;
521
488
  var objType = hoverObj ? hoverObj.__graphObjType : null;
522
489
  var objData = hoverObj ? hoverObj.__data : null;
523
-
524
490
  if (prevObjType && prevObjType !== objType) {
525
491
  // Hover out
526
492
  var fn = state["on".concat(prevObjType === 'node' ? 'Node' : 'Link', "Hover")];
527
493
  fn && fn(null, prevObjData);
528
494
  }
529
-
530
495
  if (objType) {
531
496
  // Hover in
532
497
  var _fn = state["on".concat(objType === 'node' ? 'Node' : 'Link', "Hover")];
533
498
  _fn && _fn(objData, prevObjType === objType ? prevObjData : null);
534
- } // set pointer if hovered object is clickable
535
-
499
+ }
536
500
 
501
+ // set pointer if hovered object is clickable
537
502
  renderer.domElement.classList[hoverObj && state["on".concat(objType === 'node' ? 'Node' : 'Link', "Click")] || !hoverObj && state.onBackgroundClick ? 'add' : 'remove']('clickable');
538
503
  state.hoverObj = hoverObj;
539
504
  }
540
505
  }).clickAfterDrag(false).onClick(function (obj, ev) {
541
506
  var graphObj = getGraphObj(obj);
542
-
543
507
  if (graphObj) {
544
508
  var fn = state["on".concat(graphObj.__graphObjType === 'node' ? 'Node' : 'Link', "Click")];
545
509
  fn && fn(graphObj.__data, ev);
@@ -549,27 +513,29 @@ var _3dForceGraph = Kapsule__default["default"]({
549
513
  }).onRightClick(function (obj, ev) {
550
514
  // Handle right-click events
551
515
  var graphObj = getGraphObj(obj);
552
-
553
516
  if (graphObj) {
554
517
  var fn = state["on".concat(graphObj.__graphObjType === 'node' ? 'Node' : 'Link', "RightClick")];
555
518
  fn && fn(graphObj.__data, ev);
556
519
  } else {
557
520
  state.onBackgroundRightClick && state.onBackgroundRightClick(ev);
558
521
  }
559
- }); //
560
- // Kick-off renderer
522
+ });
523
+
524
+ //
561
525
 
526
+ // Kick-off renderer
562
527
  this._animationCycle();
563
528
  }
564
- }); //
529
+ });
565
530
 
566
- function getGraphObj(object) {
567
- var obj = object; // recurse up object chain until finding the graph object
531
+ //
568
532
 
533
+ function getGraphObj(object) {
534
+ var obj = object;
535
+ // recurse up object chain until finding the graph object
569
536
  while (obj && !obj.hasOwnProperty('__graphObjType')) {
570
537
  obj = obj.parent;
571
538
  }
572
-
573
539
  return obj;
574
540
  }
575
541