Просмотр исходного кода

updated RefGraph - load nodes on click

Piotr Labudda 8 лет назад
Родитель
Сommit
a323b4612a
1 измененных файлов с 129 добавлено и 52 удалено
  1. 129 52
      SE/se-lib/Route/RefGraph.php.view.js

+ 129 - 52
SE/se-lib/Route/RefGraph.php.view.js

@@ -7,18 +7,52 @@ if ('undefined' === typeof PRIMARY_KEY) throw "Missing PRIMARY_KEY";
 // if ('undefined' === typeof JS_CHANNEL_UPDATE_NAME) throw "Missing JS_CHANNEL_UPDATE_NAME";
 var DBG = DBG || 0;
 
-var nodes = null; // [ { id: '', label: '' }, ... ]
-var edges = null; // [ { id: '', from: '', to: '' }, ... ]
-var network = null; // graph object
+var _nodes = new vis.DataSet(); // [ { id: '', label: '' }, ... ]
+var _edges = new vis.DataSet(); // [ { id: '', from: '', to: '' }, ... ]
+var _network = null; // graph object
+var _todoGraphData = [ { nodes: [], edges: [] } ]; // data by levels
+var _defaultWfsParams = {
+	resolve: 'all',
+	resolveDepth: 2,
+}
+var _defaultVisJsOptions = {
+	nodes: {
+		shape: 'box'
+	},
+	interaction: {
+		dragNodes: false
+	},
+	physics: {
+		enabled: false
+	},
+	layout: {
+		hierarchical: {
+			direction: 'LR',
+			levelSeparation: 500, // hierarchical.levelSeparation	Number	150	The distance between the different levels.
+			nodeSpacing: 40, // 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.
+			treeSpacing: 500, // 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.
+			sortMethod: 'directed'
+			// 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.
+			// 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!
+			// 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!
+			// hierarchical.parentCentralization	Boolean	true	When true, the parents nodes will be centered again after the the layout algorithm has been finished.
+			// 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.
+			// hierarchical.sortMethod	String	'hubsize'	The algorithm used to ascertain the levels of the nodes based on the data. The possible options are: hubsize, directed.
+			//
+			// Hubsize takes the nodes with the most edges and puts them at the top. From that the rest of the hierarchy is evaluated.
+			//
+			// Directed adheres to the to and from data of the edges. A --> B so B is a level lower than A.
+		}
+	}
+};
+
 
 (function () {
 	var form = document.getElementById('wfs_request')
 	var featureTypeName = TYPENAME
-	var wfsParams = {
-		resolve: 'all',
-		resolveDepth: 3,
+	var wfsParams = Object.assign({}, _defaultWfsParams, {
 		primaryKey: PRIMARY_KEY,
-	}
+	})
 	if(DBG)console.log('p5WFS_GetFeature', featureTypeName, wfsParams)
 	p5WFS_GetFeature(featureTypeName, wfsParams).then(function (features) {
 		if(DBG)console.log('features', features)
@@ -27,28 +61,27 @@ var network = null; // graph object
 		if(DBG)console.warn(e)
 		p5UI__notifyAjaxCallback({ type: 'error', msg: e })
 	})
+
 })();
 
 function updateWfsResponse(features, featureTypeName) {
 	if(DBG)console.log('updateWfsResponse', { features: features, featureTypeName: featureTypeName })
-	if (network !== null) {
-		network.destroy();
-		network = null;
-	}
+	// if (_network !== null) {
+	// 	_network.destroy();
+	// 	_network = null;
+	// }
 
-	// var _edgeIdAutoIncrement = 0
-	var _todoGraphData = [ { nodes: [], edges: [] } ]; // data by levels
 	parseResponseRec(_todoGraphData, features, featureTypeName)
 
 	var _graphData = {
-		nodes: new vis.DataSet(),
-		edges: new vis.DataSet(),
+		nodes: _nodes,
+		edges: _edges,
 	};
 	_todoGraphData.forEach(function (levelData) {
 		if (levelData.nodes && levelData.nodes.length) {
 			levelData.nodes.forEach(function (node) {
 				try {
-					_graphData.nodes.add(node)
+					_nodes.add(node)
 				} catch (e) {
 					if(DBG)console.log('_graphData.nodes.add error:', e);
 				}
@@ -57,7 +90,7 @@ function updateWfsResponse(features, featureTypeName) {
 		if (levelData.edges && levelData.edges.length) {
 			levelData.edges.forEach(function (edge) {
 				try {
-					_graphData.edges.add(edge)
+					_edges.add(edge)
 				} catch (e) {
 					if(DBG)console.log('_graphData.edges.add error:', e);
 				}
@@ -68,46 +101,79 @@ function updateWfsResponse(features, featureTypeName) {
 	// create a network
 	var container = document.getElementById(HTML_ID_REF_GRAPH)
 	container.style.height = '' + (window.innerHeight - 40) + 'px'
-	var directionInput = 'LR'
-	var options = {
-		layout: {
-			hierarchical: {
-				direction: directionInput,
-				levelSeparation: 500,
-				nodeSpacing: 200,
-				sortMethod: 'directed'
-				// 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.
-				// hierarchical.levelSeparation	Number	150	The distance between the different levels.
-				// 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.
-				// 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.
-				// 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!
-				// 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!
-				// hierarchical.parentCentralization	Boolean	true	When true, the parents nodes will be centered again after the the layout algorithm has been finished.
-				// 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.
-				// hierarchical.sortMethod	String	'hubsize'	The algorithm used to ascertain the levels of the nodes based on the data. The possible options are: hubsize, directed.
-        //
-				// Hubsize takes the nodes with the most edges and puts them at the top. From that the rest of the hierarchy is evaluated.
-        //
-				// Directed adheres to the to and from data of the edges. A --> B so B is a level lower than A.
-			}
-		}
-	};
+	var options = _defaultVisJsOptions
 	if(DBG)console.log('_graphData', _graphData)
-	network = new vis.Network(container, _graphData, options); // graphData: { nodes: [], edges: [] }
+	if (!_network) {
+		_network = new vis.Network(container, _graphData, options); // graphData: { nodes: [], edges: [] }
+
+		// add event listeners
+		_network.on('selectNode', function (params) {
+			console.log('Selection: ', params.nodes)
+			var featureID = params.nodes[0]
+			if (!featureID) return;
+			if ('-loading' === featureID.substr(-1 * '-loading'.length)) {
+				// TODO: gui msg...
+				console.log('loading nodes connected with: "' +featureID.substr(0, featureID.length - '-loading'.length) + '" ...')
+				return;
+			}
+			var selectedNode = _nodes.get(featureID)
+			if (!selectedNode) return;
+			if (selectedNode._loaded) return;
+			try {
+				var featureEx = featureID.split('.')
+				if (2 !== featureEx.length) throw "Not supported featureID format"
+				var featureTypeName = 'default_db__x3A__' + featureEx[0] + ':' + featureEx[0]
+				var wfsParams = Object.assign({}, _defaultWfsParams, {
+					primaryKey: featureEx[1]
+				});
+
+				var fakeLoadingNodeID = featureID + '-loading'
+				_nodes.add({
+					id: fakeLoadingNodeID,
+					label: 'loading...',
+				})
+				_edges.add({
+					id: fakeLoadingNodeID,
+					from: featureID,
+					to: fakeLoadingNodeID
+				})
 
-	// add event listeners
-	network.on('select', function (params) {
-		if(DBG)console.log('Selection: ', params.nodes)
-		// document.getElementById('selection').innerHTML = 'Selection: ' + params.nodes;
-	});
+				// view-source:http://visjs.org/examples/network/data/dynamicData.html
+				p5WFS_GetFeature(featureTypeName, wfsParams).then(function (features) {
+					if(DBG)console.log('features', features)
+					if (!features.length || 1 !== features.length) throw "Brak danych" // require 1 feature with recurse
+					var refFields = Object.keys(features[0]).filter(function (fieldName) {
+						return (fieldName.indexOf(':') > -1)
+					}).filter(function (fieldName) {
+						return (features[0][fieldName].length > 0)
+					})
+					if (!refFields.length) return "Brak danych"
+					updateWfsResponse(features, featureTypeName)
+					return "Pobrano nowe dane"
+				}).then(function (msg) {
+					p5UI__notifyAjaxCallback({ type: 'info', msg: msg })
+					_nodes.remove({ id: fakeLoadingNodeID })
+					_edges.remove({ id: fakeLoadingNodeID })
+					_nodes.update({ id: featureID, _loaded: true })
+				}).catch(function (e) {
+					if(DBG)console.warn(e)
+					p5UI__notifyAjaxCallback({ type: 'error', msg: e })
+					_nodes.remove({ id: fakeLoadingNodeID })
+					_edges.remove({ id: fakeLoadingNodeID })
+					_nodes.update({ id: featureID, _loaded: true })
+				})
+			} catch (e) {
+				if(DBG)console.warn(e)
+			}
+		});
+	}
 }
 
-function parseResponseRec(_todoGraphData, json, typeName, parentNodeId, level) { // @used global _edgeIdAutoIncrement
+function parseResponseRec(_todoGraphData, json, typeName, parentNodeId, level) {
 	var level = level || 0
 	var parentNodeId = parentNodeId || null
 	if(DBG)console.log('DBG::parseResponseRec', {json:json, typeName:typeName, parentNodeId:parentNodeId, isString: p5Utils__isString(json), isArray: p5Utils__isArray(json), isObject: p5Utils__isObject(json)});
 	if (p5Utils__isArray(json)) {
-		if(DBG)console.log('TODO: Not implemented - parseResponseRec isArray');
 		// TODO: create named group
 		var isXlinkList = (json.length > 0 && p5Utils__isString(json[0]))
 		json.forEach(function (subJson) {
@@ -118,13 +184,12 @@ function parseResponseRec(_todoGraphData, json, typeName, parentNodeId, level) {
 			}
 		})
 	} else if (p5Utils__isObject(json)) {
-		if(DBG)console.log('TODO: Not implemented - parseResponseRec isObject');
 		var objectName = typeName.substr(typeName.indexOf(':') + 1)
 		var nodeId = objectName + '.' + json.ID // TODO: primaryKey?
 		{
 			// _todoGraphData.nodes.add({ id: nodeId, label: nodeId })
 			if (!_todoGraphData[level]) _todoGraphData[level] = { nodes: [], edges: [] }
-			_todoGraphData[level].nodes.push({ id: nodeId, label: nodeId, group: objectName })
+			_todoGraphData[level].nodes.push({ id: nodeId, label: nodeId, group: objectName, _loaded: true })
 			if (parentNodeId) {
 				// _graphData.edges.add({ id: parentNodeId+nodeId, from: parentNodeId, to: nodeId })
 				_todoGraphData[level].edges.push({ id: parentNodeId+nodeId, from: parentNodeId, to: nodeId })
@@ -151,7 +216,7 @@ function parseResponseXlinkListRec(_todoGraphData, json, typeName, parentNodeId,
 		{
 			// _graphData.nodes.add({ id: nodeId, label: nodeId })
 			if (!_todoGraphData[level]) _todoGraphData[level] = { nodes: [], edges: [] }
-			_todoGraphData[level].nodes.push({ id: nodeId, label: nodeId, group: objectName })
+			_todoGraphData[level].nodes.push({ id: nodeId, label: nodeId, group: objectName, _loaded: false })
 			if (parentNodeId) {
 				// _graphData.edges.add({ id: parentNodeId+nodeId, from: parentNodeId, to: nodeId })
 				_todoGraphData[level].edges.push({ id: parentNodeId+nodeId, from: parentNodeId, to: nodeId })
@@ -159,6 +224,18 @@ function parseResponseXlinkListRec(_todoGraphData, json, typeName, parentNodeId,
 		}
 	} else if (p5Utils__isObject(json)) {
 		if(DBG)console.log('TODO: Not implemented - parseResponseRec isObject - fetch more xlink object');
+		console.log('TODO: Not implemented - parseResponseRec isObject - fetch more xlink object', json);
+		// var nodeId = json.substr(json.indexOf('#') + 1)
+		// var objectName = typeName
+		// {
+		// 	// _graphData.nodes.add({ id: nodeId, label: nodeId })
+		// 	if (!_todoGraphData[level]) _todoGraphData[level] = { nodes: [], edges: [] }
+		// 	_todoGraphData[level].nodes.push({ id: nodeId, label: nodeId, group: objectName })
+		// 	if (parentNodeId) {
+		// 		// _graphData.edges.add({ id: parentNodeId+nodeId, from: parentNodeId, to: nodeId })
+		// 		_todoGraphData[level].edges.push({ id: parentNodeId+nodeId, from: parentNodeId, to: nodeId })
+		// 	}
+		// }
 	} else {
 		if(DBG)console.log('TODO: Not implemented - parseResponseRec:XlinkList is not string and not object');
 	}