BiAuditGraph.php.network-graph.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. var DBG = DBG || false;
  2. var DBG1 = true;
  3. var DBG_INIT_SELECTED = []; // [ "BI_audit_ENERGA_RUM_KONTRAHENCI.18661", "BI_audit_KRS.389967" ];
  4. if ('undefined' === typeof HTML_ID_REF_GRAPH) throw "Missing HTML_ID_REF_GRAPH";
  5. if (!RAPORT_ID) throw "Missing RAPORT_ID";
  6. if (!API_URL) throw "Missing API_URL";
  7. if (!global.p5VendorJs) throw "Missing p5VendorJs";
  8. if (!global.vis) throw "Missing vis";
  9. if (!global.p5VendorJs.Typeahead) throw "Missing Typeahead";
  10. var createReactClass = global.p5VendorJs.createReactClass;
  11. var h = global.p5VendorJs.React.createElement;
  12. var React = global.p5VendorJs.React;
  13. var ReactDOM = global.p5VendorJs.ReactDOM;
  14. var Redux = global.p5VendorJs.Redux;
  15. var ReduxThunk = global.p5VendorJs.ReduxThunk;
  16. var createStoreWithThunkMiddleware = Redux.applyMiddleware(ReduxThunk)(Redux.createStore); // TODO: to vendor.js
  17. var Typeahead = global.p5VendorJs.Typeahead;
  18. var mapStatsNodeToGraphNode = function (node) {
  19. return {
  20. id: node['@object'] + '.' + node['@primaryKey'],
  21. label: Utils.nodeLabelShort(node['@label']),
  22. color: Utils.nodeColorByObject(node['@object']),
  23. rawLabel: node['@label'],
  24. value: 1,
  25. level: 0,
  26. }
  27. };
  28. var mapStatsEdgeToGraphEdge = function (edge) {
  29. return {
  30. id: Utils.makeUniqueEdgeId(edge['source'], edge['target']),
  31. from: edge['source'],
  32. to: edge['target'],
  33. pathId: edge['pathId'],
  34. listPathId: [ edge['pathId'] ],
  35. }
  36. };
  37. //// DBG: Utils:
  38. // var from, to;
  39. // from = 'aa.11'; to = 'bb.22'; console.log('DBG: Utils.makeUniqueEdgeId('+from+', '+to+')', Utils.makeUniqueEdgeId(from, to), { cache: Utils.getCacheAllEdgeId().join(',') })
  40. // from = 'bb.22'; to = 'aa.11'; console.log('DBG: Utils.makeUniqueEdgeId('+from+', '+to+')', Utils.makeUniqueEdgeId(from, to), { cache: Utils.getCacheAllEdgeId().join(',') })
  41. // from = 'cc.22'; to = 'cc.11'; console.log('DBG: Utils.makeUniqueEdgeId('+from+', '+to+')', Utils.makeUniqueEdgeId(from, to), { cache: Utils.getCacheAllEdgeId().join(',') })
  42. var Utils = (function __makeUtils() {
  43. var Utils = {};
  44. var _cacheListFeatureNames = [];
  45. Utils.fidSplit = function (fid) {
  46. var dotPos = fid.indexOf('.');
  47. return [ fid.substr(0, dotPos), fid.substr(dotPos + 1) ];
  48. }
  49. Utils.makeUniqueEdgeId = function (from, to) {
  50. var listFidArr = [ from, to ].sort().map(Utils.fidSplit);
  51. var listIdx = listFidArr.map(function (fidArr) {
  52. var cacheIdx = _cacheListFeatureNames.indexOf(fidArr[0]);
  53. if (-1 === cacheIdx) {
  54. cacheIdx = _cacheListFeatureNames.length;
  55. _cacheListFeatureNames.push(fidArr[0]);
  56. }
  57. return cacheIdx;
  58. })
  59. return listIdx.map(function (cacheIdx, fidIdx) {
  60. return cacheIdx + '.' + listFidArr[fidIdx][1];
  61. }).join('-')
  62. }
  63. Utils.getCacheAllEdgeId = function () {
  64. return [].concat(_cacheListFeatureNames);
  65. }
  66. Utils.nodeLabelShort = function (label) {
  67. return label.replace('SPÓŁKA Z OGRANICZONĄ ODPOWIEDZIALNOŚCIĄ', 'Sp. z o.o.')
  68. }
  69. Utils.bsColors = {
  70. 'base': "#777",
  71. 'blue': "#337ab7",
  72. 'green': "#5cb85c",
  73. 'lightblue': "#5bc0de",
  74. 'orange': "#f0ad4e",
  75. 'red': "#d9534f",
  76. };
  77. Utils.bsLightColors = {
  78. 'base': "#f5f5f5",
  79. 'blue': "#d9edf7",
  80. 'green': "#dff0d8",
  81. 'lightblue': "#d9edf7",
  82. 'orange': "#fcf8e3",
  83. 'red': "#f2dede",
  84. };
  85. Utils.colors = {
  86. person: Utils.bsLightColors['orange'],
  87. company: Utils.bsLightColors['red'],
  88. location: Utils.bsLightColors['base'],
  89. };
  90. Utils.nodeColorByObject = function (objectName) {
  91. switch (objectName) {
  92. case 'BI_audit_KRS_person': return Utils.colors['person'];
  93. case 'BI_audit_MSIG_person': return Utils.colors['person'];
  94. case 'BI_audit_MSIG': return Utils.colors['company'];
  95. case 'BI_audit_KRS': return Utils.colors['company'];
  96. case 'BI_audit_ENERGA_RUM_KONTRAHENCI': return Utils.colors['company'];
  97. case 'TERYT_adresy': return Utils.colors['location'];
  98. case 'BI_audit_MSIG_address': return Utils.colors['location'];
  99. case 'BI_audit_KRS_company': return Utils.colors['company'];
  100. case 'BI_audit_MSIG_company': return Utils.colors['company'];
  101. case 'BI_audit_CEIDG': return Utils.colors['company'];
  102. default: return '#666';
  103. }
  104. }
  105. return Utils;
  106. })();
  107. { // TODO: RaportOutputPanel ?
  108. var RaportOutputPanel = {};
  109. RaportOutputPanel.initialState = function () {
  110. var nodes = (STATS && STATS.nodes) ? STATS.nodes : [];
  111. var edges = (STATS && STATS.edges) ? STATS.edges : [];
  112. var paths = (STATS && STATS.path_list) ? STATS.path_list : [];
  113. DBG && console.log('DBG: STATS', STATS);
  114. return {
  115. nodes: nodes.map(mapStatsNodeToGraphNode),
  116. edges: edges.map(mapStatsEdgeToGraphEdge),
  117. paths: paths,
  118. isLoading: false,
  119. sentRequestId: 0,
  120. receivedRequestId: 0,
  121. }
  122. };
  123. RaportOutputPanel.store = function (state, action) {
  124. var prevState = state || RaportOutputPanel.initialState();
  125. DBG && console.log('DBG: store', { prevState, action, actionType: action.type });
  126. switch (action.type) {
  127. case 'SET_SENT_REQUEST_ID': return Object.assign(prevState, {
  128. sentRequestId: action.sentRequestId,
  129. isLoading: true
  130. });
  131. case 'SET_RESPONSE': return Object.assign(prevState, {
  132. receivedRequestId: action.requestId,
  133. nodes: action.body.nodes.map(mapStatsNodeToGraphNode),
  134. edges: action.body.edges,
  135. isLoading: (prevState.sentRequestId > action.requestId) ? true : false,
  136. });
  137. default: return prevState;
  138. }
  139. };
  140. RaportOutputPanel.createActions = function () {
  141. var setSentRequestId = function (sentRequestId) {
  142. return { type: 'SET_SENT_REQUEST_ID', sentRequestId: sentRequestId };
  143. }
  144. var setResponse = function (response) {
  145. return Object.assign(response, { type: 'SET_RESPONSE' });
  146. }
  147. var fetchData = function (raportId, params) {
  148. return function (dispatch, getState) {
  149. var state = getState();
  150. var this__requestId = state.sentRequestId + 1;
  151. dispatch(setSentRequestId(this__requestId));
  152. var reqPromise = window.fetch(API_URL, {
  153. method: 'GET',
  154. credentials: 'same-origin',
  155. }).then(function (response) {
  156. return response.json();
  157. });
  158. return reqPromise.then(function (response) {
  159. var items = response;
  160. var state = getState();
  161. if (state.receivedRequestId > this__requestId) {
  162. DBG && console.log('DBG: skipped response', { 'state.receivedRequestId': state.receivedRequestId, this__requestId });
  163. return;
  164. }
  165. dispatch(
  166. setResponse({
  167. requestId: this__requestId,
  168. msg: "Pobrano dane",
  169. body: response.body
  170. })
  171. );
  172. }).catch(function (e) {
  173. p5UI__notifyAjaxCallback({type: 'error', msg: 'Wystąpił błąd #GS1: ' + e});
  174. // dispatch( setErrorMsg(e) ); // TODO: show error with msg and refresh button
  175. });
  176. }
  177. }
  178. return {
  179. fetchData: fetchData,
  180. }
  181. };
  182. }
  183. { // TODO: NetworkGraph - mv to another file
  184. var NetworkGraph = {};
  185. NetworkGraph.initialState = function () {
  186. var nodes = (STATS && STATS.nodes) ? STATS.nodes : [];
  187. var edges = (STATS && STATS.edges) ? STATS.edges : [];
  188. var paths = (STATS && STATS.path_list) ? STATS.path_list : [];
  189. DBG && console.log('DBG: STATS', STATS);
  190. var allNodesSet = new vis.DataSet();
  191. allNodesSet.update( nodes.map(mapStatsNodeToGraphNode) );
  192. var allEdgesSet = new vis.DataSet();
  193. allEdgesSet.update( edges.map(mapStatsEdgeToGraphEdge) );
  194. var visibleNodesSet = new vis.DataSet();
  195. var selectedNodeIds = [];
  196. return {
  197. allNodesSet: allNodesSet,
  198. allEdgesSet: allEdgesSet,
  199. visibleNodesSet: visibleNodesSet,
  200. nodes: nodes.map(mapStatsNodeToGraphNode), // TODO: RMME
  201. edges: edges.map(mapStatsEdgeToGraphEdge),
  202. paths: paths,
  203. isLoading: false,
  204. sentRequestId: 0,
  205. receivedRequestId: 0,
  206. }
  207. };
  208. NetworkGraph.store = function (state, action) {
  209. var prevState = state || NetworkGraph.initialState();
  210. DBG && console.log('DBG: store', { prevState, action, actionType: action.type });
  211. switch (action.type) {
  212. case 'SET_SENT_REQUEST_ID': return Object.assign(prevState, {
  213. sentRequestId: action.sentRequestId,
  214. isLoading: true
  215. });
  216. case 'SET_RESPONSE': return Object.assign(prevState, {
  217. receivedRequestId: action.requestId,
  218. nodes: action.body.nodes.map(mapStatsNodeToGraphNode),
  219. edges: action.body.edges,
  220. isLoading: (prevState.sentRequestId > action.requestId) ? true : false,
  221. });
  222. case 'SET_SELECTED': {
  223. // TODO: mv from updateSelected
  224. var selected = action.selected || [];
  225. var idsSelected = selected.map( function (node) { return node.id } )
  226. DBG && console.log('DBG:NetworkGraph.SET_SELECTED ', { idsSelected, selected })
  227. var foundPaths = prevState.paths.filter(function (path) {
  228. for (var i = 0, totalFids = path.fids.length, fid = null; i < totalFids; i++) {
  229. fid = path.fids[i];
  230. DBG && console.log('DBG:foundPaths ', {fid: ''+fid, path});
  231. if ( -1 !== idsSelected.indexOf(fid) ) return true;
  232. }
  233. return false;
  234. })
  235. var addFidsToGraph = Array.from(new Set(foundPaths.reduce(function (ret, path) {
  236. return ret.concat(path.fids.filter(function (fid) {
  237. return ( -1 === idsSelected.indexOf(fid) );
  238. }))
  239. }, [])));
  240. function markColorSelected(node) {
  241. return Object.assign(node, { color: '#95c1fe' });
  242. }
  243. prevState.visibleNodesSet.clear();
  244. prevState.visibleNodesSet.add(selected.map(markColorSelected));
  245. addFidsToGraph.forEach(function (fid) {
  246. var node = prevState.allNodesSet.get(fid)
  247. prevState.visibleNodesSet.update(node);
  248. })
  249. DBG && console.log('DBG:NetworkGraph.SET_SELECTED new state ', { state: Object.assign(prevState, { selected: selected }) })
  250. return Object.assign(prevState, { selected: selected });
  251. }
  252. case 'TEST_ADD_DATA': {
  253. if (action.nodes) {
  254. action.nodes.forEach(function (node) {
  255. prevState.allNodesSet.update(node);
  256. prevState.visibleNodesSet.update(node);
  257. })
  258. }
  259. if (action.edges) {
  260. action.edges.forEach(function (edge) {
  261. prevState.allEdgesSet.update(edge);
  262. })
  263. }
  264. DBG && console.log('DBG:NetworkGraph.TEST_ADD_DATA new state ', { state: Object.assign(prevState, {}) })
  265. return Object.assign(prevState, {})
  266. }
  267. case 'RELOAD_NODES': {
  268. var nodes = prevState.visibleNodesSet.map(function(e) { return e; }); // DataSet to Array
  269. prevState.visibleNodesSet.clear();
  270. var animAddNodes = (function (this__nodes, nodes, wait) {
  271. return function (callback) {
  272. DBG && console.log('DBG:animAddNodes', { nodes });
  273. if (nodes.length > 0) {
  274. var node = nodes.pop();
  275. this__nodes.add(node);
  276. setTimeout(function () {
  277. animAddNodes(callback)
  278. }, wait);
  279. }
  280. }
  281. })(prevState.visibleNodesSet, nodes, 200);
  282. animAddNodes(animAddNodes);
  283. }
  284. default: return prevState;
  285. }
  286. };
  287. NetworkGraph.createActions = function () {
  288. var setSentRequestId = function (sentRequestId) {
  289. return { type: 'SET_SENT_REQUEST_ID', sentRequestId: sentRequestId };
  290. }
  291. var setResponse = function (response) {
  292. return Object.assign(response, { type: 'SET_RESPONSE' });
  293. }
  294. var fetchData = function (raportId, params) {
  295. return function (dispatch, getState) {
  296. var state = getState();
  297. var this__requestId = state.sentRequestId + 1;
  298. dispatch(setSentRequestId(this__requestId));
  299. var reqPromise = window.fetch(API_URL, {
  300. method: 'GET',
  301. credentials: 'same-origin',
  302. }).then(function (response) {
  303. return response.json();
  304. });
  305. return reqPromise.then(function (response) {
  306. var items = response;
  307. var state = getState();
  308. if (state.receivedRequestId > this__requestId) {
  309. DBG && console.log('DBG: skipped response', { 'state.receivedRequestId': state.receivedRequestId, this__requestId });
  310. return;
  311. }
  312. dispatch(
  313. setResponse({
  314. requestId: this__requestId,
  315. msg: "Pobrano dane",
  316. body: response.body
  317. })
  318. );
  319. }).catch(function (e) {
  320. p5UI__notifyAjaxCallback({type: 'error', msg: 'Wystąpił błąd #GS1: ' + e});
  321. // dispatch( setErrorMsg(e) ); // TODO: show error with msg and refresh button
  322. });
  323. }
  324. }
  325. var setSelected = function (selected) {
  326. return { type: 'SET_SELECTED', selected: selected };
  327. }
  328. return {
  329. fetchData: fetchData,
  330. setSelected: setSelected,
  331. }
  332. };
  333. }
  334. var defaultNetworkGraphOptions = {
  335. nodes: {
  336. shape: 'dot',
  337. scaling: {
  338. min: 8, max: 30,
  339. label: {
  340. min: 8, max: 16, drawThreshold: 6, maxVisible: 20
  341. }
  342. },
  343. font: { color: "#666", size: 10, face: 'Helvetica Neue, Helvetica, Arial' }
  344. // font: "8px Helvetica Neue, Helvetica, Arial"
  345. },
  346. interaction: {
  347. hover: true,
  348. hoverConnectedEdges: false,
  349. selectConnectedEdges: true,
  350. },
  351. physics: {
  352. barnesHut: {
  353. avoidOverlap: 0.2
  354. }
  355. },
  356. };
  357. var TMP_COUNTER = 1;
  358. var p5UI__NetworkGraph = createReactClass({
  359. _network: null,
  360. _visOutputRef: React.createRef(),
  361. _allNodes: null, // new vis.DataSet(),
  362. _allEdges: null, // new vis.DataSet(),
  363. _nodes: new vis.DataSet(),
  364. _edges: new vis.DataSet(),
  365. getStateFromStore: function () {
  366. var state = this.props.store.getState();
  367. return {
  368. visibleNodesSet: state.visibleNodesSet,
  369. allEdgesSet: state.allEdgesSet,
  370. isLoading: state.isLoading,
  371. receivedRequestId: state.receivedRequestId, // to force render after udpate nodes, edges
  372. }
  373. },
  374. getInitialState: function () {
  375. // if (this.props.selected) this._updateSelected(this.props.selected);
  376. return Object.assign({
  377. initialized: false,
  378. isLoading: false,
  379. receivedRequestId: null,
  380. }, this.getStateFromStore());
  381. },
  382. setOutputRef: function (elem) {
  383. this._visOutputRef = elem;
  384. },
  385. componentDidMount: function () {
  386. // var data = { nodes: this._nodes, edges: this._edges };
  387. var data = { nodes: this.state.visibleNodesSet, edges: this.state.allEdgesSet };
  388. DBG && console.log('DBG:componentDidMount data', { data });
  389. this._network = new vis.Network(this._visOutputRef, data, defaultNetworkGraphOptions);
  390. if (this.props.onZoom) this._network.on('zoom', this.props.onZoom)
  391. this.setState({ initialized: true });
  392. this._unsubscribe = this.props.store.subscribe(this._storeUpdated)
  393. },
  394. _storeUpdated: function () {
  395. this.setState( this.getStateFromStore() )
  396. },
  397. fitToContainer: function () {
  398. if (this._network) {
  399. this._network.fit()
  400. }
  401. },
  402. incScale: function () {
  403. if (this._network) {
  404. var scale = this._network.getScale();
  405. this._network.moveTo({
  406. scale: scale + 0.2
  407. })
  408. }
  409. },
  410. decScale: function () {
  411. if (this._network) {
  412. var scale = this._network.getScale();
  413. this._network.moveTo({
  414. scale: (scale > 0.3) ? scale - 0.2 : scale
  415. })
  416. }
  417. },
  418. reloadGraph: function () {
  419. this.props.store.dispatch({ type: 'RELOAD_NODES' })
  420. return;
  421. if (this._network) {
  422. // this._network.setData({ nodes: [], edges: [] });
  423. // var edges = this._edges.getDataSet();
  424. var networkFit = (function (network) {
  425. var _network = network;
  426. return function () {
  427. DBG && console.log('DBG:networkFit');
  428. _network.fit();
  429. }
  430. })(this._network);
  431. // {
  432. // var edges = this._edges.map(function(e) { return e; }); // DataSet to Array
  433. // this._edges.clear();
  434. // var animAddEdges = (function (this__edges, edges, wait) {
  435. // return function (callback) {
  436. // DBG && console.log('DBG:animAddEdges', { edges });
  437. // if (edges.length > 0) {
  438. // var edge = edges.pop();
  439. // this__edges.add(edge);
  440. // setTimeout(function () {
  441. // animAddEdges(callback)
  442. // }, wait);
  443. // }
  444. // }
  445. // })(this._edges, edges, 10);
  446. // animAddEdges(animAddEdges);
  447. // }
  448. {
  449. var nodes = this._nodes.map(function(e) { return e; }); // DataSet to Array
  450. this._nodes.clear();
  451. var animAddNodes = (function (this__nodes, nodes, wait, onFinishCallback) {
  452. return function (callback) {
  453. DBG && console.log('DBG:animAddNodes', { nodes });
  454. if (nodes.length > 0) {
  455. var node = nodes.pop();
  456. this__nodes.add(node);
  457. setTimeout(function () {
  458. animAddNodes(callback)
  459. }, wait);
  460. } else if (onFinishCallback) {
  461. setTimeout(function () {
  462. onFinishCallback()
  463. }, 500);
  464. }
  465. }
  466. })(this._nodes, nodes, 200, networkFit);
  467. animAddNodes(animAddNodes);
  468. }
  469. // DBG && console.log('DBG: reloadGraph', { 'this._nodes': this._nodes, 'this._edges': this._edges, edges: edges });
  470. // this._network.setData({ nodes: this._nodes, edges: this._edges });
  471. // this._network.fit() // zoom out to fit container size
  472. }
  473. },
  474. testOnClick1: function () {
  475. TMP_COUNTER++;
  476. this._nodes.add({ id: TMP_COUNTER, label: "Node " + TMP_COUNTER, value: TMP_COUNTER, level: 0 });
  477. },
  478. testOnClick2: function () {
  479. TMP_COUNTER++;
  480. var ids = this._nodes.getIds();
  481. var totalNodes = ids.length
  482. if (totalNodes < 3) return;
  483. var fromIdx = Math.floor(Math.random() * totalNodes);
  484. var toIdx = Math.floor(Math.random() * totalNodes);
  485. this._edges.add({ from: ids[fromIdx], to: ids[toIdx] });
  486. },
  487. testOnClick3: function () {
  488. this.props.store.dispatch( this.props.storeActions.fetchData( this.props.raportId ) );
  489. },
  490. testOnClick4: function () {
  491. DBG && console.log('DBG:Utils cache ', { cache: Utils.getCacheAllEdgeId() })
  492. },
  493. testOnClick5: function () {
  494. var edges = [];
  495. var nodes = [ { id: 'TERYT_adresy.123', label: "TER.123" }, { id: 'TERYT_adresy.666', label: "TER.666" } ];
  496. DBG && console.log('DBG:testOnClick5 add custom node + edges ', { nodes: nodes, edges: edges })
  497. this.props.store.dispatch({ type: 'TEST_ADD_DATA', nodes: nodes, edges: edges })
  498. },
  499. shouldComponentUpdate: function (nextProps, nextState) {
  500. // if (this.state.receivedRequestId !== nextState.receivedRequestId) { // add missing nodes
  501. // var state = this.props.store.getState();
  502. // DBG && console.warn("TODO: update nodes, edges", { state });
  503. // // this._edges.add( edge_or_edges_array )
  504. // if (state.nodes && state.nodes.length) {
  505. // var __nodes = this._nodes;
  506. // state.nodes.forEach(function (node) {
  507. // __nodes.add(node);
  508. // })
  509. // }
  510. // // edge: { from: page, to: subpageID, color:getEdgeColor(level), level: level, selectionWidth:2, hoverWidth:0 }
  511. // if (state.edges && state.edges.length) {
  512. // var __edges = this._edges;
  513. // // state.edges.forEach(function (edge) {
  514. // state.edges.slice(0, 30).forEach(function (edge) {
  515. // __edges.add({
  516. // from: edge.source,
  517. // to: edge.target,
  518. // });
  519. // })
  520. // }
  521. // }
  522. if (this.props.selected.length != nextProps.selected.length) {
  523. // this._updateSelected(nextProps.selected)
  524. }
  525. return false;
  526. },
  527. _updateSelected: function (selected) { // TODO: move to RaportOutputPanel Store
  528. var state = this.props.store.getState();
  529. var idsSelected = (selected || []).map( function (node) { return node.id } )
  530. var nodes = [];
  531. // var edges = state.edges.filter(function (edge) { // use idsSelected - TODO: RMME
  532. // return ( -1 !== idsSelected.indexOf(edge.source) || -1 !== idsSelected.indexOf(edge.target) );
  533. // })
  534. {
  535. // TODO: find all paths with selected fids
  536. var foundPaths = state.paths.filter(function (path) {
  537. for (var i = 0, totalFids = path.fids.length, fid = null; i < totalFids; i++) {
  538. fid = path.fids[i];
  539. DBG && console.log('DBG:foundPaths ', {fid: ''+fid, path});
  540. if ( -1 !== idsSelected.indexOf(fid) ) return true;
  541. }
  542. return false;
  543. })
  544. // TODO: add missing nodes (not selected but on path)
  545. var addFidsToGraph = Array.from(new Set(foundPaths.reduce(function (ret, path) {
  546. return ret.concat(path.fids.filter(function (fid) {
  547. return ( -1 === idsSelected.indexOf(fid) );
  548. }))
  549. }, [])));
  550. // TODO: view only combined path or all not selected nodes? - trying: not selected nodes
  551. // TODO: convert found paths to graph edges
  552. }
  553. DBG && console.warn('DBG: TODO set edges by selectd nodes...', { state_nodes: state.nodes, state_edges: state.edges, idsSelected, foundPaths, addFidsToGraph });
  554. // this._nodes = new vis.DataSet();
  555. { // TODO: convert fid to node on found list
  556. { // if (!this._allNodes) {
  557. this._allNodes = new vis.DataSet();
  558. this._allNodes.update(state.nodes);
  559. }
  560. var this__allNodes = this._allNodes;
  561. var this__nodes = this._nodes;
  562. addFidsToGraph.forEach(function (fid) {
  563. var node = this__allNodes.get(fid)
  564. this__nodes.update(node);
  565. })
  566. }
  567. DBG && console.log('DBG: check edges: ', { 'this._edges.length': this._edges.length, 'state.edges.length': state.edges.length });
  568. if (this._edges.length != state.edges.length) {
  569. DBG && console.log('DBG: TODO: update edges', { 'state.edges': state.edges });
  570. var this__edges = this._edges;
  571. state.edges.forEach(function (edge) {
  572. var foundEdge = this__edges.get(edge.id);
  573. if (!foundEdge) {
  574. this__edges.add(edge);
  575. } else {
  576. var listPathId = (-1 !== foundEdge.listPathId.indexOf(edge.pathId)) ? foundEdge.listPathId : foundEdge.listPathId.concat(edge.pathId);
  577. var mergedEdge = Object.assign(foundEdge, {
  578. listPathId: listPathId,
  579. width: 1 + (listPathId.length - 1) / 10,
  580. });
  581. this__edges.update(mergedEdge);
  582. }
  583. })
  584. }
  585. if (this._network) {
  586. // this._network.setData({ nodes: this._nodes, edges: this._edges });
  587. // this._network.fit() // zoom to fit container size
  588. }
  589. },
  590. render: function () {
  591. return h('div', { style: { 'position': "relative" } }, [
  592. h('div', {
  593. ref: this.setOutputRef,
  594. style: {
  595. 'min-height': 600,
  596. 'height': 600,
  597. 'border-radius': "6px",
  598. 'border': "1px solid #ddd",
  599. },
  600. }),
  601. h('div', { className: "", style: { position: "absolute", right: 10, top: 10 } }, [
  602. h('div', { className: "btn-group-vertical", title: "Powiększenie" }, [
  603. h('button', { onClick: this.incScale, className: "btn btn-xs btn-default" }, [ h('i', { className: "glyphicon glyphicon-plus" }) ]),
  604. h('button', { onClick: this.fitToContainer, className: "btn btn-xs btn-default" }, [ "100%" ]),
  605. h('button', { onClick: this.decScale, className: "btn btn-xs btn-default" }, [ h('i', { className: "glyphicon glyphicon-minus" }) ]),
  606. ]),
  607. h('div', { style: { clear: "both", margin: 4 } }),
  608. h('div', { className: "btn-group-vertical", style: { width: "100%" } }, [
  609. h('button', { onClick: this.reloadGraph, className: "btn btn-xs btn-default", title: "Odśwież" }, [ h('i', { className: "glyphicon glyphicon-random" }) ]),
  610. ]),
  611. ]),
  612. // h('div', {}, [
  613. // h('button', { onClick: this.testOnClick1 }, [ "TEST 1 ", h('small', [], "(+ node)") ]),
  614. // h('button', { onClick: this.testOnClick2 }, [ "TEST 2 ", h('small', [], "(+ edge)") ]),
  615. // h('button', { onClick: this.testOnClick3 }, [ "TEST 3 ", h('small', [], "(+ fetch)") ]),
  616. // h('button', { onClick: this.testOnClick4 }, [ "TEST 4 ", h('small', [], "(+ log Utils.cache)") ]),
  617. // h('button', { onClick: this.testOnClick5 }, [ "TEST 5 ", h('small', [], "(+ data)") ]),
  618. // ]),
  619. ]);
  620. }
  621. });
  622. /**
  623. * props.store: networkGraphStore
  624. * - used: state.nodes
  625. */
  626. var p5UI__RaportOutputPanel = createReactClass({
  627. getInitialState: function () {
  628. var initSelected = [];
  629. if (DBG_INIT_SELECTED) {
  630. var state = this.props.store.getState()
  631. initSelected = state.nodes.filter(function (node) {
  632. return ( -1 !== DBG_INIT_SELECTED.indexOf(node.id));
  633. })
  634. this.props.store.dispatch( this.props.storeActions.setSelected(initSelected) )
  635. }
  636. return {
  637. selected: initSelected,
  638. }
  639. },
  640. handleSelectFeatures: function (selected) {
  641. DBG && console.log('DBG:typeahead selected:', { selected })
  642. this.setState({ selected: selected }); // TODO: read from this.props.store.getState()
  643. this.props.store.dispatch( this.props.storeActions.setSelected( selected ) );
  644. },
  645. _onZoom: function (event) {
  646. // {
  647. // direction: '+'/'-',
  648. // scale: Number,
  649. // pointer: {x:pointer_x, y:pointer_y}
  650. // }
  651. DBG && console.log('DBG:onZoom', { scale: event.scale, event })
  652. // var this__handleZoomUpdate = this.handleZoomUpdate;
  653. },
  654. // handleZoomUpdate: function () {
  655. // DBG && console.warn('DBG:handleZoomUpdate', { event })
  656. // },
  657. render: function () {
  658. var state = this.props.store.getState()
  659. DBG && console.log('DBG:render - state', state);
  660. var nodes = state.nodes || [];
  661. return h(React.Fragment, {}, [
  662. h(Typeahead, {
  663. labelKey: "label",
  664. multiple: true,
  665. options: nodes,
  666. placeholder: "Wybierz",
  667. bsSize: 'large',
  668. selected: this.state.selected,
  669. onChange: this.handleSelectFeatures,
  670. }),
  671. h(p5UI__NetworkGraph, {
  672. raportId: this.props.raportId,
  673. store: this.props.store,
  674. storeActions: this.props.storeActions,
  675. selected: this.state.selected,
  676. onZoom: window._.throttle(this._onZoom, 500),
  677. })
  678. ])
  679. }
  680. })
  681. ReactDOM.render(
  682. h(p5UI__RaportOutputPanel, {
  683. raportId: RAPORT_ID,
  684. store: createStoreWithThunkMiddleware(NetworkGraph.store),
  685. storeActions: NetworkGraph.createActions(),
  686. }),
  687. document.getElementById(HTML_ID_REF_GRAPH)
  688. );