three-forcegraph.common.js 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642
  1. 'use strict';
  2. var three$2 = require('three');
  3. var d3Force3d = require('d3-force-3d');
  4. var graph = require('ngraph.graph');
  5. var forcelayout = require('ngraph.forcelayout');
  6. var Kapsule = require('kapsule');
  7. var accessorFn = require('accessor-fn');
  8. var d3Array = require('d3-array');
  9. var dataJoint = require('data-joint');
  10. var d3Scale = require('d3-scale');
  11. var d3ScaleChromatic = require('d3-scale-chromatic');
  12. var tinyColor = require('tinycolor2');
  13. function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
  14. var graph__default = /*#__PURE__*/_interopDefaultLegacy(graph);
  15. var forcelayout__default = /*#__PURE__*/_interopDefaultLegacy(forcelayout);
  16. var Kapsule__default = /*#__PURE__*/_interopDefaultLegacy(Kapsule);
  17. var accessorFn__default = /*#__PURE__*/_interopDefaultLegacy(accessorFn);
  18. var dataJoint__default = /*#__PURE__*/_interopDefaultLegacy(dataJoint);
  19. var tinyColor__default = /*#__PURE__*/_interopDefaultLegacy(tinyColor);
  20. function ownKeys(object, enumerableOnly) {
  21. var keys = Object.keys(object);
  22. if (Object.getOwnPropertySymbols) {
  23. var symbols = Object.getOwnPropertySymbols(object);
  24. if (enumerableOnly) {
  25. symbols = symbols.filter(function (sym) {
  26. return Object.getOwnPropertyDescriptor(object, sym).enumerable;
  27. });
  28. }
  29. keys.push.apply(keys, symbols);
  30. }
  31. return keys;
  32. }
  33. function _objectSpread2(target) {
  34. for (var i = 1; i < arguments.length; i++) {
  35. var source = arguments[i] != null ? arguments[i] : {};
  36. if (i % 2) {
  37. ownKeys(Object(source), true).forEach(function (key) {
  38. _defineProperty(target, key, source[key]);
  39. });
  40. } else if (Object.getOwnPropertyDescriptors) {
  41. Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
  42. } else {
  43. ownKeys(Object(source)).forEach(function (key) {
  44. Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
  45. });
  46. }
  47. }
  48. return target;
  49. }
  50. function _typeof(obj) {
  51. "@babel/helpers - typeof";
  52. if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
  53. _typeof = function (obj) {
  54. return typeof obj;
  55. };
  56. } else {
  57. _typeof = function (obj) {
  58. return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
  59. };
  60. }
  61. return _typeof(obj);
  62. }
  63. function _classCallCheck(instance, Constructor) {
  64. if (!(instance instanceof Constructor)) {
  65. throw new TypeError("Cannot call a class as a function");
  66. }
  67. }
  68. function _defineProperty(obj, key, value) {
  69. if (key in obj) {
  70. Object.defineProperty(obj, key, {
  71. value: value,
  72. enumerable: true,
  73. configurable: true,
  74. writable: true
  75. });
  76. } else {
  77. obj[key] = value;
  78. }
  79. return obj;
  80. }
  81. function _inherits(subClass, superClass) {
  82. if (typeof superClass !== "function" && superClass !== null) {
  83. throw new TypeError("Super expression must either be null or a function");
  84. }
  85. subClass.prototype = Object.create(superClass && superClass.prototype, {
  86. constructor: {
  87. value: subClass,
  88. writable: true,
  89. configurable: true
  90. }
  91. });
  92. if (superClass) _setPrototypeOf(subClass, superClass);
  93. }
  94. function _getPrototypeOf(o) {
  95. _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
  96. return o.__proto__ || Object.getPrototypeOf(o);
  97. };
  98. return _getPrototypeOf(o);
  99. }
  100. function _setPrototypeOf(o, p) {
  101. _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
  102. o.__proto__ = p;
  103. return o;
  104. };
  105. return _setPrototypeOf(o, p);
  106. }
  107. function _isNativeReflectConstruct() {
  108. if (typeof Reflect === "undefined" || !Reflect.construct) return false;
  109. if (Reflect.construct.sham) return false;
  110. if (typeof Proxy === "function") return true;
  111. try {
  112. Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
  113. return true;
  114. } catch (e) {
  115. return false;
  116. }
  117. }
  118. function _construct(Parent, args, Class) {
  119. if (_isNativeReflectConstruct()) {
  120. _construct = Reflect.construct;
  121. } else {
  122. _construct = function _construct(Parent, args, Class) {
  123. var a = [null];
  124. a.push.apply(a, args);
  125. var Constructor = Function.bind.apply(Parent, a);
  126. var instance = new Constructor();
  127. if (Class) _setPrototypeOf(instance, Class.prototype);
  128. return instance;
  129. };
  130. }
  131. return _construct.apply(null, arguments);
  132. }
  133. function _objectWithoutPropertiesLoose(source, excluded) {
  134. if (source == null) return {};
  135. var target = {};
  136. var sourceKeys = Object.keys(source);
  137. var key, i;
  138. for (i = 0; i < sourceKeys.length; i++) {
  139. key = sourceKeys[i];
  140. if (excluded.indexOf(key) >= 0) continue;
  141. target[key] = source[key];
  142. }
  143. return target;
  144. }
  145. function _objectWithoutProperties(source, excluded) {
  146. if (source == null) return {};
  147. var target = _objectWithoutPropertiesLoose(source, excluded);
  148. var key, i;
  149. if (Object.getOwnPropertySymbols) {
  150. var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
  151. for (i = 0; i < sourceSymbolKeys.length; i++) {
  152. key = sourceSymbolKeys[i];
  153. if (excluded.indexOf(key) >= 0) continue;
  154. if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
  155. target[key] = source[key];
  156. }
  157. }
  158. return target;
  159. }
  160. function _assertThisInitialized(self) {
  161. if (self === void 0) {
  162. throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
  163. }
  164. return self;
  165. }
  166. function _possibleConstructorReturn(self, call) {
  167. if (call && (typeof call === "object" || typeof call === "function")) {
  168. return call;
  169. }
  170. return _assertThisInitialized(self);
  171. }
  172. function _createSuper(Derived) {
  173. var hasNativeReflectConstruct = _isNativeReflectConstruct();
  174. return function _createSuperInternal() {
  175. var Super = _getPrototypeOf(Derived),
  176. result;
  177. if (hasNativeReflectConstruct) {
  178. var NewTarget = _getPrototypeOf(this).constructor;
  179. result = Reflect.construct(Super, arguments, NewTarget);
  180. } else {
  181. result = Super.apply(this, arguments);
  182. }
  183. return _possibleConstructorReturn(this, result);
  184. };
  185. }
  186. function _slicedToArray(arr, i) {
  187. return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
  188. }
  189. function _toConsumableArray(arr) {
  190. return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
  191. }
  192. function _arrayWithoutHoles(arr) {
  193. if (Array.isArray(arr)) return _arrayLikeToArray(arr);
  194. }
  195. function _arrayWithHoles(arr) {
  196. if (Array.isArray(arr)) return arr;
  197. }
  198. function _iterableToArray(iter) {
  199. if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
  200. }
  201. function _iterableToArrayLimit(arr, i) {
  202. var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
  203. if (_i == null) return;
  204. var _arr = [];
  205. var _n = true;
  206. var _d = false;
  207. var _s, _e;
  208. try {
  209. for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
  210. _arr.push(_s.value);
  211. if (i && _arr.length === i) break;
  212. }
  213. } catch (err) {
  214. _d = true;
  215. _e = err;
  216. } finally {
  217. try {
  218. if (!_n && _i["return"] != null) _i["return"]();
  219. } finally {
  220. if (_d) throw _e;
  221. }
  222. }
  223. return _arr;
  224. }
  225. function _unsupportedIterableToArray(o, minLen) {
  226. if (!o) return;
  227. if (typeof o === "string") return _arrayLikeToArray(o, minLen);
  228. var n = Object.prototype.toString.call(o).slice(8, -1);
  229. if (n === "Object" && o.constructor) n = o.constructor.name;
  230. if (n === "Map" || n === "Set") return Array.from(o);
  231. if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
  232. }
  233. function _arrayLikeToArray(arr, len) {
  234. if (len == null || len > arr.length) len = arr.length;
  235. for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
  236. return arr2;
  237. }
  238. function _nonIterableSpread() {
  239. throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
  240. }
  241. function _nonIterableRest() {
  242. throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
  243. }
  244. var materialDispose = function materialDispose(material) {
  245. if (material instanceof Array) {
  246. material.forEach(materialDispose);
  247. } else {
  248. if (material.map) {
  249. material.map.dispose();
  250. }
  251. material.dispose();
  252. }
  253. };
  254. var deallocate = function deallocate(obj) {
  255. if (obj.geometry) {
  256. obj.geometry.dispose();
  257. }
  258. if (obj.material) {
  259. materialDispose(obj.material);
  260. }
  261. if (obj.texture) {
  262. obj.texture.dispose();
  263. }
  264. if (obj.children) {
  265. obj.children.forEach(deallocate);
  266. }
  267. };
  268. var emptyObject = function emptyObject(obj) {
  269. while (obj.children.length) {
  270. var childObj = obj.children[0];
  271. obj.remove(childObj);
  272. deallocate(childObj);
  273. }
  274. };
  275. var _excluded = ["objFilter"];
  276. function threeDigest(data, scene) {
  277. var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
  278. var _ref$objFilter = _ref.objFilter,
  279. objFilter = _ref$objFilter === void 0 ? function () {
  280. return true;
  281. } : _ref$objFilter,
  282. options = _objectWithoutProperties(_ref, _excluded);
  283. return dataJoint__default['default'](data, scene.children.filter(objFilter), function (obj) {
  284. return scene.add(obj);
  285. }, function (obj) {
  286. scene.remove(obj);
  287. emptyObject(obj);
  288. }, _objectSpread2({
  289. objBindAttr: '__threeObj'
  290. }, options));
  291. }
  292. var colorStr2Hex = function colorStr2Hex(str) {
  293. return isNaN(str) ? parseInt(tinyColor__default['default'](str).toHex(), 16) : str;
  294. };
  295. var colorAlpha = function colorAlpha(str) {
  296. return isNaN(str) ? tinyColor__default['default'](str).getAlpha() : 1;
  297. };
  298. var autoColorScale = d3Scale.scaleOrdinal(d3ScaleChromatic.schemePaired); // Autoset attribute colorField by colorByAccessor property
  299. // If an object has already a color, don't set it
  300. // Objects can be nodes or links
  301. function autoColorObjects(objects, colorByAccessor, colorField) {
  302. if (!colorByAccessor || typeof colorField !== 'string') return;
  303. objects.filter(function (obj) {
  304. return !obj[colorField];
  305. }).forEach(function (obj) {
  306. obj[colorField] = autoColorScale(colorByAccessor(obj));
  307. });
  308. }
  309. function getDagDepths (_ref, idAccessor) {
  310. var nodes = _ref.nodes,
  311. links = _ref.links;
  312. var _ref2 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
  313. _ref2$nodeFilter = _ref2.nodeFilter,
  314. nodeFilter = _ref2$nodeFilter === void 0 ? function () {
  315. return true;
  316. } : _ref2$nodeFilter,
  317. _ref2$onLoopError = _ref2.onLoopError,
  318. onLoopError = _ref2$onLoopError === void 0 ? function (loopIds) {
  319. throw "Invalid DAG structure! Found cycle in node path: ".concat(loopIds.join(' -> '), ".");
  320. } : _ref2$onLoopError;
  321. // linked graph
  322. var graph = {};
  323. nodes.forEach(function (node) {
  324. return graph[idAccessor(node)] = {
  325. data: node,
  326. out: [],
  327. depth: -1,
  328. skip: !nodeFilter(node)
  329. };
  330. });
  331. links.forEach(function (_ref3) {
  332. var source = _ref3.source,
  333. target = _ref3.target;
  334. var sourceId = getNodeId(source);
  335. var targetId = getNodeId(target);
  336. if (!graph.hasOwnProperty(sourceId)) throw "Missing source node with id: ".concat(sourceId);
  337. if (!graph.hasOwnProperty(targetId)) throw "Missing target node with id: ".concat(targetId);
  338. var sourceNode = graph[sourceId];
  339. var targetNode = graph[targetId];
  340. sourceNode.out.push(targetNode);
  341. function getNodeId(node) {
  342. return _typeof(node) === 'object' ? idAccessor(node) : node;
  343. }
  344. });
  345. var foundLoops = [];
  346. traverse(Object.values(graph));
  347. var nodeDepths = Object.assign.apply(Object, [{}].concat(_toConsumableArray(Object.entries(graph).filter(function (_ref4) {
  348. var _ref5 = _slicedToArray(_ref4, 2),
  349. node = _ref5[1];
  350. return !node.skip;
  351. }).map(function (_ref6) {
  352. var _ref7 = _slicedToArray(_ref6, 2),
  353. id = _ref7[0],
  354. node = _ref7[1];
  355. return _defineProperty({}, id, node.depth);
  356. }))));
  357. return nodeDepths;
  358. function traverse(nodes) {
  359. var nodeStack = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
  360. var currentDepth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
  361. for (var i = 0, l = nodes.length; i < l; i++) {
  362. var node = nodes[i];
  363. if (nodeStack.indexOf(node) !== -1) {
  364. var _ret = function () {
  365. var loop = [].concat(_toConsumableArray(nodeStack.slice(nodeStack.indexOf(node))), [node]).map(function (d) {
  366. return idAccessor(d.data);
  367. });
  368. if (!foundLoops.some(function (foundLoop) {
  369. return foundLoop.length === loop.length && foundLoop.every(function (id, idx) {
  370. return id === loop[idx];
  371. });
  372. })) {
  373. foundLoops.push(loop);
  374. onLoopError(loop);
  375. }
  376. return "continue";
  377. }();
  378. if (_ret === "continue") continue;
  379. }
  380. if (currentDepth > node.depth) {
  381. // Don't unnecessarily revisit chunks of the graph
  382. node.depth = currentDepth;
  383. traverse(node.out, [].concat(_toConsumableArray(nodeStack), [node]), currentDepth + (node.skip ? 0 : 1));
  384. }
  385. }
  386. }
  387. }
  388. var three$1 = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists
  389. : {
  390. Group: three$2.Group,
  391. Mesh: three$2.Mesh,
  392. MeshLambertMaterial: three$2.MeshLambertMaterial,
  393. Color: three$2.Color,
  394. BufferGeometry: three$2.BufferGeometry,
  395. BufferAttribute: three$2.BufferAttribute,
  396. Matrix4: three$2.Matrix4,
  397. Vector3: three$2.Vector3,
  398. SphereBufferGeometry: three$2.SphereBufferGeometry,
  399. CylinderBufferGeometry: three$2.CylinderBufferGeometry,
  400. TubeBufferGeometry: three$2.TubeBufferGeometry,
  401. ConeBufferGeometry: three$2.ConeBufferGeometry,
  402. Line: three$2.Line,
  403. LineBasicMaterial: three$2.LineBasicMaterial,
  404. QuadraticBezierCurve3: three$2.QuadraticBezierCurve3,
  405. CubicBezierCurve3: three$2.CubicBezierCurve3,
  406. Box3: three$2.Box3
  407. };
  408. var ngraph = {
  409. graph: graph__default['default'],
  410. forcelayout: forcelayout__default['default']
  411. };
  412. var DAG_LEVEL_NODE_RATIO = 2; // support multiple method names for backwards threejs compatibility
  413. var setAttributeFn = new three$1.BufferGeometry().setAttribute ? 'setAttribute' : 'addAttribute';
  414. var applyMatrix4Fn = new three$1.BufferGeometry().applyMatrix4 ? 'applyMatrix4' : 'applyMatrix';
  415. var ForceGraph = Kapsule__default['default']({
  416. props: {
  417. jsonUrl: {
  418. onChange: function onChange(jsonUrl, state) {
  419. var _this = this;
  420. if (jsonUrl && !state.fetchingJson) {
  421. // Load data asynchronously
  422. state.fetchingJson = true;
  423. state.onLoading();
  424. fetch(jsonUrl).then(function (r) {
  425. return r.json();
  426. }).then(function (json) {
  427. state.fetchingJson = false;
  428. state.onFinishLoading(json);
  429. _this.graphData(json);
  430. });
  431. }
  432. },
  433. triggerUpdate: false
  434. },
  435. graphData: {
  436. "default": {
  437. nodes: [],
  438. links: []
  439. },
  440. onChange: function onChange(graphData, state) {
  441. state.engineRunning = false; // Pause simulation immediately
  442. }
  443. },
  444. numDimensions: {
  445. "default": 3,
  446. onChange: function onChange(numDim, state) {
  447. var chargeForce = state.d3ForceLayout.force('charge'); // Increase repulsion on 3D mode for improved spatial separation
  448. if (chargeForce) {
  449. chargeForce.strength(numDim > 2 ? -60 : -30);
  450. }
  451. if (numDim < 3) {
  452. eraseDimension(state.graphData.nodes, 'z');
  453. }
  454. if (numDim < 2) {
  455. eraseDimension(state.graphData.nodes, 'y');
  456. }
  457. function eraseDimension(nodes, dim) {
  458. nodes.forEach(function (d) {
  459. delete d[dim]; // position
  460. delete d["v".concat(dim)]; // velocity
  461. });
  462. }
  463. }
  464. },
  465. dagMode: {
  466. onChange: function onChange(dagMode, state) {
  467. // td, bu, lr, rl, zin, zout, radialin, radialout
  468. !dagMode && state.forceEngine === 'd3' && (state.graphData.nodes || []).forEach(function (n) {
  469. return n.fx = n.fy = n.fz = undefined;
  470. }); // unfix nodes when disabling dag mode
  471. }
  472. },
  473. dagLevelDistance: {},
  474. dagNodeFilter: {
  475. "default": function _default(node) {
  476. return true;
  477. }
  478. },
  479. onDagError: {
  480. triggerUpdate: false
  481. },
  482. nodeRelSize: {
  483. "default": 4
  484. },
  485. // volume per val unit
  486. nodeId: {
  487. "default": 'id'
  488. },
  489. nodeVal: {
  490. "default": 'val'
  491. },
  492. nodeResolution: {
  493. "default": 8
  494. },
  495. // how many slice segments in the sphere's circumference
  496. nodeColor: {
  497. "default": 'color'
  498. },
  499. nodeAutoColorBy: {},
  500. nodeOpacity: {
  501. "default": 0.75
  502. },
  503. nodeVisibility: {
  504. "default": true
  505. },
  506. nodeThreeObject: {},
  507. nodeThreeObjectExtend: {
  508. "default": false
  509. },
  510. linkSource: {
  511. "default": 'source'
  512. },
  513. linkTarget: {
  514. "default": 'target'
  515. },
  516. linkVisibility: {
  517. "default": true
  518. },
  519. linkColor: {
  520. "default": 'color'
  521. },
  522. linkAutoColorBy: {},
  523. linkOpacity: {
  524. "default": 0.2
  525. },
  526. linkWidth: {},
  527. // Rounded to nearest decimal. For falsy values use dimensionless line with 1px regardless of distance.
  528. linkResolution: {
  529. "default": 6
  530. },
  531. // how many radial segments in each line tube's geometry
  532. linkCurvature: {
  533. "default": 0,
  534. triggerUpdate: false
  535. },
  536. // line curvature radius (0: straight, 1: semi-circle)
  537. linkCurveRotation: {
  538. "default": 0,
  539. triggerUpdate: false
  540. },
  541. // line curve rotation along the line axis (0: interection with XY plane, PI: upside down)
  542. linkMaterial: {},
  543. linkThreeObject: {},
  544. linkThreeObjectExtend: {
  545. "default": false
  546. },
  547. linkPositionUpdate: {
  548. triggerUpdate: false
  549. },
  550. // custom function to call for updating the link's position. Signature: (threeObj, { start: { x, y, z}, end: { x, y, z }}, link). If the function returns a truthy value, the regular link position update will not run.
  551. linkDirectionalArrowLength: {
  552. "default": 0
  553. },
  554. linkDirectionalArrowColor: {},
  555. linkDirectionalArrowRelPos: {
  556. "default": 0.5,
  557. triggerUpdate: false
  558. },
  559. // value between 0<>1 indicating the relative pos along the (exposed) line
  560. linkDirectionalArrowResolution: {
  561. "default": 8
  562. },
  563. // how many slice segments in the arrow's conic circumference
  564. linkDirectionalParticles: {
  565. "default": 0
  566. },
  567. // animate photons travelling in the link direction
  568. linkDirectionalParticleSpeed: {
  569. "default": 0.01,
  570. triggerUpdate: false
  571. },
  572. // in link length ratio per frame
  573. linkDirectionalParticleWidth: {
  574. "default": 0.5
  575. },
  576. linkDirectionalParticleColor: {},
  577. linkDirectionalParticleResolution: {
  578. "default": 4
  579. },
  580. // how many slice segments in the particle sphere's circumference
  581. forceEngine: {
  582. "default": 'd3'
  583. },
  584. // d3 or ngraph
  585. d3AlphaMin: {
  586. "default": 0
  587. },
  588. d3AlphaDecay: {
  589. "default": 0.0228,
  590. triggerUpdate: false,
  591. onChange: function onChange(alphaDecay, state) {
  592. state.d3ForceLayout.alphaDecay(alphaDecay);
  593. }
  594. },
  595. d3AlphaTarget: {
  596. "default": 0,
  597. triggerUpdate: false,
  598. onChange: function onChange(alphaTarget, state) {
  599. state.d3ForceLayout.alphaTarget(alphaTarget);
  600. }
  601. },
  602. d3VelocityDecay: {
  603. "default": 0.4,
  604. triggerUpdate: false,
  605. onChange: function onChange(velocityDecay, state) {
  606. state.d3ForceLayout.velocityDecay(velocityDecay);
  607. }
  608. },
  609. ngraphPhysics: {
  610. "default": {
  611. // defaults from https://github.com/anvaka/ngraph.physics.simulator/blob/master/index.js
  612. timeStep: 20,
  613. gravity: -1.2,
  614. theta: 0.8,
  615. springLength: 30,
  616. springCoefficient: 0.0008,
  617. dragCoefficient: 0.02
  618. }
  619. },
  620. warmupTicks: {
  621. "default": 0,
  622. triggerUpdate: false
  623. },
  624. // how many times to tick the force engine at init before starting to render
  625. cooldownTicks: {
  626. "default": Infinity,
  627. triggerUpdate: false
  628. },
  629. cooldownTime: {
  630. "default": 15000,
  631. triggerUpdate: false
  632. },
  633. // ms
  634. onLoading: {
  635. "default": function _default() {},
  636. triggerUpdate: false
  637. },
  638. onFinishLoading: {
  639. "default": function _default() {},
  640. triggerUpdate: false
  641. },
  642. onUpdate: {
  643. "default": function _default() {},
  644. triggerUpdate: false
  645. },
  646. onFinishUpdate: {
  647. "default": function _default() {},
  648. triggerUpdate: false
  649. },
  650. onEngineTick: {
  651. "default": function _default() {},
  652. triggerUpdate: false
  653. },
  654. onEngineStop: {
  655. "default": function _default() {},
  656. triggerUpdate: false
  657. }
  658. },
  659. methods: {
  660. refresh: function refresh(state) {
  661. state._flushObjects = true;
  662. state._rerender();
  663. return this;
  664. },
  665. // Expose d3 forces for external manipulation
  666. d3Force: function d3Force(state, forceName, forceFn) {
  667. if (forceFn === undefined) {
  668. return state.d3ForceLayout.force(forceName); // Force getter
  669. }
  670. state.d3ForceLayout.force(forceName, forceFn); // Force setter
  671. return this;
  672. },
  673. d3ReheatSimulation: function d3ReheatSimulation(state) {
  674. state.d3ForceLayout.alpha(1);
  675. this.resetCountdown();
  676. return this;
  677. },
  678. // reset cooldown state
  679. resetCountdown: function resetCountdown(state) {
  680. state.cntTicks = 0;
  681. state.startTickTime = new Date();
  682. state.engineRunning = true;
  683. return this;
  684. },
  685. tickFrame: function tickFrame(state) {
  686. var isD3Sim = state.forceEngine !== 'ngraph';
  687. if (state.engineRunning) {
  688. layoutTick();
  689. }
  690. updateArrows();
  691. updatePhotons();
  692. return this; //
  693. function layoutTick() {
  694. if (++state.cntTicks > state.cooldownTicks || new Date() - state.startTickTime > state.cooldownTime || isD3Sim && state.d3AlphaMin > 0 && state.d3ForceLayout.alpha() < state.d3AlphaMin) {
  695. state.engineRunning = false; // Stop ticking graph
  696. state.onEngineStop();
  697. } else {
  698. state.layout[isD3Sim ? 'tick' : 'step'](); // Tick it
  699. state.onEngineTick();
  700. } // Update nodes position
  701. state.graphData.nodes.forEach(function (node) {
  702. var obj = node.__threeObj;
  703. if (!obj) return;
  704. var pos = isD3Sim ? node : state.layout.getNodePosition(node[state.nodeId]);
  705. obj.position.x = pos.x;
  706. obj.position.y = pos.y || 0;
  707. obj.position.z = pos.z || 0;
  708. }); // Update links position
  709. var linkWidthAccessor = accessorFn__default['default'](state.linkWidth);
  710. var linkCurvatureAccessor = accessorFn__default['default'](state.linkCurvature);
  711. var linkCurveRotationAccessor = accessorFn__default['default'](state.linkCurveRotation);
  712. var linkThreeObjectExtendAccessor = accessorFn__default['default'](state.linkThreeObjectExtend);
  713. state.graphData.links.forEach(function (link) {
  714. var lineObj = link.__lineObj;
  715. if (!lineObj) return;
  716. var pos = isD3Sim ? link : state.layout.getLinkPosition(state.layout.graph.getLink(link.source, link.target).id);
  717. var start = pos[isD3Sim ? 'source' : 'from'];
  718. var end = pos[isD3Sim ? 'target' : 'to'];
  719. if (!start || !end || !start.hasOwnProperty('x') || !end.hasOwnProperty('x')) return; // skip invalid link
  720. calcLinkCurve(link); // calculate link curve for all links, including custom replaced, so it can be used in directional functionality
  721. var extendedObj = linkThreeObjectExtendAccessor(link);
  722. if (state.linkPositionUpdate && state.linkPositionUpdate(extendedObj ? lineObj.children[1] : lineObj, // pass child custom object if extending the default
  723. {
  724. start: {
  725. x: start.x,
  726. y: start.y,
  727. z: start.z
  728. },
  729. end: {
  730. x: end.x,
  731. y: end.y,
  732. z: end.z
  733. }
  734. }, link) && !extendedObj) {
  735. // exit if successfully custom updated position of non-extended obj
  736. return;
  737. }
  738. var curveResolution = 30; // # line segments
  739. var curve = link.__curve; // select default line obj if it's an extended group
  740. var line = lineObj.children.length ? lineObj.children[0] : lineObj;
  741. if (line.type === 'Line') {
  742. // Update line geometry
  743. if (!curve) {
  744. // straight line
  745. var linePos = line.geometry.getAttribute('position');
  746. if (!linePos || !linePos.array || linePos.array.length !== 6) {
  747. line.geometry[setAttributeFn]('position', linePos = new three$1.BufferAttribute(new Float32Array(2 * 3), 3));
  748. }
  749. linePos.array[0] = start.x;
  750. linePos.array[1] = start.y || 0;
  751. linePos.array[2] = start.z || 0;
  752. linePos.array[3] = end.x;
  753. linePos.array[4] = end.y || 0;
  754. linePos.array[5] = end.z || 0;
  755. linePos.needsUpdate = true;
  756. } else {
  757. // bezier curve line
  758. line.geometry.setFromPoints(curve.getPoints(curveResolution));
  759. }
  760. line.geometry.computeBoundingSphere();
  761. } else if (line.type === 'Mesh') {
  762. // Update cylinder geometry
  763. if (!curve) {
  764. // straight tube
  765. if (!line.geometry.type.match(/^Cylinder(Buffer)?Geometry$/)) {
  766. var linkWidth = Math.ceil(linkWidthAccessor(link) * 10) / 10;
  767. var r = linkWidth / 2;
  768. var geometry = new three$1.CylinderBufferGeometry(r, r, 1, state.linkResolution, 1, false);
  769. geometry[applyMatrix4Fn](new three$1.Matrix4().makeTranslation(0, 1 / 2, 0));
  770. geometry[applyMatrix4Fn](new three$1.Matrix4().makeRotationX(Math.PI / 2));
  771. line.geometry.dispose();
  772. line.geometry = geometry;
  773. }
  774. var vStart = new three$1.Vector3(start.x, start.y || 0, start.z || 0);
  775. var vEnd = new three$1.Vector3(end.x, end.y || 0, end.z || 0);
  776. var distance = vStart.distanceTo(vEnd);
  777. line.position.x = vStart.x;
  778. line.position.y = vStart.y;
  779. line.position.z = vStart.z;
  780. line.scale.z = distance;
  781. line.parent.localToWorld(vEnd); // lookAt requires world coords
  782. line.lookAt(vEnd);
  783. } else {
  784. // curved tube
  785. if (!line.geometry.type.match(/^Tube(Buffer)?Geometry$/)) {
  786. // reset object positioning
  787. line.position.set(0, 0, 0);
  788. line.rotation.set(0, 0, 0);
  789. line.scale.set(1, 1, 1);
  790. }
  791. var _linkWidth = Math.ceil(linkWidthAccessor(link) * 10) / 10;
  792. var _r = _linkWidth / 2;
  793. var _geometry = new three$1.TubeBufferGeometry(curve, curveResolution, _r, state.linkResolution, false);
  794. line.geometry.dispose();
  795. line.geometry = _geometry;
  796. }
  797. }
  798. }); //
  799. function calcLinkCurve(link) {
  800. var pos = isD3Sim ? link : state.layout.getLinkPosition(state.layout.graph.getLink(link.source, link.target).id);
  801. var start = pos[isD3Sim ? 'source' : 'from'];
  802. var end = pos[isD3Sim ? 'target' : 'to'];
  803. if (!start || !end || !start.hasOwnProperty('x') || !end.hasOwnProperty('x')) return; // skip invalid link
  804. var curvature = linkCurvatureAccessor(link);
  805. if (!curvature) {
  806. link.__curve = null; // Straight line
  807. } else {
  808. // bezier curve line (only for line types)
  809. var vStart = new three$1.Vector3(start.x, start.y || 0, start.z || 0);
  810. var vEnd = new three$1.Vector3(end.x, end.y || 0, end.z || 0);
  811. var l = vStart.distanceTo(vEnd); // line length
  812. var curve;
  813. var curveRotation = linkCurveRotationAccessor(link);
  814. if (l > 0) {
  815. var dx = end.x - start.x;
  816. var dy = end.y - start.y || 0;
  817. var vLine = new three$1.Vector3().subVectors(vEnd, vStart);
  818. var cp = vLine.clone().multiplyScalar(curvature).cross(dx !== 0 || dy !== 0 ? new three$1.Vector3(0, 0, 1) : new three$1.Vector3(0, 1, 0)) // avoid cross-product of parallel vectors (prefer Z, fallback to Y)
  819. .applyAxisAngle(vLine.normalize(), curveRotation) // rotate along line axis according to linkCurveRotation
  820. .add(new three$1.Vector3().addVectors(vStart, vEnd).divideScalar(2));
  821. curve = new three$1.QuadraticBezierCurve3(vStart, cp, vEnd);
  822. } else {
  823. // Same point, draw a loop
  824. var d = curvature * 70;
  825. var endAngle = -curveRotation; // Rotate clockwise (from Z angle perspective)
  826. var startAngle = endAngle + Math.PI / 2;
  827. curve = new three$1.CubicBezierCurve3(vStart, new three$1.Vector3(d * Math.cos(startAngle), d * Math.sin(startAngle), 0).add(vStart), new three$1.Vector3(d * Math.cos(endAngle), d * Math.sin(endAngle), 0).add(vStart), vEnd);
  828. }
  829. link.__curve = curve;
  830. }
  831. }
  832. }
  833. function updateArrows() {
  834. // update link arrow position
  835. var arrowRelPosAccessor = accessorFn__default['default'](state.linkDirectionalArrowRelPos);
  836. var arrowLengthAccessor = accessorFn__default['default'](state.linkDirectionalArrowLength);
  837. var nodeValAccessor = accessorFn__default['default'](state.nodeVal);
  838. state.graphData.links.forEach(function (link) {
  839. var arrowObj = link.__arrowObj;
  840. if (!arrowObj) return;
  841. var pos = isD3Sim ? link : state.layout.getLinkPosition(state.layout.graph.getLink(link.source, link.target).id);
  842. var start = pos[isD3Sim ? 'source' : 'from'];
  843. var end = pos[isD3Sim ? 'target' : 'to'];
  844. if (!start || !end || !start.hasOwnProperty('x') || !end.hasOwnProperty('x')) return; // skip invalid link
  845. var startR = Math.sqrt(Math.max(0, nodeValAccessor(start) || 1)) * state.nodeRelSize;
  846. var endR = Math.sqrt(Math.max(0, nodeValAccessor(end) || 1)) * state.nodeRelSize;
  847. var arrowLength = arrowLengthAccessor(link);
  848. var arrowRelPos = arrowRelPosAccessor(link);
  849. var getPosAlongLine = link.__curve ? function (t) {
  850. return link.__curve.getPoint(t);
  851. } // interpolate along bezier curve
  852. : function (t) {
  853. // straight line: interpolate linearly
  854. var iplt = function iplt(dim, start, end, t) {
  855. return start[dim] + (end[dim] - start[dim]) * t || 0;
  856. };
  857. return {
  858. x: iplt('x', start, end, t),
  859. y: iplt('y', start, end, t),
  860. z: iplt('z', start, end, t)
  861. };
  862. };
  863. var lineLen = link.__curve ? link.__curve.getLength() : Math.sqrt(['x', 'y', 'z'].map(function (dim) {
  864. return Math.pow((end[dim] || 0) - (start[dim] || 0), 2);
  865. }).reduce(function (acc, v) {
  866. return acc + v;
  867. }, 0));
  868. var posAlongLine = startR + arrowLength + (lineLen - startR - endR - arrowLength) * arrowRelPos;
  869. var arrowHead = getPosAlongLine(posAlongLine / lineLen);
  870. var arrowTail = getPosAlongLine((posAlongLine - arrowLength) / lineLen);
  871. ['x', 'y', 'z'].forEach(function (dim) {
  872. return arrowObj.position[dim] = arrowTail[dim];
  873. });
  874. var headVec = _construct(three$1.Vector3, _toConsumableArray(['x', 'y', 'z'].map(function (c) {
  875. return arrowHead[c];
  876. })));
  877. arrowObj.parent.localToWorld(headVec); // lookAt requires world coords
  878. arrowObj.lookAt(headVec);
  879. });
  880. }
  881. function updatePhotons() {
  882. // update link particle positions
  883. var particleSpeedAccessor = accessorFn__default['default'](state.linkDirectionalParticleSpeed);
  884. state.graphData.links.forEach(function (link) {
  885. var cyclePhotons = link.__photonsObj && link.__photonsObj.children;
  886. var singleHopPhotons = link.__singleHopPhotonsObj && link.__singleHopPhotonsObj.children;
  887. if ((!singleHopPhotons || !singleHopPhotons.length) && (!cyclePhotons || !cyclePhotons.length)) return;
  888. var pos = isD3Sim ? link : state.layout.getLinkPosition(state.layout.graph.getLink(link.source, link.target).id);
  889. var start = pos[isD3Sim ? 'source' : 'from'];
  890. var end = pos[isD3Sim ? 'target' : 'to'];
  891. if (!start || !end || !start.hasOwnProperty('x') || !end.hasOwnProperty('x')) return; // skip invalid link
  892. var particleSpeed = particleSpeedAccessor(link);
  893. var getPhotonPos = link.__curve ? function (t) {
  894. return link.__curve.getPoint(t);
  895. } // interpolate along bezier curve
  896. : function (t) {
  897. // straight line: interpolate linearly
  898. var iplt = function iplt(dim, start, end, t) {
  899. return start[dim] + (end[dim] - start[dim]) * t || 0;
  900. };
  901. return {
  902. x: iplt('x', start, end, t),
  903. y: iplt('y', start, end, t),
  904. z: iplt('z', start, end, t)
  905. };
  906. };
  907. var photons = [].concat(_toConsumableArray(cyclePhotons || []), _toConsumableArray(singleHopPhotons || []));
  908. photons.forEach(function (photon, idx) {
  909. var singleHop = photon.parent.__linkThreeObjType === 'singleHopPhotons';
  910. if (!photon.hasOwnProperty('__progressRatio')) {
  911. photon.__progressRatio = singleHop ? 0 : idx / cyclePhotons.length;
  912. }
  913. photon.__progressRatio += particleSpeed;
  914. if (photon.__progressRatio >= 1) {
  915. if (!singleHop) {
  916. photon.__progressRatio = photon.__progressRatio % 1;
  917. } else {
  918. // remove particle
  919. photon.parent.remove(photon);
  920. emptyObject(photon);
  921. return;
  922. }
  923. }
  924. var photonPosRatio = photon.__progressRatio;
  925. var pos = getPhotonPos(photonPosRatio);
  926. ['x', 'y', 'z'].forEach(function (dim) {
  927. return photon.position[dim] = pos[dim];
  928. });
  929. });
  930. });
  931. }
  932. },
  933. emitParticle: function emitParticle(state, link) {
  934. if (link) {
  935. if (!link.__singleHopPhotonsObj) {
  936. var obj = new three$1.Group();
  937. obj.__linkThreeObjType = 'singleHopPhotons';
  938. link.__singleHopPhotonsObj = obj;
  939. state.graphScene.add(obj);
  940. }
  941. var particleWidthAccessor = accessorFn__default['default'](state.linkDirectionalParticleWidth);
  942. var photonR = Math.ceil(particleWidthAccessor(link) * 10) / 10 / 2;
  943. var numSegments = state.linkDirectionalParticleResolution;
  944. var particleGeometry = new three$1.SphereBufferGeometry(photonR, numSegments, numSegments);
  945. var linkColorAccessor = accessorFn__default['default'](state.linkColor);
  946. var particleColorAccessor = accessorFn__default['default'](state.linkDirectionalParticleColor);
  947. var photonColor = particleColorAccessor(link) || linkColorAccessor(link) || '#f0f0f0';
  948. var materialColor = new three$1.Color(colorStr2Hex(photonColor));
  949. var opacity = state.linkOpacity * 3;
  950. var particleMaterial = new three$1.MeshLambertMaterial({
  951. color: materialColor,
  952. transparent: true,
  953. opacity: opacity
  954. }); // add a single hop particle
  955. link.__singleHopPhotonsObj.add(new three$1.Mesh(particleGeometry, particleMaterial));
  956. }
  957. return this;
  958. },
  959. getGraphBbox: function getGraphBbox(state) {
  960. var nodeFilter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
  961. return true;
  962. };
  963. if (!state.initialised) return null; // recursively collect all nested geometries bboxes
  964. var bboxes = function getBboxes(obj) {
  965. var bboxes = [];
  966. if (obj.geometry) {
  967. obj.geometry.computeBoundingBox();
  968. var box = new three$1.Box3();
  969. box.copy(obj.geometry.boundingBox).applyMatrix4(obj.matrixWorld);
  970. bboxes.push(box);
  971. }
  972. return bboxes.concat.apply(bboxes, _toConsumableArray((obj.children || []).filter(function (obj) {
  973. return !obj.hasOwnProperty('__graphObjType') || obj.__graphObjType === 'node' && nodeFilter(obj.__data);
  974. } // exclude filtered out nodes
  975. ).map(getBboxes)));
  976. }(state.graphScene);
  977. if (!bboxes.length) return null; // extract global x,y,z min/max
  978. return Object.assign.apply(Object, _toConsumableArray(['x', 'y', 'z'].map(function (c) {
  979. return _defineProperty({}, c, [d3Array.min(bboxes, function (bb) {
  980. return bb.min[c];
  981. }), d3Array.max(bboxes, function (bb) {
  982. return bb.max[c];
  983. })]);
  984. })));
  985. }
  986. },
  987. stateInit: function stateInit() {
  988. return {
  989. d3ForceLayout: d3Force3d.forceSimulation().force('link', d3Force3d.forceLink()).force('charge', d3Force3d.forceManyBody()).force('center', d3Force3d.forceCenter()).force('dagRadial', null).stop(),
  990. engineRunning: false
  991. };
  992. },
  993. init: function init(threeObj, state) {
  994. // Main three object to manipulate
  995. state.graphScene = threeObj;
  996. },
  997. update: function update(state, changedProps) {
  998. var hasAnyPropChanged = function hasAnyPropChanged(propList) {
  999. return propList.some(function (p) {
  1000. return changedProps.hasOwnProperty(p);
  1001. });
  1002. };
  1003. state.engineRunning = false; // pause simulation
  1004. state.onUpdate();
  1005. if (state.nodeAutoColorBy !== null && hasAnyPropChanged(['nodeAutoColorBy', 'graphData', 'nodeColor'])) {
  1006. // Auto add color to uncolored nodes
  1007. autoColorObjects(state.graphData.nodes, accessorFn__default['default'](state.nodeAutoColorBy), state.nodeColor);
  1008. }
  1009. if (state.linkAutoColorBy !== null && hasAnyPropChanged(['linkAutoColorBy', 'graphData', 'linkColor'])) {
  1010. // Auto add color to uncolored links
  1011. autoColorObjects(state.graphData.links, accessorFn__default['default'](state.linkAutoColorBy), state.linkColor);
  1012. } // Digest nodes WebGL objects
  1013. if (state._flushObjects || hasAnyPropChanged(['graphData', 'nodeThreeObject', 'nodeThreeObjectExtend', 'nodeVal', 'nodeColor', 'nodeVisibility', 'nodeRelSize', 'nodeResolution', 'nodeOpacity'])) {
  1014. var customObjectAccessor = accessorFn__default['default'](state.nodeThreeObject);
  1015. var customObjectExtendAccessor = accessorFn__default['default'](state.nodeThreeObjectExtend);
  1016. var valAccessor = accessorFn__default['default'](state.nodeVal);
  1017. var colorAccessor = accessorFn__default['default'](state.nodeColor);
  1018. var visibilityAccessor = accessorFn__default['default'](state.nodeVisibility);
  1019. var sphereGeometries = {}; // indexed by node value
  1020. var sphereMaterials = {}; // indexed by color
  1021. threeDigest(state.graphData.nodes.filter(visibilityAccessor), state.graphScene, {
  1022. purge: state._flushObjects || hasAnyPropChanged([// recreate objects if any of these props have changed
  1023. 'nodeThreeObject', 'nodeThreeObjectExtend']),
  1024. objFilter: function objFilter(obj) {
  1025. return obj.__graphObjType === 'node';
  1026. },
  1027. createObj: function createObj(node) {
  1028. var customObj = customObjectAccessor(node);
  1029. var extendObj = customObjectExtendAccessor(node);
  1030. if (customObj && state.nodeThreeObject === customObj) {
  1031. // clone object if it's a shared object among all nodes
  1032. customObj = customObj.clone();
  1033. }
  1034. var obj;
  1035. if (customObj && !extendObj) {
  1036. obj = customObj;
  1037. } else {
  1038. // Add default object (sphere mesh)
  1039. obj = new three$1.Mesh();
  1040. obj.__graphDefaultObj = true;
  1041. if (customObj && extendObj) {
  1042. obj.add(customObj); // extend default with custom
  1043. }
  1044. }
  1045. obj.__graphObjType = 'node'; // Add object type
  1046. return obj;
  1047. },
  1048. updateObj: function updateObj(obj, node) {
  1049. if (obj.__graphDefaultObj) {
  1050. // bypass internal updates for custom node objects
  1051. var val = valAccessor(node) || 1;
  1052. var radius = Math.cbrt(val) * state.nodeRelSize;
  1053. var numSegments = state.nodeResolution;
  1054. if (!obj.geometry.type.match(/^Sphere(Buffer)?Geometry$/) || obj.geometry.parameters.radius !== radius || obj.geometry.parameters.widthSegments !== numSegments) {
  1055. if (!sphereGeometries.hasOwnProperty(val)) {
  1056. sphereGeometries[val] = new three$1.SphereBufferGeometry(radius, numSegments, numSegments);
  1057. }
  1058. obj.geometry.dispose();
  1059. obj.geometry = sphereGeometries[val];
  1060. }
  1061. var color = colorAccessor(node);
  1062. var materialColor = new three$1.Color(colorStr2Hex(color || '#ffffaa'));
  1063. var opacity = state.nodeOpacity * colorAlpha(color);
  1064. if (obj.material.type !== 'MeshLambertMaterial' || !obj.material.color.equals(materialColor) || obj.material.opacity !== opacity) {
  1065. if (!sphereMaterials.hasOwnProperty(color)) {
  1066. sphereMaterials[color] = new three$1.MeshLambertMaterial({
  1067. color: materialColor,
  1068. transparent: true,
  1069. opacity: opacity
  1070. });
  1071. }
  1072. obj.material.dispose();
  1073. obj.material = sphereMaterials[color];
  1074. }
  1075. }
  1076. }
  1077. });
  1078. } // Digest links WebGL objects
  1079. if (state._flushObjects || hasAnyPropChanged(['graphData', 'linkThreeObject', 'linkThreeObjectExtend', 'linkMaterial', 'linkColor', 'linkWidth', 'linkVisibility', 'linkResolution', 'linkOpacity', 'linkDirectionalArrowLength', 'linkDirectionalArrowColor', 'linkDirectionalArrowResolution', 'linkDirectionalParticles', 'linkDirectionalParticleWidth', 'linkDirectionalParticleColor', 'linkDirectionalParticleResolution'])) {
  1080. var _customObjectAccessor = accessorFn__default['default'](state.linkThreeObject);
  1081. var _customObjectExtendAccessor = accessorFn__default['default'](state.linkThreeObjectExtend);
  1082. var customMaterialAccessor = accessorFn__default['default'](state.linkMaterial);
  1083. var _visibilityAccessor = accessorFn__default['default'](state.linkVisibility);
  1084. var _colorAccessor = accessorFn__default['default'](state.linkColor);
  1085. var widthAccessor = accessorFn__default['default'](state.linkWidth);
  1086. var cylinderGeometries = {}; // indexed by link width
  1087. var lambertLineMaterials = {}; // for cylinder objects, indexed by link color
  1088. var basicLineMaterials = {}; // for line objects, indexed by link color
  1089. var visibleLinks = state.graphData.links.filter(_visibilityAccessor); // lines digest cycle
  1090. threeDigest(visibleLinks, state.graphScene, {
  1091. objBindAttr: '__lineObj',
  1092. purge: state._flushObjects || hasAnyPropChanged([// recreate objects if any of these props have changed
  1093. 'linkThreeObject', 'linkThreeObjectExtend', 'linkWidth']),
  1094. objFilter: function objFilter(obj) {
  1095. return obj.__graphObjType === 'link';
  1096. },
  1097. createObj: function createObj(link) {
  1098. var customObj = _customObjectAccessor(link);
  1099. var extendObj = _customObjectExtendAccessor(link);
  1100. if (customObj && state.linkThreeObject === customObj) {
  1101. // clone object if it's a shared object among all links
  1102. customObj = customObj.clone();
  1103. }
  1104. var defaultObj;
  1105. if (!customObj || extendObj) {
  1106. // construct default line obj
  1107. var useCylinder = !!widthAccessor(link);
  1108. if (useCylinder) {
  1109. defaultObj = new three$1.Mesh();
  1110. } else {
  1111. // Use plain line (constant width)
  1112. var lineGeometry = new three$1.BufferGeometry();
  1113. lineGeometry[setAttributeFn]('position', new three$1.BufferAttribute(new Float32Array(2 * 3), 3));
  1114. defaultObj = new three$1.Line(lineGeometry);
  1115. }
  1116. }
  1117. var obj;
  1118. if (!customObj) {
  1119. obj = defaultObj;
  1120. obj.__graphDefaultObj = true;
  1121. } else {
  1122. if (!extendObj) {
  1123. // use custom object
  1124. obj = customObj;
  1125. } else {
  1126. // extend default with custom in a group
  1127. obj = new three$1.Group();
  1128. obj.__graphDefaultObj = true;
  1129. obj.add(defaultObj);
  1130. obj.add(customObj);
  1131. }
  1132. }
  1133. obj.renderOrder = 10; // Prevent visual glitches of dark lines on top of nodes by rendering them last
  1134. obj.__graphObjType = 'link'; // Add object type
  1135. return obj;
  1136. },
  1137. updateObj: function updateObj(updObj, link) {
  1138. if (updObj.__graphDefaultObj) {
  1139. // bypass internal updates for custom link objects
  1140. // select default object if it's an extended group
  1141. var obj = updObj.children.length ? updObj.children[0] : updObj;
  1142. var linkWidth = Math.ceil(widthAccessor(link) * 10) / 10;
  1143. var useCylinder = !!linkWidth;
  1144. if (useCylinder) {
  1145. var r = linkWidth / 2;
  1146. var numSegments = state.linkResolution;
  1147. if (!obj.geometry.type.match(/^Cylinder(Buffer)?Geometry$/) || obj.geometry.parameters.radiusTop !== r || obj.geometry.parameters.radialSegments !== numSegments) {
  1148. if (!cylinderGeometries.hasOwnProperty(linkWidth)) {
  1149. var geometry = new three$1.CylinderBufferGeometry(r, r, 1, numSegments, 1, false);
  1150. geometry[applyMatrix4Fn](new three$1.Matrix4().makeTranslation(0, 1 / 2, 0));
  1151. geometry[applyMatrix4Fn](new three$1.Matrix4().makeRotationX(Math.PI / 2));
  1152. cylinderGeometries[linkWidth] = geometry;
  1153. }
  1154. obj.geometry.dispose();
  1155. obj.geometry = cylinderGeometries[linkWidth];
  1156. }
  1157. }
  1158. var customMaterial = customMaterialAccessor(link);
  1159. if (customMaterial) {
  1160. obj.material = customMaterial;
  1161. } else {
  1162. var color = _colorAccessor(link);
  1163. var materialColor = new three$1.Color(colorStr2Hex(color || '#f0f0f0'));
  1164. var opacity = state.linkOpacity * colorAlpha(color);
  1165. var materialType = useCylinder ? 'MeshLambertMaterial' : 'LineBasicMaterial';
  1166. if (obj.material.type !== materialType || !obj.material.color.equals(materialColor) || obj.material.opacity !== opacity) {
  1167. var lineMaterials = useCylinder ? lambertLineMaterials : basicLineMaterials;
  1168. if (!lineMaterials.hasOwnProperty(color)) {
  1169. lineMaterials[color] = new three$1[materialType]({
  1170. color: materialColor,
  1171. transparent: opacity < 1,
  1172. opacity: opacity,
  1173. depthWrite: opacity >= 1 // Prevent transparency issues
  1174. });
  1175. }
  1176. obj.material.dispose();
  1177. obj.material = lineMaterials[color];
  1178. }
  1179. }
  1180. }
  1181. }
  1182. }); // Arrows digest cycle
  1183. if (state.linkDirectionalArrowLength || changedProps.hasOwnProperty('linkDirectionalArrowLength')) {
  1184. var arrowLengthAccessor = accessorFn__default['default'](state.linkDirectionalArrowLength);
  1185. var arrowColorAccessor = accessorFn__default['default'](state.linkDirectionalArrowColor);
  1186. threeDigest(visibleLinks.filter(arrowLengthAccessor), state.graphScene, {
  1187. objBindAttr: '__arrowObj',
  1188. objFilter: function objFilter(obj) {
  1189. return obj.__linkThreeObjType === 'arrow';
  1190. },
  1191. createObj: function createObj() {
  1192. var obj = new three$1.Mesh(undefined, new three$1.MeshLambertMaterial({
  1193. transparent: true
  1194. }));
  1195. obj.__linkThreeObjType = 'arrow'; // Add object type
  1196. return obj;
  1197. },
  1198. updateObj: function updateObj(obj, link) {
  1199. var arrowLength = arrowLengthAccessor(link);
  1200. var numSegments = state.linkDirectionalArrowResolution;
  1201. if (!obj.geometry.type.match(/^Cone(Buffer)?Geometry$/) || obj.geometry.parameters.height !== arrowLength || obj.geometry.parameters.radialSegments !== numSegments) {
  1202. var coneGeometry = new three$1.ConeBufferGeometry(arrowLength * 0.25, arrowLength, numSegments); // Correct orientation
  1203. coneGeometry.translate(0, arrowLength / 2, 0);
  1204. coneGeometry.rotateX(Math.PI / 2);
  1205. obj.geometry.dispose();
  1206. obj.geometry = coneGeometry;
  1207. }
  1208. obj.material.color = new three$1.Color(arrowColorAccessor(link) || _colorAccessor(link) || '#f0f0f0');
  1209. obj.material.opacity = state.linkOpacity * 3;
  1210. }
  1211. });
  1212. } // Photon particles digest cycle
  1213. if (state.linkDirectionalParticles || changedProps.hasOwnProperty('linkDirectionalParticles')) {
  1214. var particlesAccessor = accessorFn__default['default'](state.linkDirectionalParticles);
  1215. var particleWidthAccessor = accessorFn__default['default'](state.linkDirectionalParticleWidth);
  1216. var particleColorAccessor = accessorFn__default['default'](state.linkDirectionalParticleColor);
  1217. var particleMaterials = {}; // indexed by link color
  1218. var particleGeometries = {}; // indexed by particle width
  1219. threeDigest(visibleLinks.filter(particlesAccessor), state.graphScene, {
  1220. objBindAttr: '__photonsObj',
  1221. objFilter: function objFilter(obj) {
  1222. return obj.__linkThreeObjType === 'photons';
  1223. },
  1224. createObj: function createObj() {
  1225. var obj = new three$1.Group();
  1226. obj.__linkThreeObjType = 'photons'; // Add object type
  1227. return obj;
  1228. },
  1229. updateObj: function updateObj(obj, link) {
  1230. var numPhotons = Math.round(Math.abs(particlesAccessor(link)));
  1231. var curPhoton = !!obj.children.length && obj.children[0];
  1232. var photonR = Math.ceil(particleWidthAccessor(link) * 10) / 10 / 2;
  1233. var numSegments = state.linkDirectionalParticleResolution;
  1234. var particleGeometry;
  1235. if (curPhoton && curPhoton.geometry.parameters.radius === photonR && curPhoton.geometry.parameters.widthSegments === numSegments) {
  1236. particleGeometry = curPhoton.geometry;
  1237. } else {
  1238. if (!particleGeometries.hasOwnProperty(photonR)) {
  1239. particleGeometries[photonR] = new three$1.SphereBufferGeometry(photonR, numSegments, numSegments);
  1240. }
  1241. particleGeometry = particleGeometries[photonR];
  1242. curPhoton && curPhoton.geometry.dispose();
  1243. }
  1244. var photonColor = particleColorAccessor(link) || _colorAccessor(link) || '#f0f0f0';
  1245. var materialColor = new three$1.Color(colorStr2Hex(photonColor));
  1246. var opacity = state.linkOpacity * 3;
  1247. var particleMaterial;
  1248. if (curPhoton && curPhoton.material.color.equals(materialColor) && curPhoton.material.opacity === opacity) {
  1249. particleMaterial = curPhoton.material;
  1250. } else {
  1251. if (!particleMaterials.hasOwnProperty(photonColor)) {
  1252. particleMaterials[photonColor] = new three$1.MeshLambertMaterial({
  1253. color: materialColor,
  1254. transparent: true,
  1255. opacity: opacity
  1256. });
  1257. }
  1258. particleMaterial = particleMaterials[photonColor];
  1259. curPhoton && curPhoton.material.dispose();
  1260. } // digest cycle for each photon
  1261. threeDigest(_toConsumableArray(new Array(numPhotons)).map(function (_, idx) {
  1262. return {
  1263. idx: idx
  1264. };
  1265. }), obj, {
  1266. idAccessor: function idAccessor(d) {
  1267. return d.idx;
  1268. },
  1269. createObj: function createObj() {
  1270. return new three$1.Mesh(particleGeometry, particleMaterial);
  1271. },
  1272. updateObj: function updateObj(obj) {
  1273. obj.geometry = particleGeometry;
  1274. obj.material = particleMaterial;
  1275. }
  1276. });
  1277. }
  1278. });
  1279. }
  1280. }
  1281. state._flushObjects = false; // reset objects refresh flag
  1282. // simulation engine
  1283. if (hasAnyPropChanged(['graphData', 'nodeId', 'linkSource', 'linkTarget', 'numDimensions', 'forceEngine', 'dagMode', 'dagNodeFilter', 'dagLevelDistance'])) {
  1284. state.engineRunning = false; // Pause simulation
  1285. // parse links
  1286. state.graphData.links.forEach(function (link) {
  1287. link.source = link[state.linkSource];
  1288. link.target = link[state.linkTarget];
  1289. }); // Feed data to force-directed layout
  1290. var isD3Sim = state.forceEngine !== 'ngraph';
  1291. var layout;
  1292. if (isD3Sim) {
  1293. // D3-force
  1294. (layout = state.d3ForceLayout).stop().alpha(1) // re-heat the simulation
  1295. .numDimensions(state.numDimensions).nodes(state.graphData.nodes); // add links (if link force is still active)
  1296. var linkForce = state.d3ForceLayout.force('link');
  1297. if (linkForce) {
  1298. linkForce.id(function (d) {
  1299. return d[state.nodeId];
  1300. }).links(state.graphData.links);
  1301. } // setup dag force constraints
  1302. var nodeDepths = state.dagMode && getDagDepths(state.graphData, function (node) {
  1303. return node[state.nodeId];
  1304. }, {
  1305. nodeFilter: state.dagNodeFilter,
  1306. onLoopError: state.onDagError || undefined
  1307. });
  1308. var maxDepth = Math.max.apply(Math, _toConsumableArray(Object.values(nodeDepths || [])));
  1309. var dagLevelDistance = state.dagLevelDistance || state.graphData.nodes.length / (maxDepth || 1) * DAG_LEVEL_NODE_RATIO * (['radialin', 'radialout'].indexOf(state.dagMode) !== -1 ? 0.7 : 1); // Fix nodes to x,y,z for dag mode
  1310. if (state.dagMode) {
  1311. var getFFn = function getFFn(fix, invert) {
  1312. return function (node) {
  1313. return !fix ? undefined : (nodeDepths[node[state.nodeId]] - maxDepth / 2) * dagLevelDistance * (invert ? -1 : 1);
  1314. };
  1315. };
  1316. var fxFn = getFFn(['lr', 'rl'].indexOf(state.dagMode) !== -1, state.dagMode === 'rl');
  1317. var fyFn = getFFn(['td', 'bu'].indexOf(state.dagMode) !== -1, state.dagMode === 'td');
  1318. var fzFn = getFFn(['zin', 'zout'].indexOf(state.dagMode) !== -1, state.dagMode === 'zout');
  1319. state.graphData.nodes.filter(state.dagNodeFilter).forEach(function (node) {
  1320. node.fx = fxFn(node);
  1321. node.fy = fyFn(node);
  1322. node.fz = fzFn(node);
  1323. });
  1324. } // Use radial force for radial dags
  1325. state.d3ForceLayout.force('dagRadial', ['radialin', 'radialout'].indexOf(state.dagMode) !== -1 ? d3Force3d.forceRadial(function (node) {
  1326. var nodeDepth = nodeDepths[node[state.nodeId]] || -1;
  1327. return (state.dagMode === 'radialin' ? maxDepth - nodeDepth : nodeDepth) * dagLevelDistance;
  1328. }).strength(function (node) {
  1329. return state.dagNodeFilter(node) ? 1 : 0;
  1330. }) : null);
  1331. } else {
  1332. // ngraph
  1333. var _graph = ngraph.graph();
  1334. state.graphData.nodes.forEach(function (node) {
  1335. _graph.addNode(node[state.nodeId]);
  1336. });
  1337. state.graphData.links.forEach(function (link) {
  1338. _graph.addLink(link.source, link.target);
  1339. });
  1340. layout = ngraph.forcelayout(_graph, _objectSpread2({
  1341. dimensions: state.numDimensions
  1342. }, state.ngraphPhysics));
  1343. layout.graph = _graph; // Attach graph reference to layout
  1344. }
  1345. for (var i = 0; i < state.warmupTicks && !(isD3Sim && state.d3AlphaMin > 0 && state.d3ForceLayout.alpha() < state.d3AlphaMin); i++) {
  1346. layout[isD3Sim ? "tick" : "step"]();
  1347. } // Initial ticks before starting to render
  1348. state.layout = layout;
  1349. this.resetCountdown();
  1350. }
  1351. state.engineRunning = true; // resume simulation
  1352. state.onFinishUpdate();
  1353. }
  1354. });
  1355. function fromKapsule (kapsule) {
  1356. var baseClass = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Object;
  1357. var initKapsuleWithSelf = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  1358. var FromKapsule = /*#__PURE__*/function (_baseClass) {
  1359. _inherits(FromKapsule, _baseClass);
  1360. var _super = _createSuper(FromKapsule);
  1361. function FromKapsule() {
  1362. var _this;
  1363. _classCallCheck(this, FromKapsule);
  1364. for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
  1365. args[_key] = arguments[_key];
  1366. }
  1367. _this = _super.call.apply(_super, [this].concat(args));
  1368. _this.__kapsuleInstance = kapsule().apply(void 0, [].concat(_toConsumableArray(initKapsuleWithSelf ? [_assertThisInitialized(_this)] : []), args));
  1369. return _this;
  1370. }
  1371. return FromKapsule;
  1372. }(baseClass); // attach kapsule props/methods to class prototype
  1373. Object.keys(kapsule()).forEach(function (m) {
  1374. return FromKapsule.prototype[m] = function () {
  1375. var _this$__kapsuleInstan;
  1376. var returnVal = (_this$__kapsuleInstan = this.__kapsuleInstance)[m].apply(_this$__kapsuleInstan, arguments);
  1377. return returnVal === this.__kapsuleInstance ? this // chain based on this class, not the kapsule obj
  1378. : returnVal;
  1379. };
  1380. });
  1381. return FromKapsule;
  1382. }
  1383. var three = window.THREE ? window.THREE : {
  1384. Group: three$2.Group
  1385. }; // Prefer consumption from global THREE, if exists
  1386. var threeForcegraph = fromKapsule(ForceGraph, three.Group, true);
  1387. module.exports = threeForcegraph;