three-forcegraph.module.js 56 KB

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