WfsJsRequestPanel.php.refGraph.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. // @require variables:
  2. if ('undefined' === typeof HTML_ID_REF_GRAPH) throw "Missing HTML_ID_REF_GRAPH";
  3. if ('undefined' === typeof FUNCTION_FETCH_CHILDRENS) throw "Missing FUNCTION_FETCH_CHILDRENS";
  4. if ('undefined' === typeof FUNCTION_FETCH_PARENTS) throw "Missing FUNCTION_FETCH_PARENTS";
  5. if ('undefined' === typeof JS_CHANNEL_UPDATE_NAME) throw "Missing JS_CHANNEL_UPDATE_NAME";
  6. if ('undefined' === typeof postal) throw "Missing postal.js";
  7. if ('undefined' === typeof vis) throw "Missing vis.js";
  8. var DBG = DBG || false
  9. var nodes = null; // [ { id: '', label: '' }, ... ]
  10. var edges = null; // [ { id: '', from: '', to: '' }, ... ]
  11. var network = null; // graph object
  12. function dataMakeNode(params) {
  13. var objectName = params.typeName.substr(params.typeName.indexOf(':') + 1)
  14. var nodeId = objectName + '.' + params.primaryKey // TODO: primaryKey?
  15. return {
  16. id: nodeId,
  17. label: makeShortLabel(nodeId), // TODO: get from schema assert @label attribute
  18. group: objectName,
  19. _loaded: true,
  20. typeName: params.typeName,
  21. primaryKey: params.primaryKey // TODO: _primaryKey
  22. }
  23. }
  24. function dataMakeEdge(parentNodeId, nodeObject) {
  25. return {
  26. id: parentNodeId + nodeObject.id,
  27. from: parentNodeId,
  28. to: nodeObject.id,
  29. }
  30. }
  31. function dataMakeXlinkNode(params) {
  32. var objectName = params.typeName.substr(params.typeName.indexOf(':') + 1)
  33. var nodeId = params.xlink.substr(params.xlink.indexOf('#') + 1)
  34. var primaryKey = nodeId.substr(nodeId.lastIndexOf('.') + 1)
  35. return {
  36. id: nodeId,
  37. label: makeShortLabel(nodeId) + ' (+)',
  38. group: objectName,
  39. _loaded: false,
  40. typeName: params.typeName,
  41. primaryKey: primaryKey
  42. }
  43. }
  44. function dataMakeFetchMoreNode(params) {
  45. // params = {
  46. // parentNodeId: parentNodeId,
  47. // type: json.type,
  48. // objectName: objectName,
  49. // ref: json,
  50. // }
  51. if(DBG)console.log('DBG dataMakeFetchMoreNode(params)', params)
  52. var nodeId = params.parentNodeId+'fetch-more-features-'+params.type+'-on-' + params.objectName;
  53. return {
  54. id: nodeId,
  55. label: 'Pobierz więcej (+)',
  56. group: 'fetch-more-data', // params.objectName,
  57. _loaded: false,
  58. _type: 'ref',
  59. parentNodeId: params.parentNodeId,
  60. ref: params.ref,
  61. // typeName: typeName,
  62. // primaryKey: nodeId.substr(nodeId.lastIndexOf('.') + 1)
  63. };
  64. }
  65. function dataMakeFetchMoreEdge(parentNodeId, fetchMoreNode) {
  66. // @param parentNodeId - from node id
  67. // @param fetchMoreNode - from dataMakeFetchMoreNode
  68. if(DBG)console.log('DBG dataMakeFetchMoreEdge(parentNodeId, fetchMoreNode)', {parentNodeId:parentNodeId, fetchMoreNode:fetchMoreNode})
  69. return {
  70. id: fetchMoreNode.id,
  71. from: parentNodeId,
  72. to: fetchMoreNode.id
  73. }
  74. }
  75. function _dataUpdatedCallback(data, envelope) {
  76. console.log('refGraph:postal:updated', {data: data, envelope: envelope})
  77. if (network !== null) {
  78. network.destroy();
  79. network = null;
  80. }
  81. // var _edgeIdAutoIncrement = 0
  82. var _todoGraphData = [ { nodes: [], edges: [] } ]; // data by levels
  83. parseResponseRec(_todoGraphData, data.response, data.typeName)
  84. var _graphData = {
  85. nodes: new vis.DataSet(),
  86. edges: new vis.DataSet(),
  87. };
  88. _todoGraphData.forEach(function (levelData) {
  89. if (levelData.nodes && levelData.nodes.length) {
  90. levelData.nodes.forEach(function (node) {
  91. try {
  92. _graphData.nodes.add(node)
  93. } catch (e) {
  94. if(DBG)console.log('_graphData.nodes.add error:', e);
  95. }
  96. })
  97. }
  98. if (levelData.edges && levelData.edges.length) {
  99. levelData.edges.forEach(function (edge) {
  100. try {
  101. _graphData.edges.add(edge)
  102. } catch (e) {
  103. if(DBG)console.log('_graphData.edges.add error:', e);
  104. }
  105. })
  106. }
  107. })
  108. // create a network
  109. var container = document.getElementById(HTML_ID_REF_GRAPH)
  110. container.style.height = '' + (window.innerHeight - 40) + 'px'
  111. var directionInput = 'LR'
  112. var options = {
  113. layout: {
  114. hierarchical: {
  115. direction: directionInput,
  116. levelSeparation: 500,
  117. nodeSpacing: 200,
  118. sortMethod: 'directed'
  119. // hierarchical.enabled Boolean false Toggle the usage of the hierarchical layout system. If this option is not defined, it is set to true if any of the properties in this object are defined.
  120. // hierarchical.levelSeparation Number 150 The distance between the different levels.
  121. // hierarchical.nodeSpacing Number 100 Minimum distance between nodes on the free axis. This is only for the initial layout. If you enable physics, the node distance there will be the effective node distance.
  122. // hierarchical.treeSpacing Number 200 Distance between different trees (independent networks). This is only for the initial layout. If you enable physics, the repulsion model will denote the distance between the trees.
  123. // hierarchical.blockShifting Boolean true Method for reducing whitespace. Can be used alone or together with edge minimization. Each node will check for whitespace and will shift it's branch along with it for as far as it can, respecting the nodeSpacing on any level. This is mainly for the initial layout. If you enable physics, they layout will be determined by the physics. This will greatly speed up the stabilization time though!
  124. // hierarchical.edgeMinimization Boolean true Method for reducing whitespace. Can be used alone or together with block shifting. Enabling block shifting will usually speed up the layout process. Each node will try to move along its free axis to reduce the total length of it's edges. This is mainly for the initial layout. If you enable physics, they layout will be determined by the physics. This will greatly speed up the stabilization time though!
  125. // hierarchical.parentCentralization Boolean true When true, the parents nodes will be centered again after the the layout algorithm has been finished.
  126. // hierarchical.direction String 'UD' The direction of the hierarchical layout. The available options are: UD, DU, LR, RL. To simplify: up-down, down-up, left-right, right-left.
  127. // hierarchical.sortMethod String 'hubsize' The algorithm used to ascertain the levels of the nodes based on the data. The possible options are: hubsize, directed.
  128. //
  129. // Hubsize takes the nodes with the most edges and puts them at the top. From that the rest of the hierarchy is evaluated.
  130. //
  131. // Directed adheres to the to and from data of the edges. A --> B so B is a level lower than A.
  132. }
  133. }
  134. };
  135. console.log('_graphData', _graphData)
  136. network = new vis.Network(container, _graphData, options); // graphData: { nodes: [], edges: [] }
  137. // add event listeners
  138. network.on('select', function (params) {
  139. console.log('Selection: ', params.nodes)
  140. // document.getElementById('selection').innerHTML = 'Selection: ' + params.nodes;
  141. });
  142. }
  143. var subscription = postal.subscribe({
  144. channel: JS_CHANNEL_UPDATE_NAME,
  145. topic: "updated",
  146. callback: _dataUpdatedCallback
  147. });
  148. function isP5LinkObject(json) {
  149. if ( !('type' in json) || !json['type'] ) return false;
  150. if ( !('value' in json) || !json['value'] ) return false;
  151. if ( !('@typeName' in json) || !json['@typeName'] ) return false;
  152. if ( !('@startIndex' in json) || !json['@startIndex'] ) return false;
  153. if ( !('@backRefPK' in json) || !json['@backRefPK'] ) return false;
  154. if ( !('@backRefNS' in json) || !json['@backRefNS'] ) return false;
  155. return true;
  156. }
  157. function parseResponseRec(_todoGraphData, json, typeName, parentNodeId, level) { // @used global _edgeIdAutoIncrement
  158. var level = level || 0
  159. var parentNodeId = parentNodeId || null
  160. console.log('DBG::_todoGraphData level('+level+')', _todoGraphData);
  161. if(DBG)console.log('DBG::parseResponseRec', {json:json, typeName:typeName, parentNodeId:parentNodeId, isString: p5Utils__isString(json), isArray: p5Utils__isArray(json), isObject: p5Utils__isObject(json)});
  162. if (p5Utils__isArray(json)) {
  163. if(DBG)console.log('DBG::parseResponseRec isArray', json);
  164. // TODO: create named group
  165. var isXlinkList = (json.length > 0 && p5Utils__isString(json[0]))
  166. json.forEach(function (subJson) {
  167. if (isXlinkList) {
  168. parseResponseXlinkListRec(_todoGraphData, subJson, typeName, parentNodeId, level)
  169. } else {
  170. parseResponseRec(_todoGraphData, subJson, typeName, parentNodeId, level)
  171. }
  172. })
  173. } else if (p5Utils__isObject(json) && isP5LinkObject(json)) {
  174. if(DBG)console.log('DBG::parseResponseRec isP5LinkObject', json);
  175. parseResponseP5Link(_todoGraphData, json, typeName, parentNodeId, level)
  176. } else if (p5Utils__isObject(json)) {
  177. if(DBG)console.log('DBG::parseResponseRec isObject', json);
  178. var objectName = typeName.substr(typeName.indexOf(':') + 1)
  179. var nodeId = objectName + '.' + json.ID // TODO: primaryKey?
  180. {
  181. // _todoGraphData.nodes.add({ id: nodeId, label: nodeId })
  182. if (!_todoGraphData[level]) _todoGraphData[level] = { nodes: [], edges: [] }
  183. _todoGraphData[level].nodes.push({ id: nodeId, label: nodeId, group: objectName })
  184. if (parentNodeId) {
  185. // _graphData.edges.add({ id: parentNodeId+nodeId, from: parentNodeId, to: nodeId })
  186. _todoGraphData[level].edges.push({ id: parentNodeId+nodeId, from: parentNodeId, to: nodeId })
  187. }
  188. }
  189. Object.keys(json).filter(function (fieldName) {
  190. return (fieldName.indexOf(':') > -1)
  191. })
  192. .forEach(function (fieldName) {
  193. var value = json[fieldName]
  194. console.log('feature['+fieldName+'] = ', value)
  195. parseResponseRec(_todoGraphData, value, fieldName, nodeId, level + 1)
  196. })
  197. } else if (p5Utils__isString(json)) {
  198. if(DBG)console.log('TODO: Not implemented - parseResponseRec isString');
  199. } else {
  200. if(DBG)console.log('TODO: Not implemented - parseResponseRec is not string, not array and not object');
  201. }
  202. }
  203. function parseResponseXlinkListRec(_todoGraphData, json, typeName, parentNodeId, level) {
  204. console.log('DBG::_todoGraphData level('+level+')', _todoGraphData);
  205. if(DBG)console.log('DBG::parseResponseRec:XlinkList', {json:json, typeName:typeName, parentNodeId:parentNodeId, isString: p5Utils__isString(json), isArray: p5Utils__isArray(json), isObject: p5Utils__isObject(json)});
  206. if (p5Utils__isString(json)) { // xlink "https://biuro.biall-net.pl/wfs/default_db/BI_audit_ENERGA_RUM_KONTRAHENCI#BI_audit_ENERGA_RUM_KONTRAHENCI.9233",
  207. var nodeId = json.substr(json.indexOf('#') + 1)
  208. var objectName = typeName
  209. {
  210. // _graphData.nodes.add({ id: nodeId, label: nodeId })
  211. if (!_todoGraphData[level]) _todoGraphData[level] = { nodes: [], edges: [] }
  212. _todoGraphData[level].nodes.push({ id: nodeId, label: nodeId, group: objectName })
  213. if (parentNodeId) {
  214. // _graphData.edges.add({ id: parentNodeId+nodeId, from: parentNodeId, to: nodeId })
  215. _todoGraphData[level].edges.push({ id: parentNodeId+nodeId, from: parentNodeId, to: nodeId })
  216. }
  217. }
  218. } else if (p5Utils__isObject(json) && isP5LinkObject(json)) {
  219. parseResponseP5Link(_todoGraphData, json, typeName, parentNodeId, level)
  220. } else {
  221. if(DBG)console.log('TODO: Not implemented - parseResponseRec:XlinkList is not string and not object');
  222. }
  223. }
  224. function parseResponseP5Link(_todoGraphData, json, typeName, parentNodeId, level) {
  225. if(DBG)console.log('parseResponseRec isObject and P5Link - fetch more xlink object');
  226. console.warn("TODO: parseResponseP5Link(_todoGraphData, json, typeName, parentNodeId, level)", json);
  227. // example json: { type: "next",
  228. // @backRefNS: "default_db/BI_audit_ENERGA_RUM_KONTRAHENCI_POWIAZANIA/BI_audit_ENERGA_RUM_KONTRAHENCI_POWIAZANIA",
  229. // @backRefPK: "42",
  230. // @typeName: "default_db__x3A__BI_audit_ENERGA_RUM_KONTRAHENCI_P…ow:BI_audit_ENERGA_RUM_KONTRAHENCI_POWIAZANIA_row",
  231. // @startIndex: "10" }
  232. if (!parentNodeId) throw "Missing parentNodeId for ref link object";
  233. var objectName = typeName.substr(typeName.indexOf(':') + 1)
  234. {
  235. // _graphData.nodes.add({ id: nodeId, label: nodeId })
  236. if (!_todoGraphData[level]) _todoGraphData[level] = { nodes: [], edges: [] }
  237. switch (json.type) {
  238. case 'next': {
  239. if(DBG)console.log('TODO: next "'+json.type+'" - fetch more xlink object');
  240. // var nodeId = 'fetch-more-features-'+json.type+'-on-' + objectName;
  241. // _todoGraphData[level].nodes.push({
  242. // id: nodeId,
  243. // label: 'Pobierz więcej (+)',
  244. // group: objectName,
  245. // _loaded: false,
  246. // _type: 'ref',
  247. // parentNodeId: parentNodeId,
  248. // ref: json,
  249. // // typeName: typeName,
  250. // // primaryKey: nodeId.substr(nodeId.lastIndexOf('.') + 1)
  251. // })
  252. // // _graphData.edges.add({ id: parentNodeId+nodeId, from: parentNodeId, to: nodeId })
  253. // _todoGraphData[level].edges.push({ id: parentNodeId+nodeId, from: parentNodeId, to: nodeId })
  254. var nodeObject = dataMakeFetchMoreNode({
  255. parentNodeId: parentNodeId,
  256. type: json.type,
  257. objectName: objectName,
  258. ref: json,
  259. })
  260. _todoGraphData[level].nodes.push(nodeObject)
  261. _todoGraphData[level].edges.push(dataMakeFetchMoreEdge(parentNodeId, nodeObject))
  262. } break;
  263. default: {
  264. if(DBG)console.log('TODO: Not implemented - parseResponseRec isObject with type "'+json.type+'" - fetch more xlink object');
  265. }
  266. }
  267. }
  268. }
  269. function refGraphFetchChildrens() {
  270. }
  271. function refGraphFetchParents() {
  272. }
  273. global['FUNCTION_FETCH_CHILDRENS'] = 'refGraphFetchChildrens'
  274. global['FUNCTION_FETCH_PARENTS'] = 'refGraphFetchParents'