BiAuditGraph.php.network-graph.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  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. return Object.assign({
  376. initialized: false,
  377. isLoading: false,
  378. receivedRequestId: null,
  379. }, this.getStateFromStore());
  380. },
  381. setOutputRef: function (elem) {
  382. this._visOutputRef = elem;
  383. },
  384. componentDidMount: function () {
  385. // var data = { nodes: this._nodes, edges: this._edges };
  386. var data = { nodes: this.state.visibleNodesSet, edges: this.state.allEdgesSet };
  387. DBG && console.log('DBG:componentDidMount data', { data });
  388. this._network = new vis.Network(this._visOutputRef, data, defaultNetworkGraphOptions);
  389. if (this.props.onZoom) this._network.on('zoom', this.props.onZoom)
  390. this.setState({ initialized: true });
  391. this._unsubscribe = this.props.store.subscribe(this._storeUpdated)
  392. },
  393. _storeUpdated: function () {
  394. this.setState( this.getStateFromStore() )
  395. },
  396. fitToContainer: function () {
  397. if (this._network) {
  398. this._network.fit()
  399. }
  400. },
  401. incScale: function () {
  402. if (this._network) {
  403. var scale = this._network.getScale();
  404. this._network.moveTo({
  405. scale: scale + 0.2
  406. })
  407. }
  408. },
  409. decScale: function () {
  410. if (this._network) {
  411. var scale = this._network.getScale();
  412. this._network.moveTo({
  413. scale: (scale > 0.3) ? scale - 0.2 : scale
  414. })
  415. }
  416. },
  417. reloadGraph: function () {
  418. this.props.store.dispatch({ type: 'RELOAD_NODES' })
  419. },
  420. testOnClick1: function () {
  421. TMP_COUNTER++;
  422. this._nodes.add({ id: TMP_COUNTER, label: "Node " + TMP_COUNTER, value: TMP_COUNTER, level: 0 });
  423. },
  424. testOnClick2: function () {
  425. TMP_COUNTER++;
  426. var ids = this._nodes.getIds();
  427. var totalNodes = ids.length
  428. if (totalNodes < 3) return;
  429. var fromIdx = Math.floor(Math.random() * totalNodes);
  430. var toIdx = Math.floor(Math.random() * totalNodes);
  431. this._edges.add({ from: ids[fromIdx], to: ids[toIdx] });
  432. },
  433. testOnClick3: function () {
  434. this.props.store.dispatch( this.props.storeActions.fetchData( this.props.raportId ) );
  435. },
  436. testOnClick4: function () {
  437. DBG && console.log('DBG:Utils cache ', { cache: Utils.getCacheAllEdgeId() })
  438. },
  439. testOnClick5: function () {
  440. var edges = [];
  441. var nodes = [ { id: 'TERYT_adresy.123', label: "TER.123" }, { id: 'TERYT_adresy.666', label: "TER.666" } ];
  442. DBG && console.log('DBG:testOnClick5 add custom node + edges ', { nodes: nodes, edges: edges })
  443. this.props.store.dispatch({ type: 'TEST_ADD_DATA', nodes: nodes, edges: edges })
  444. },
  445. shouldComponentUpdate: function (nextProps, nextState) {
  446. // if (this.state.receivedRequestId !== nextState.receivedRequestId) { // add missing nodes
  447. // var state = this.props.store.getState();
  448. // DBG && console.warn("TODO: update nodes, edges", { state });
  449. // // this._edges.add( edge_or_edges_array )
  450. // if (state.nodes && state.nodes.length) {
  451. // var __nodes = this._nodes;
  452. // state.nodes.forEach(function (node) {
  453. // __nodes.add(node);
  454. // })
  455. // }
  456. // // edge: { from: page, to: subpageID, color:getEdgeColor(level), level: level, selectionWidth:2, hoverWidth:0 }
  457. // if (state.edges && state.edges.length) {
  458. // var __edges = this._edges;
  459. // // state.edges.forEach(function (edge) {
  460. // state.edges.slice(0, 30).forEach(function (edge) {
  461. // __edges.add({
  462. // from: edge.source,
  463. // to: edge.target,
  464. // });
  465. // })
  466. // }
  467. // }
  468. return false;
  469. },
  470. render: function () {
  471. return h('div', { style: { 'position': "relative" } }, [
  472. h('div', {
  473. ref: this.setOutputRef,
  474. style: {
  475. 'min-height': 600,
  476. 'height': 600,
  477. 'border-radius': "6px",
  478. 'border': "1px solid #ddd",
  479. },
  480. }),
  481. h('div', { className: "", style: { position: "absolute", right: 10, top: 10 } }, [
  482. h('div', { className: "btn-group-vertical", title: "Powiększenie" }, [
  483. h('button', { onClick: this.incScale, className: "btn btn-xs btn-default" }, [ h('i', { className: "glyphicon glyphicon-plus" }) ]),
  484. h('button', { onClick: this.fitToContainer, className: "btn btn-xs btn-default" }, [ "100%" ]),
  485. h('button', { onClick: this.decScale, className: "btn btn-xs btn-default" }, [ h('i', { className: "glyphicon glyphicon-minus" }) ]),
  486. ]),
  487. h('div', { style: { clear: "both", margin: 4 } }),
  488. h('div', { className: "btn-group-vertical", style: { width: "100%" } }, [
  489. h('button', { onClick: this.reloadGraph, className: "btn btn-xs btn-default", title: "Odśwież" }, [ h('i', { className: "glyphicon glyphicon-random" }) ]),
  490. ]),
  491. ]),
  492. // h('div', {}, [
  493. // h('button', { onClick: this.testOnClick1 }, [ "TEST 1 ", h('small', [], "(+ node)") ]),
  494. // h('button', { onClick: this.testOnClick2 }, [ "TEST 2 ", h('small', [], "(+ edge)") ]),
  495. // h('button', { onClick: this.testOnClick3 }, [ "TEST 3 ", h('small', [], "(+ fetch)") ]),
  496. // h('button', { onClick: this.testOnClick4 }, [ "TEST 4 ", h('small', [], "(+ log Utils.cache)") ]),
  497. // h('button', { onClick: this.testOnClick5 }, [ "TEST 5 ", h('small', [], "(+ data)") ]),
  498. // ]),
  499. ]);
  500. }
  501. });
  502. /**
  503. * props.store: networkGraphStore
  504. * - used: state.nodes
  505. */
  506. var p5UI__RaportOutputPanel = createReactClass({
  507. getInitialState: function () {
  508. var initSelected = [];
  509. if (DBG_INIT_SELECTED) {
  510. var state = this.props.store.getState()
  511. initSelected = DBG_INIT_SELECTED.map(function (fid) {
  512. return state.allNodesSet.get(fid)
  513. })
  514. this.props.store.dispatch( this.props.storeActions.setSelected(initSelected) )
  515. }
  516. return {
  517. selected: initSelected,
  518. }
  519. },
  520. handleSelectFeatures: function (selected) {
  521. DBG && console.log('DBG:typeahead selected:', { selected })
  522. this.setState({ selected: selected }); // TODO: read from this.props.store.getState()
  523. this.props.store.dispatch( this.props.storeActions.setSelected( selected ) );
  524. },
  525. _onZoom: function (event) {
  526. // {
  527. // direction: '+'/'-',
  528. // scale: Number,
  529. // pointer: {x:pointer_x, y:pointer_y}
  530. // }
  531. DBG && console.log('DBG:onZoom', { scale: event.scale, event })
  532. // var this__handleZoomUpdate = this.handleZoomUpdate;
  533. },
  534. // handleZoomUpdate: function () {
  535. // DBG && console.warn('DBG:handleZoomUpdate', { event })
  536. // },
  537. render: function () {
  538. var state = this.props.store.getState()
  539. DBG && console.log('DBG:render - state', state);
  540. var nodes = state.allNodesSet.map(function (node) { return node; });
  541. return h(React.Fragment, {}, [
  542. h(Typeahead, {
  543. labelKey: "label",
  544. multiple: true,
  545. options: nodes,
  546. placeholder: "Wybierz",
  547. bsSize: 'large',
  548. selected: this.state.selected,
  549. onChange: this.handleSelectFeatures,
  550. }),
  551. h(p5UI__NetworkGraph, {
  552. raportId: this.props.raportId,
  553. store: this.props.store,
  554. storeActions: this.props.storeActions,
  555. selected: this.state.selected,
  556. onZoom: window._.throttle(this._onZoom, 500),
  557. })
  558. ])
  559. }
  560. })
  561. ReactDOM.render(
  562. h(p5UI__RaportOutputPanel, {
  563. raportId: RAPORT_ID,
  564. store: createStoreWithThunkMiddleware(NetworkGraph.store),
  565. storeActions: NetworkGraph.createActions(),
  566. }),
  567. document.getElementById(HTML_ID_REF_GRAPH)
  568. );