All Downloads are FREE. Search and download functionalities are using the official Maven repository.

structr.js.graph.js Maven / Gradle / Ivy

Go to download

Structr is an open source framework based on the popular Neo4j graph database.

The newest version!
/*
 * Copyright (C) 2010-2016 Structr GmbH
 *
 * This file is part of Structr .
 *
 * Structr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * Structr is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Structr.  If not, see .
 */
var win = $(window);
var engine, mode, colors = [], color = 0;
var nodeIds = [], relIds = [], removedRel;
var activeTabRightGraphKey = 'structrActiveTabRightGraph_' + port;
var activeTabLeftGraphKey = 'structrActiveTabLeftGraph_' + port;
var activeTabLeftGraph, activeTabRightGraph;
var queriesSlideout, displaySlideout, filtersSlideout, nodesSlideout, relationshipsSlideout, graph;
var savedQueriesKey = 'structrSavedQueries_' + port;
var relTypes = {}, nodeTypes = {}, nodeColors = {}, relColors = {}, hasDragged, hasDoubleClicked, clickTimeout, doubleClickTime = 250, refreshTimeout;
var filteredNodeTypes = [], hiddenNodeTypes = [], hiddenRelTypes = []; //['OWNS', 'SECURITY'];
var edgeType = 'curvedArrow';
var schemaNodes = {}, schemaRelationships = {}, schemaNodesById = {};
var displayHtmlTypes = false, displayCustomTypes = true, displayCoreTypes = false, displayUiTypes = false, displayLogTypes = false, displayOtherTypes = false;
var maxRels = 100, defaultNodeColor = '#a5a5a5', defaultRelColor = '#cccccc';
var tmpX, tmpY;
var forceAtlas2Config = {
	gravity: 1,
	strongGravityMode: true,
	adjustSizes: true,
	iterationsPerRender: 10,
	barnesHutOptimize: false,
	slowDown: 2
		//outboundAttractionDistribution: true
		//startingIterations: 1000
};

var animating = false;
var timeout   = 0;
var expanded  = {};
var count     = 0;

$(document).ready(function() {
	Structr.registerModule('graph', _Graph);

	$(document.body).on('mousedown', function(e) {
		tmpX = e.clientX;
		tmpY = e.clientY;
	});

	$(document.body).on('mouseup', function(e) {
		hasDragged = (tmpX && tmpY && (tmpX !== e.clientX || tmpY !== e.clientY));
		tmpX = e.clientX;
		tmpY = e.clientY;
	});

});

var _Graph = {
	icon: 'icon/page.png',
	add_icon: 'icon/page_add.png',
	delete_icon: 'icon/page_delete.png',
	clone_icon: 'icon/page_copy.png',
	init: function() {

		// Colors created with http://paletton.com

		colors.push('#82CE25');
		colors.push('#1DA353');
		colors.push('#E24C29');
		colors.push('#C22363');

		colors.push('#B7ED74');
		colors.push('#61C68A');
		colors.push('#FF967D');
		colors.push('#E26F9E');

		colors.push('#9BDD4A');
		colors.push('#3BAF6A');
		colors.push('#F37052');
		colors.push('#D1467E');

		colors.push('#63A80F');
		colors.push('#0C853D');
		colors.push('#B93111');
		colors.push('#9E0E48');

		colors.push('#498500');
		colors.push('#00692A');
		colors.push('#921C00');
		colors.push('#7D0033');

		colors.push('#019097');
		colors.push('#103BA8');
		colors.push('#FAA800');
		colors.push('#FA7300');

		colors.push('#3FB0B5');
		colors.push('#5070C1');
		colors.push('#FFC857');
		colors.push('#FFA557');

		colors.push('#1CA2A8');
		colors.push('#2E55B7');
		colors.push('#FFB929');
		colors.push('#FF8C29');

		colors.push('#017277');
		colors.push('#0B2E85');
		colors.push('#C68500');
		colors.push('#C65B00');

		colors.push('#00595D');
		colors.push('#072368');
		colors.push('#9A6800');
		colors.push('#9A4700');

		var max = 255, min = 0;

		for (i = 50; i < 999; i++) {
			var color = 'rgb(' + (Math.floor((max - min) * Math.random()) + min) + ',' + (Math.floor((max - min) * Math.random()) + min) + ',' + (Math.floor((max - min) * Math.random()) + min) + ')';
			colors.push(color);
		}

		_Graph.updateNodeTypes();

		sigma.renderers.def = sigma.renderers.canvas;

		if (engine) {
			_Logger.log(_LogType.GRAPH, 'sigma engine already exists', engine);
			//_Graph.scheduleRefreshEngine();
			//_Graph.clearGraph();
			//engine.refresh();
			engine = undefined;
		}
		engine = new sigma({
			container: 'graph-canvas',
//			settings: {
//				immutable: false,
//				//scalingMode: 'outside',
//				//autoRescale: false,
//				//batchEdgesDrawing: true,
//				minNodeSize: 20,
//				maxNodeSize: 20,
//				borderSize: 4,
//				defaultNodeBorderColor: '#a5a5a5',
//				singleHover: true,
//				doubleClickEnabled: false, // catch doubleClick event, see https://github.com/jacomyal/sigma.js/commit/1453afbf0d08fb5a64a88df3c3b941a2894a713b
//
//				minEdgeSize: 4,
//				maxEdgeSize: 4,
//				enableEdgeHovering: true,
//				edgeHoverColor: 'default',
//				edgeHoverSizeRatio: 1.3,
//				edgeHoverExtremities: true,
//				defaultEdgeHoverColor: '#888',
//				//edgeLabelSize: 'proportional',
//				minArrowSize: 12
//					//sideMargin: 1,
//			},
			settings : {
				font: 'Open Sans',
				immutable: false,
				minNodeSize: 4,
				maxNodeSize: 16,
				borderSize: 4,
				defaultNodeBorderColor: '#a5a5a5',
				singleHover: true,
				doubleClickEnabled: false,
				minEdgeSize: 4,
				maxEdgeSize: 4,
				enableEdgeHovering: true,
				edgeHoverColor: 'default',
				edgeHoverSizeRatio: 1.3,
				edgeHoverExtremities: true,
				defaultEdgeColor: '#999',
				defaultEdgeHoverColor: '#888',
				minArrowSize: 12,
				//maxArrowSize: 12,
				labelSize: 'proportional',
				labelSizeRatio: 1,
				//sideMargin: 100
			}
		});

		engine.bind('doubleClickNode', function(e) {
			window.clearTimeout(clickTimeout);
			hasDoubleClicked = true;
			_Graph.loadRelationships(e.data.node.id);
			engine.renderers[0].dispatchEvent('outNode', {node: e.data.node});
			return false;
		});

		engine.bind('clickNode', function(e) {

			_Logger.log(_LogType.GRAPH, 'clickNode');

			if (hasDoubleClicked) {
				_Logger.log(_LogType.GRAPH, 'double clicked, returning');
				return false;
			}

			var node = e.data.node;

			if (hasDragged) {
				hasDragged = false;
				return false;
			}

			clickTimeout = window.setTimeout(function() {
				if (!hasDoubleClicked && !hasDragged) {
					_Entities.showProperties(node);
					engine.renderers[0].dispatchEvent('outNode', {node: node});
					window.clearTimeout(clickTimeout);
				}
			}, doubleClickTime);
			window.setTimeout(function() {
				hasDoubleClicked = false;
			}, doubleClickTime + 10);

		});

		var dragListener = new sigma.plugins.dragNodes(engine, engine.renderers[0]);
		dragListener.bind('startdrag', function() {
			hasDragged = false;
		});
		dragListener.bind('drag', function(e) {
			hasDragged = true;
			var node = e.data.node;

			engine.graph.nodes().forEach(function(n) {
				if (n === node) {
					return;
				}
				var d = _Graph.distance(node, n);
				if (shiftKey && d < 200) {

					var draggedNodeSchemaNode = schemaNodes[node.type];
					//console.log('shift and in radius', n, node, sourceSchemaNode);

					if (!draggedNodeSchemaNode) {

						console.log("Unknown type " + node.type);
						return;
					}

					if (draggedNodeSchemaNode.relatedTo) {

						// outgoing schema rels
						draggedNodeSchemaNode.relatedTo.forEach(function(toRel) {

							var edgeId = node.id + '-[:' + toRel.id + ']->' + n.id;

							if (toRel.allTargetTypesPossible || (toRel.possibleTargetTypes && toRel.possibleTargetTypes.contains(n.type)) && !engine.graph.edges(edgeId)) {

								//console.log('toRel, target multi', toRel.targetMultiplicity, toRel);

								if (toRel.sourceMultiplicity === '1') {
									engine.graph.edges().forEach(function(edge) {
										//console.log(edge, n, node, toRel);
										if (edge.target === n.id && edge.relType === toRel.relationshipType) {
											edge.hidden = true;
											edge.removed = true;
											//console.log('outgoing rel found, will be removed', edge);
											removedRel = edge.id;
										}
									});
								}

								if (toRel.targetMultiplicity === '1') {
									engine.graph.edges().forEach(function(edge) {
										//console.log(edge, n, node, toRel);
										if (edge.source === node.id && edge.relType === toRel.relationshipType) {
											edge.hidden = true;
											edge.removed = true;
											//console.log('outgoing rel found, will be removed', edge);
											removedRel = edge.id;
										}
									});
								}

								engine.graph.addEdge({
									id: edgeId,
									label: toRel.relationshipType,
									source: node.id,
									target: n.id,
									size: 40,
									color: '#81ce25',
									type: 'curvedArrow',
									added: true,
									replaced: removedRel,
									relType: toRel.relationshipType
								});

							}
						});
					}

					if (draggedNodeSchemaNode.relatedFrom) {

						// incoming schema rels
						draggedNodeSchemaNode.relatedFrom.forEach(function(fromRel) {

							var edgeId = node.id + '<-[:' + fromRel.id + ']-' + n.id;

							//console.log('possible source type:', possibleSourceType, 'edge exists?', edgeId, engine.graph.edges(edgeId));

							if (fromRel.allSourceTypesPossible || (fromRel.possibleSourceTypes && fromRel.possibleSourceTypes.contains(n.type)) && !engine.graph.edges(edgeId)) {

								//console.log('fromRel source multi', fromRel.sourceMultiplicity, fromRel);

								if (fromRel.sourceMultiplicity === '1') {

									// loop over all edges if they fit the schema rel
									engine.graph.edges().forEach(function(edge) {
										//console.log(edge, n, node, fromRel);
										//if (edge.source === n.id && edge.relType === fromRel.relationshipType) {
										if (edge.target === node.id && edge.relType === fromRel.relationshipType) {
											edge.hidden = true;
											edge.removed = true;
											//console.log('outgoing rel found, will be removed', edge);
											removedRel = edge.id;
										}
									});
								}

								if (fromRel.targetMultiplicity === '1') {

									// loop over all edges if they fit the schema rel
									engine.graph.edges().forEach(function(edge) {
										//console.log(edge, n, node, fromRel);
										//if (edge.source === n.id && edge.relType === fromRel.relationshipType) {
										if (edge.source === n.id && edge.relType === fromRel.relationshipType) {
											edge.hidden = true;
											edge.removed = true;
											//console.log('outgoing rel found, will be removed', edge);
											removedRel = edge.id;
										}
									});
								}

								engine.graph.addEdge({
									id: edgeId,
									label: fromRel.relationshipType,
									source: n.id,
									target: node.id,
									size: 40,
									color: '#81ce25',
									type: 'curvedArrow',
									added: true,
									replaced: removedRel,
									relType: fromRel.relationshipType
								});
							}
						});
					}
					_Graph.scheduleRefreshEngine();

				} else {

					engine.graph.edges().forEach(function(edge) {

						if ((edge.source === node.id && edge.target === n.id) || (edge.source === n.id && edge.target === node.id)) {

							if (edge.added) {
								var replaced = edge.replaced;
								_Logger.log(_LogType.GRAPH, 'edge replaced ', replaced);
								engine.graph.dropEdge(edge.id);
								if (replaced && engine.graph.edges(replaced)) {
									engine.graph.edges(replaced).hidden = false;
									removedRel = undefined;
								}
							}
						}
					});
				}
			});

		});
		dragListener.bind('dragend', function(e) {

			//console.log('dragend', removedRel);

			if (removedRel) {
				Command.deleteRelationship(removedRel);
				removedRel = undefined;
			}

			engine.graph.edges().forEach(function(edge) {


				if (edge.added) {
					// Create new relationship
					var relData = {
						sourceId: edge.source,
						targetId: edge.target,
						relType: edge.relType
					};
					Command.createRelationship(relData, function(rel) {

						//console.log('created new rel', rel.id, 'to replace', edge.id);
						var ref = edge.id;

						edge.color = defaultRelColor;
						edge.id = rel.id;
						edge.added = false;
						_Graph.scheduleRefreshEngine();

						engine.graph.dropEdge(ref);

						//console.log('reference still valid', engine.graph.edges(ref));
					});
				}
			});
		});

		engine.bind('clickEdge', function(e) {
			hasDoubleClicked = false;
			_Entities.showProperties(e.data.edge);
			engine.renderers[0].dispatchEvent('outEdge', {edge: e.data.edge});
		});

	},
	onload: function() {

		$('#main-help a').attr('href', 'http://docs.structr.org/frontend-user-guide#Graph');

		activeTabLeftGraph = LSWrapper.getItem(activeTabRightGraphKey);
		activeTabRightGraph = LSWrapper.getItem(activeTabLeftGraphKey);

		main.prepend(
			'
Queries
' + '
Display Options
' + '
Filters

Node Filters

Relationship Filters

' + '
' + '
' + '
' //+ '
Nodes
' //+ '
Relationships
' + '
' ); queriesSlideout = $('#queries'); displaySlideout = $('#display'); filtersSlideout = $('#filters'); var nodeFilters = $('#nodeFilters', filtersSlideout); nodeFilters.append('
Core types
'); $('.toggle-core-types', nodeFilters).on('click', function() { displayCoreTypes = !displayCoreTypes; _Graph.updateNodeTypes(); }); nodeFilters.append('
UI types
'); $('.toggle-ui-types', nodeFilters).on('click', function() { displayUiTypes = !displayUiTypes; _Graph.updateNodeTypes(); }); nodeFilters.append('
Custom types
'); $('.toggle-custom-types', nodeFilters).on('click', function() { displayCustomTypes = !displayCustomTypes; _Graph.updateNodeTypes(); }); nodeFilters.append('
HTML types
'); $('.toggle-html-types', nodeFilters).on('click', function() { displayHtmlTypes = !displayHtmlTypes; _Graph.updateNodeTypes(); }); nodeFilters.append('
Log types
'); $('.toggle-log-types', nodeFilters).on('click', function() { displayLogTypes = !displayLogTypes; _Graph.updateNodeTypes(); }); nodeFilters.append('
Other types
'); $('.toggle-other-types', nodeFilters).on('click', function() { displayOtherTypes = !displayOtherTypes; _Graph.updateNodeTypes(); }); graph = $('#graph-canvas'); $(document.body).on('selectstart', function(e) { e.preventDefault(); return false; }); graph.droppable({ accept: '.node-type', drop: function(e, ui) { var nodeType = ui.helper.attr('data-node-type') var x = ui.offset.left; var y = ui.offset.top; //console.log('Creating node of type', nodeType, x, y); Command.create({ type: nodeType }, function(obj) { Command.get(obj.id, function(node) { _Graph.drawNode(node); _Graph.refreshEngine(); }); }); } }); _Graph.init(); nodesSlideout = $('#nodes'); relationshipsSlideout = $('#relationships'); lsw = queriesSlideout.width() + 12; rsw = nodesSlideout.width() + 12; $('.slideOut').on('mouseover', function() { running = false; return true; }); $('.slideOut').on('mouseout', function() { running = true; //_Graph.scheduleRefreshEngine(); return true; }); $('#queriesTab').on('click', function() { if (Math.abs(queriesSlideout.position().left + lsw) <= 3) { Structr.closeLeftSlideOuts([displaySlideout, filtersSlideout], activeTabLeftGraphKey); Structr.openLeftSlideOut(queriesSlideout, this, activeTabLeftGraphKey); } else { Structr.closeLeftSlideOuts([queriesSlideout], activeTabLeftGraphKey); } }); $('#displayTab').on('click', function() { if (Math.abs(displaySlideout.position().left + lsw) <= 3) { Structr.closeLeftSlideOuts([queriesSlideout, filtersSlideout], activeTabLeftGraphKey); Structr.openLeftSlideOut(displaySlideout, this, activeTabLeftGraphKey, function() { //console.log('Display options opened'); }); } else { Structr.closeLeftSlideOuts([displaySlideout], activeTabLeftGraphKey); } }); $('#filtersTab').on('click', function() { if (Math.abs(filtersSlideout.position().left + lsw) <= 3) { Structr.closeLeftSlideOuts([queriesSlideout, displaySlideout], activeTabLeftGraphKey); Structr.openLeftSlideOut(filtersSlideout, this, activeTabLeftGraphKey, function() { //console.log('Filters opened'); }); } else { Structr.closeLeftSlideOuts([filtersSlideout], activeTabLeftGraphKey); } }); // $('#nodesTab').on('click', function() { // if (nodesSlideout.position().left === $(window).width()) { // Structr.closeSlideOuts([relationshipsSlideout], activeTabRightGraphKey); // Structr.openSlideOut(nodesSlideout, this, activeTabRightGraphKey, function() { // console.log('Nodes opened'); // }); // } else { // Structr.closeSlideOuts([nodesSlideout], activeTabRightGraphKey); // } // }); // // $('#relationshipsTab').on('click', function() { // if (relationshipsSlideout.position().left === $(window).width()) { // Structr.closeSlideOuts([nodesSlideout], activeTabRightGraphKey); // Structr.openSlideOut(relationshipsSlideout, this, activeTabRightGraphKey, function() { // console.log('Rels opened'); // }); // } else { // Structr.closeSlideOuts([relationshipsSlideout], activeTabRightGraphKey); // } // }); if (activeTabLeftGraph) { $('#' + activeTabLeftGraph).addClass('active').click(); } if (activeTabRightGraph) { $('#' + activeTabRightGraph).addClass('active').click(); } queriesSlideout.append('
' + '
'); queriesSlideout.append('
' + '
'); queriesSlideout.append('

Cypher Parameters

'); _Graph.appendCypherParameter($('#cypher-params')); $('#clear-graph').on('click', function() { _Graph.clearGraph(); }); $('#exec-rest').on('click', function() { var query = $('.search[name=rest]').val(); if (query && query.length) { _Graph.execQuery(query, 'rest'); } }); $('#exec-cypher').on('click', function() { var query = $('.search[name=cypher]').val(); var params = {}; var names = $.map($('[name="cyphername[]"]'), function(n) { return $(n).val(); }); var values = $.map($('[name="cyphervalue[]"]'), function(v) { return $(v).val(); }); for (var i = 0; i < names.length; i++) { params[names[i]] = values[i]; } if (query && query.length) { _Graph.execQuery(query, 'cypher', JSON.stringify(params)); } }); $('#add-cypher-parameter').on('click', function() { _Graph.appendCypherParameter($('#cypher-params')); }); _Graph.activateClearSearchIcon(); queriesSlideout.append('

Saved Queries

'); _Graph.listSavedQueries(); //_Graph.restoreSavedQuery(0); searchField = $('.search', queriesSlideout); searchField.focus(); searchField.keydown(function(e) { var rawSearchString = $(this).val(); var searchString = rawSearchString; var self = $(this); var type = self.attr('name'); if (type !== 'cypher') { var type; var posOfColon = rawSearchString.indexOf(':'); if (posOfColon > -1) { type = rawSearchString.substring(0, posOfColon); type = type.capitalize(); searchString = rawSearchString.substring(posOfColon + 1, rawSearchString.length); } } if (searchString && searchString.length) { _Graph.activateClearSearchIcon(type); } else { _Graph.clearSearch(type); } if (searchString && searchString.length && e.which === 13) { //console.log('Search executed', searchString, type); if (!shiftKey) { _Graph.execQuery(searchString, type); return false; } } else if (e.which === 27 || rawSearchString === '') { _Graph.clearSearch(type); } }); win.off('resize'); win.resize(function() { _Graph.resize(); }); Structr.unblockMenu(100); }, execQuery: function(query, type, params) { //console.log('exec', type, 'query: ', query, ', with parameters.', params); if (query && query.length) { if (type === 'cypher') { Command.cypher(query.replace(/(\r\n|\n|\r)/gm, ''), params, _Graph.processQueryResults); _Graph.saveQuery(query, 'cypher', params); } else { Command.rest(query.replace(/(\r\n|\n|\r)/gm, ''), _Graph.processQueryResults); _Graph.saveQuery(query, 'rest'); } _Graph.listSavedQueries(); } }, processQueryResults: function (results) { // console.log('query results: ', results); var nodes = []; var rels = []; $(results).each(function (i, entity) { if (entity.hasOwnProperty('relType')) { rels.push(entity); } else { nodes.push(entity); } }); nodes.forEach(function (entity) { StructrModel.createSearchResult(entity); }); rels.forEach(function (entity) { StructrModel.createSearchResult(entity); }); if (engine) { _Graph.resize(); _Graph.scheduleRefreshEngine(); } }, saveQuery: function(query, type, params) { var savedQueries = JSON.parse(LSWrapper.getItem(savedQueriesKey)) || []; var exists = false; $.each(savedQueries, function(i, q) { if (q.query === query && q.params === params) { exists = true; } }); if (!exists) { savedQueries.unshift({'type': type, 'query': query, 'params': params}); LSWrapper.setItem(savedQueriesKey, JSON.stringify(savedQueries)); Structr.saveLocalStorage(); } }, removeSavedQuery: function(i) { var savedQueries = JSON.parse(LSWrapper.getItem(savedQueriesKey)) || []; savedQueries.splice(i, 1); LSWrapper.setItem(savedQueriesKey, JSON.stringify(savedQueries)); _Graph.listSavedQueries(); Structr.saveLocalStorage(); }, restoreSavedQuery: function(i, exec) { var savedQueries = JSON.parse(LSWrapper.getItem(savedQueriesKey)) || []; var query = savedQueries[i]; $('.search[name=' + query.type + ']').val(query.query); _Graph.activateClearSearchIcon(query.type); $('#cypher-params input').remove(); $('#cypher-params br').remove(); $('#cypher-params img.remove-cypher-parameter').remove(); if (query.params && query.params.length) { var parObj = JSON.parse(query.params); $.each(Object.keys(parObj), function(i, key) { _Graph.appendCypherParameter($('#cypher-params'), key, parObj[key]); }); } else { _Graph.appendCypherParameter($('#cypher-params')); } if (exec) { _Graph.execQuery(query.query, query.type, query.params); } }, listSavedQueries: function() { $('#saved-queries').empty(); queriesSlideout.append('
'); var savedQueries = JSON.parse(LSWrapper.getItem(savedQueriesKey)) || []; $.each(savedQueries, function(q, query) { if (query.type === 'cypher') { $('#saved-queries').append('
Cypher Query' + query.query + '
'); } else { $('#saved-queries').append('
REST Query' + query.query + '
'); } }); $('.saved-query').on('click', function() { _Graph.restoreSavedQuery($(this).index()); }); $('.replay').on('click', function() { _Graph.restoreSavedQuery($(this).parent().index(), true); }); $('.remove-query').on('click', function() { _Graph.removeSavedQuery($(this).parent().index()); }); }, activateClearSearchIcon: function(type) { var icon = $('#clear-' + type); icon.show().on('click', function() { $(this).hide(); $('.search[name=' + type + ']').val('').focus(); }); }, clearSearch: function(type) { $('#clear-' + type).hide().off('click'); $('.search[name=' + type + ']').val('').focus(); }, clearGraph: function() { //console.log('clearGraph'); colors = []; relTypes = {}; nodeTypes = {}; //nodeColors = {}; //relColors = {}; nodeIds = []; relIds = []; hiddenNodeTypes = []; hiddenRelTypes = []; engine.graph.clear(); engine.refresh(); //engine = undefined; }, unload: function() { //console.log('unload graph'); _Graph.clearGraph(); }, loadRelationships: function(nodeId) { if (nodeId) { $.ajax({ url: rootUrl + nodeId + '/out?pageSize=' + maxRels, dataType: "json", //async: false, success: function(data) { if (!data || data.length === 0 || !data.result || !data.result.length) { return; } var results = data.result; var count = 0, i = 0; while (i < results.length && count < maxRels) { var r = results[i++]; if (relIds.indexOf(r.id) === -1) { _Graph.loadRelationship(r); } } _Graph.scheduleRefreshEngine(); } }); $.ajax({ url: rootUrl + nodeId + '/in?pageSize=' + maxRels, dataType: "json", //async: false, success: function(data) { if (!data || data.length === 0 || !data.result || !data.result.length) { return; } var results = data.result; var count = 0, i = 0; while (i < results.length && count < maxRels) { var r = results[i++]; if (relIds.indexOf(r.id) === -1) { _Graph.loadRelationship(r); } } _Graph.scheduleRefreshEngine(); } }); } }, loadNode: function(nodeId, callback) { //console.log('loadNode', nodeId, callback); if (nodeId) { if (isIn(nodeId, nodeIds)) { if (callback) { callback(); } } else { Command.get(nodeId, function(n) { _Graph.drawNode(n); if (callback) { callback(); } }); } } }, loadRelationship: function(rel) { //console.log('loadRelationship', rel); _Graph.loadNode(rel.sourceId, function() { _Graph.loadNode(rel.targetId, function() { _Graph.drawRel(rel); }); }); }, findRelationships: function(sourceId, targedId, relType) { var edges = []; engine.graph.edges().forEach(function(edge) { if (edge.source === sourceId && edge.target === targedId && (!relType || edge.relType === relType)) { edges.push(edge); } }); return edges; }, drawNode: function(node, x, y) { if (isIn(node.id, nodeIds) || isIn(node.type, filteredNodeTypes)) { return; } nodeIds.push(node.id); _Graph.setNodeColor(node); //console.log('drawing node', node, nodeTypes[node.type], isIn(node.type, hiddenNodeTypes)); engine.graph.addNode({ id: node.id || node.name, label: (node.name || node.tag || node.id.substring(0, 5) + '…') + ':' + node.type, x: x || Math.random(10), y: y || Math.random(10), size: 20, color: nodeColors[node.type], type: node.type, name: node.name, hidden: isIn(node.type, hiddenNodeTypes) }); //_Graph.scheduleRefreshEngine(); //_Graph.updateNodeTypes(); }, drawRel: function(r) { if (isIn(r.id, relIds) || (!isIn(r.sourceId, nodeIds) || !isIn(r.targetId, nodeIds)) ) { return; } relIds.push(r.id); _Graph.setRelationshipColor(r); //var existingEdges = _Graph.findRelationships(r.sourceId, r.targetId, r.relType); var existingEdges = _Graph.findRelationships(r.sourceId, r.targetId); var c = existingEdges.length * 15; //console.log('Found existing edges:', r, existingEdges, c); engine.graph.addEdge({ id: r.id, label: r.relType, source: r.sourceId, target: r.targetId, size: 40, color: defaultRelColor, type: edgeType, relType: r.relType, hidden: isIn(r.relType, hiddenRelTypes), count: c }); _Graph.scheduleRefreshEngine(); _Graph.updateRelationshipTypes(); }, updateNode: function(node, obj) { if (!node) { node = engine.graph.nodes(obj.id); } if (obj.name) { node.name = obj.name; } if (obj.id) { node.id = obj.id; } if (obj.tag) { node.tag = obj.tag; } node.label = (node.name || node.tag || node.id.substring(0, 5) + '…') + ':' + node.type; if (obj.type) { node.type = obj.type; } _Graph.scheduleRefreshEngine(); }, resize: function() { Structr.resize(); var windowHeight = win.height(); var offsetHeight = 360; $('#saved-queries').css({ height: windowHeight - offsetHeight + 'px' }); var ch = win.height() - 61; graph.css({ height: ch, width: win.width() }); $('canvas', graph).css({ height: ch, width: win.width() }); nodeTypes = $('#node-types'); var distance = nodeTypes.position().top - 61; var boxHeight = (ch - (3 * distance)) / 2; nodeTypes.css({ height: boxHeight }); $('#relationship-types').css({ top: nodeTypes.position().top + boxHeight + distance, height: boxHeight }); if (engine) { _Graph.scheduleRefreshEngine(); } }, loadTypeDefinition: function(type, callback) { var url = rootUrl + '_schema/' + type; $.ajax({ url: url, dataType: 'json', contentType: 'application/json; charset=utf-8', //async: false, statusCode: { 200: function(data) { if (callback) { callback(data.result[0]); } }, 401: function(data) { console.log(data); }, 404: function(data) { console.log(data); }, 422: function(data) { console.log(data); } } }).always(function(data) { if (callback) { callback(data.result[0]); } }); }, updateNodeTypes: function() { var nodeTypesBox = $('#node-types'); fastRemoveAllChildren(nodeTypesBox[0]); // getByType: function(type, pageSize, page, sort, order, properties, includeDeletedAndHidden, callback) { Command.getSchemaInfo(function(nodes) { nodes.sort(function(a, b) { var aName = a.name.toLowerCase(); var bName = b.name.toLowerCase(); return aName < bName ? -1 : aName > bName ? 1 : 0; }); nodes.forEach(function(node) { var hide = false; if (!displayCustomTypes && node.className.startsWith('org.structr.dynamic')) hide = true; if (!hide && !displayCoreTypes && node.className.startsWith('org.structr.core.entity')) hide = true; if (!hide && !displayHtmlTypes && node.className.startsWith('org.structr.web.entity.html')) hide = true; if (!hide && !displayUiTypes && node.className.startsWith('org.structr.web.entity') && !(displayHtmlTypes && node.className.startsWith('org.structr.web.entity.html'))) hide = true; if (!hide && !displayLogTypes && node.className.startsWith('org.structr.rest.logging.entity')) hide = true; if (!hide && !displayOtherTypes && node.className.startsWith('org.structr.xmpp')) hide = true; //console.log(hide, node.type); if (hide) { filteredNodeTypes.push(node.type); return; } else { filteredNodeTypes.splice(filteredNodeTypes.indexOf(node.type), 1); } //console.log(filteredNodeTypes); schemaNodes[node.type] = node; schemaNodesById[node.id] = node; // expand comma-separated list into real collection if (schemaNodes[node.type].possibleSourceTypes) { schemaNodes[node.type].possibleSourceTypes = schemaNodes[node.type].possibleSourceTypes.split(","); } // expand comma-separated list into real collection if (schemaNodes[node.type].possibleTargetTypes) { schemaNodes[node.type].possibleTargetTypes = schemaNodes[node.type].possibleTargetTypes.split(","); } var nodeType = node.name; if (!isIn(nodeType, Object.keys(nodeColors))) { nodeColors[nodeType] = colors[color++]; } //Object.keys(nodeColors).forEach(function (nodeType) { nodeTypesBox.append('
' + nodeType + '
'); var nt = $('#node-type-' + nodeType, nodeTypesBox); if (isIn(nodeType, hiddenNodeTypes)) { nt.attr('data-hidden', 1); nt.addClass('hidden-node-type'); console.log('nodeType is hidden', nodeType); } nt.on('mousedown', function() { var nodeTypeEl = $(this); nodeTypeEl.css({pointer: 'move'}); //_Graph.toggleNodeType(nodeType); }).on('click', function() { // TODO: Query }).on('mouseover', function() { _Graph.highlightNodeType(nodeType); }).on('mouseout', function() { _Graph.unhighlightNodeType(nodeType); }).draggable({ helper: 'clone' }); $('.toggle-type', nt).on('click', function() { var n = $(this); if (n.attr('data-hidden')) { _Graph.showNodeType(nodeType, function() { n.removeAttr('data-hidden', 1); //n.removeClass('hidden-node-type'); }); } else { _Graph.hideNodeType(nodeType, function() { n.attr('data-hidden', 1); //n.addClass('hidden-node-type'); }); } }); }); _Graph.filterNodeTypes(filteredNodeTypes); _Graph.resize(); }); }, filterNodeTypes: function(types, callback) { types.forEach(function(type) { engine.graph.nodes().forEach(function(node) { if (node.type === type) { //console.log(type, node.type, node); engine.graph.dropNode(node.id); //try { engine.graph.dropNode(node); } catch(x) {} } }); }); _Graph.refreshEngine(); if (callback) { callback(); } //console.log(hiddenNodeTypes); }, hideNodeType: function(type, callback) { engine.graph.nodes().forEach(function(node) { if (node.type === type) { node.hidden = true; } }); hiddenNodeTypes.push(type); _Graph.refreshEngine(); if (callback) { callback(); } //console.log(hiddenNodeTypes); }, showNodeTypes: function(types, callback) { types.forEach(function(type) { engine.graph.nodes().forEach(function(node) { if (node.type === type) { node.hidden = false; } }); hiddenNodeTypes.splice(hiddenNodeTypes.indexOf(type), 1); }); _Graph.refreshEngine(); if (callback) { callback(); } //console.log(hiddenNodeTypes); }, showNodeType: function(type, callback) { engine.graph.nodes().forEach(function(node) { if (node.type === type) { node.hidden = false; } }); hiddenNodeTypes.splice(hiddenNodeTypes.indexOf(type), 1); _Graph.refreshEngine(); if (callback) { callback(); } //console.log(hiddenNodeTypes); }, highlightNodeType: function(type) { engine.graph.nodes().forEach(function(node) { if (node.type === type) { node.oldColor = node.color; node.color = colorLuminance(node.color, -.2); } }); //_Graph.scheduleRefreshEngine(); }, unhighlightNodeType: function(type) { engine.graph.nodes().forEach(function(node) { if (node.type === type) { node.color = node.oldColor; } }); //_Graph.scheduleRefreshEngine(); }, setNodeColor: function(node) { if (!isIn(node.type, Object.keys(nodeColors))) { node.color = colors[color++]; //console.log(typeDef.type, typeDef.color, color); nodeColors[node.type] = node.color; } else { node.color = nodeColors[node.type]; } }, setRelationshipColor: function(rel) { //console.log('setRelColor', rel); if (!isIn(rel.relType, Object.keys(relColors))) { rel.color = colors[color++]; //console.log(typeDef.type, typeDef.color, color); relColors[rel.relType] = rel.color; } else { rel.color = relColors[rel.relType]; } }, updateRelationshipTypes: function() { var relTypesBox = $('#relationship-types'); relTypesBox.empty(); //console.log(relColors); Object.keys(relColors).forEach(function(relType) { relTypesBox.append('
' + relType + '
'); var rt = $('#rel-type-' + relType, relTypesBox); if (isIn(relType, hiddenRelTypes)) { rt.attr('data-hidden', 1); rt.addClass('hidden-node-type'); } rt.on('mousedown', function() { var relTypeEl = $(this); relTypeEl.css({pointer: 'move'}); //_Graph.toggleNodeType(nodeType); }).on('click', function() { var n = $(this); if (n.attr('data-hidden')) { _Graph.showRelType(relType, function() { n.removeAttr('data-hidden', 1); n.removeClass('hidden-node-type'); }); } else { _Graph.hideRelType(relType, function() { n.attr('data-hidden', 1); n.addClass('hidden-node-type'); }); } }).on('mouseover', function() { _Graph.highlightRelationshipType(relType); }).on('mouseout', function() { _Graph.unhighlightRelationshipType(relType); }); }); }, highlightRelationshipType: function(type) { engine.graph.edges().forEach(function(edge) { if (edge.relType === type) { edge.oldColor = edge.color; edge.color = colorLuminance(edge.color, -.2); } }); //_Graph.scheduleRefreshEngine(); }, unhighlightRelationshipType: function(type) { engine.graph.edges().forEach(function(edge) { if (edge.relType === type) { edge.color = edge.oldColor; } }); //_Graph.scheduleRefreshEngine(); }, hideRelType: function(type, callback) { engine.graph.edges().forEach(function(edge) { if (edge.relType === type) { edge.hidden = true; } }); hiddenRelTypes.push(type); _Graph.scheduleRefreshEngine(); if (callback) { callback(); } }, showRelType: function(type, callback) { engine.graph.edges().forEach(function(edge) { if (edge.relType === type) { edge.hidden = false; } }); hiddenRelTypes.splice(hiddenRelTypes.indexOf('type'), 1); _Graph.scheduleRefreshEngine(); if (callback) { callback(); } }, appendCypherParameter: function(el, key, value) { el.append('
'); $('.remove-cypher-parameter', el).on('click', function() { $(this).parent().remove(); }); }, scheduleRefreshEngine: function() { window.clearTimeout(refreshTimeout); refreshTimeout = window.setTimeout(_Graph.refreshEngine, 100); }, refreshEngine: function() { hasDoubleClicked = false; hasDragged = false; engine.refresh(); }, distance: function(n1, n2) { var x1 = parseInt(n1['renderer1:x']); var y1 = parseInt(n1['renderer1:y']); var x2 = parseInt(n2['renderer1:x']); var y2 = parseInt(n2['renderer1:y']); var d = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); //console.log(x1,y2, x2,y2, d); return d; } }; function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min)) + min; } function colorLuminance(hex, lum) { hex = String(hex).replace(/[^0-9a-f]/gi, ''); lum = lum || 0; if (hex.length < 6) { hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; } // convert to decimal var r = convertToDec(hex.substr(0, 2)), g = convertToDec(hex.substr(2, 2)), b = convertToDec(hex.substr(4, 2)); // desaturate var rgb = desaturate(r, g, b, .5); // change luminosity var newHex = "#", c, i; for (i = 0; i < 3; i++) { c = rgb[i]; c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16); newHex += ("00" + c).substr(c.length); } return newHex; } function convertToDec(hex) { return parseInt(hex, 16); } function desaturate(r, g, b, k) { var intensity = 0.3 * r + 0.59 * g + 0.11 * b; r = Math.floor(intensity * k + r * (1 - k)); g = Math.floor(intensity * k + g * (1 - k)); b = Math.floor(intensity * k + b * (1 - k)); return [r, g, b]; } function doLayout(num) { running = true; restartLayout(num); } function restartLayout(num) { window.setTimeout(function() { animating = true; sigma.layouts.fruchtermanReingold.start(engine, { autoArea: false, area: 1000000000, gravity: 0, speed: 0.1, iterations: 1000 }); animating = false; if (count++ < num) { restartLayout(num); } else { count = 0; } }, 20); }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy