如何获取连接的mxgraph之间的父子关系

     2023-03-08     204

关键词:

【中文标题】如何获取连接的mxgraph之间的父子关系【英文标题】:How to get the parent child relationship between connected mxgraph 【发布时间】:2019-09-25 10:33:31 【问题描述】:

我正在尝试简化连接 mxgraph 之间的关系

问题:一旦绘制了图表,我正在尝试获得简化的关系。

我正在尝试获取 json 中连接节点之间的关系。

注意:解决方案必须适用于每个绘制状态。

这里是代码笔:

https://codepen.io/eabangalore/pen/pmELpL

我想从上面的代码 sn-p 中得到关系。

预期输出(来自绘制的关系):

[
  "id":0,"parent":"#","text":"A","child":["cid":1,"connectionText":"Bangalore"],
  "id":1,"parent":0,"text":"B","child":["cid":2,"connectionText":""],
  "id":2,"parent":1,"text":"C","child":["cid":null,"connectionText":""]
];

请参考codepen,如下sn-p不工作。

<!--
  Copyright (c) 2006-2013, JGraph Ltd
  
  Dynamic toolbar example for mxGraph. This example demonstrates changing the
  state of the toolbar at runtime.
-->
<html>
<head>
	<title>Toolbar example for mxGraph</title>

	<!-- Sets the basepath for the library if not in same directory -->
  <script type="text/javascript">
    mxBasePath = 'https://jgraph.github.io/mxgraph/javascript/src';
    
    function setGraphData()
      var graphState ="tagName":"mxGraphModel","children":["tagName":"root","children":["tagName":"mxCell","attributes":"id":"0","tagName":"mxCell","attributes":"id":"1","parent":"0","tagName":"mxCell","attributes":"id":"2","value":"A","style":"","vertex":"1","parent":"1","children":["tagName":"mxGeometry","attributes":"x":"271.56251525878906","y":"82.44792175292969","width":"100","height":"40","as":"geometry"],"tagName":"mxCell","attributes":"id":"3","value":"B","style":"","vertex":"1","parent":"1","children":["tagName":"mxGeometry","attributes":"x":"678.2291717529297","y":"106.89236450195312","width":"100","height":"40","as":"geometry"],"tagName":"mxCell","attributes":"id":"4","value":"Bangalore","edge":"1","parent":"1","source":"2","target":"3","children":["tagName":"mxGeometry","attributes":"relative":"1","as":"geometry"],"tagName":"mxCell","attributes":"id":"5","value":"C","style":"","vertex":"1","parent":"1","children":["tagName":"mxGeometry","attributes":"x":"1013.7847747802734","y":"83.55902862548828","width":"100","height":"40","as":"geometry"],"tagName":"mxCell","attributes":"id":"6","edge":"1","parent":"1","source":"3","target":"5","children":["tagName":"mxGeometry","attributes":"relative":"1","as":"geometry"]]];
      
      localStorage.setItem('graphState',JSON.stringify(graphState));
    
    
    	function html2json(html)
		if(html.nodeType==3)
			return 
				"tagName":"#text",
				"content":html.textContent
			
		
		var element = 
			"tagName":html.tagName
		;

		if(html.getAttributeNames().length>0)
			element.attributes = html.getAttributeNames().reduce(
				function(acc,at)acc[at]=html.getAttribute(at); return acc;,
				
			);
		

		if(html.childNodes.length>0)
			element.children = Array.from(html.childNodes)
				.filter(
					function(el)
						return el.nodeType!=3
						||el.textContent.trim().length>0
					)
				.map(function(el)return html2json(el););
		
		return element;
	

	function json2html(json)
		var xmlDoc = document.implementation.createDocument(null, json.tagName);

		var addAttributes = function(jsonNode, node)
			if(jsonNode.attributes)
				Object.keys(jsonNode.attributes).map(
					function(name)
						node.setAttribute(name,jsonNode.attributes[name]);
					
				);
			
		

		var addChildren = function(jsonNode,node)
			if(jsonNode.children)
				jsonNode.children.map(
					function(jsonChildNode)
						json2htmlNode(jsonChildNode,node);
					
				);
			
		

		var json2htmlNode = function(jsonNode,parent)
			if(jsonNode.tagName=="#text")
				return xmlDoc.createTextNode(jsonNode.content);
			

			var node = xmlDoc.createElement(jsonNode.tagName);

			addAttributes(jsonNode,node);
			addChildren(jsonNode,node);

			parent.appendChild(node);
		

		addAttributes(json,xmlDoc.firstElementChild);
		addChildren(json,xmlDoc.firstElementChild);

		return xmlDoc;
	
  </script>

  <!-- Loads and initializes the library -->
  <script type="text/javascript" src="https://jgraph.github.io/mxgraph/javascript/src/js/mxClient.js"></script>

	<!-- Example code -->
	<script type="text/javascript">
		// Program starts here. Creates a sample graph in the
		// DOM node with the specified ID. This function is invoked
		// from the onLoad event handler of the document (see below).
		function main()
		
      setGraphData();
			// Checks if browser is supported
			if (!mxClient.isBrowserSupported())
			
				// Displays an error message if the browser is
				// not supported.
				mxUtils.error('Browser is not supported!', 200, false);
			
			else
			
				// Defines an icon for creating new connections in the connection handler.
				// This will automatically disable the highlighting of the source vertex.
				mxConnectionHandler.prototype.connectImage = new mxImage('images/connector.gif', 16, 16);

				// Creates the div for the toolbar
				var tbContainer = document.createElement('div');
				tbContainer.style.position = 'absolute';
				tbContainer.style.overflow = 'hidden';
				tbContainer.style.padding = '2px';
				tbContainer.style.left = '0px';
				tbContainer.style.top = '0px';
				tbContainer.style.width = '24px';
				tbContainer.style.bottom = '0px';
				
				document.body.appendChild(tbContainer);
			
				// Creates new toolbar without event processing
				var toolbar = new mxToolbar(tbContainer);
				toolbar.enabled = false
				
				// Creates the div for the graph
				var container = document.createElement('div');
				container.style.position = 'absolute';
				container.style.overflow = 'hidden';
				container.style.left = '24px';
				container.style.top = '0px';
				container.style.right = '0px';
				container.style.bottom = '0px';
				container.style.background = 'url("editors/images/grid.gif")';

				document.body.appendChild(container);
				
				// Workaround for Internet Explorer ignoring certain styles
				if (mxClient.IS_QUIRKS)
				
					document.body.style.overflow = 'hidden';
					new mxDivResizer(tbContainer);
					new mxDivResizer(container);
				
	
				// Creates the model and the graph inside the container
				// using the fastest rendering available on the browser
				var model = new mxGraphModel();
				var graph = new mxGraph(container, model);

				// Enables new connections in the graph
				graph.setConnectable(true);
				graph.setMultigraph(false);

				// Stops editing on enter or escape keypress
				var keyHandler = new mxKeyHandler(graph);
				var rubberband = new mxRubberband(graph);
				
				var addVertex = function(icon, w, h, style)
				
					var vertex = new mxCell(null, new mxGeometry(0, 0, w, h), style);
					vertex.setVertex(true);
				
					var img = addToolbarItem(graph, toolbar, vertex, icon);
					img.enabled = true;
					
					graph.getSelectionModel().addListener(mxEvent.CHANGE, function()
					
						var tmp = graph.isSelectionEmpty();
						mxUtils.setOpacity(img, (tmp) ? 100 : 20);
						img.enabled = tmp;
					);
				;
				
				addVertex('https://jgraph.github.io/mxgraph/javascript/examples/editors/images/rectangle.gif', 100, 40, '');
				addVertex('https://jgraph.github.io/mxgraph/javascript/examples/editors/images/rounded.gif', 100, 40, 'shape=rounded');
				addVertex('https://jgraph.github.io/mxgraph/javascript/examples/editors/images/ellipse.gif', 40, 40, 'shape=ellipse');
				addVertex('https://jgraph.github.io/mxgraph/javascript/examples/editors/images/rhombus.gif', 40, 40, 'shape=rhombus');
				addVertex('https://jgraph.github.io/mxgraph/javascript/examples/editors/images/triangle.gif', 40, 40, 'shape=triangle');
				addVertex('https://jgraph.github.io/mxgraph/javascript/examples/editors/images/cylinder.gif', 40, 40, 'shape=cylinder');
				addVertex('https://jgraph.github.io/mxgraph/javascript/examples/editors/images/actor.gif', 30, 40, 'shape=actor');
        
        
       				// read state on load 
				if(window.localStorage.graphState)	
					var doc = json2html(JSON.parse(localStorage.graphState));	
					var dec = new mxCodec(doc);
					dec.decode(doc.documentElement, graph.getModel());
				

				// save state on change
				graph.getModel().addListener('change',function()
						var codec = new mxCodec();		
						window.localStorage.graphState = JSON.stringify(html2json(codec.encode(
							graph.getModel()
						)));
				);
			
		

		function addToolbarItem(graph, toolbar, prototype, image)
		
			// Function that is executed when the image is dropped on
			// the graph. The cell argument points to the cell under
			// the mousepointer if there is one.
			var funct = function(graph, evt, cell, x, y)
			
				graph.stopEditing(false);

				var vertex = graph.getModel().cloneCell(prototype);
				vertex.geometry.x = x;
				vertex.geometry.y = y;
					
				graph.addCell(vertex);
				graph.setSelectionCell(vertex);
			
			
			// Creates the image which is used as the drag icon (preview)
			var img = toolbar.addMode(null, image, function(evt, cell)
			
				var pt = this.graph.getPointForEvent(evt);
				funct(graph, evt, cell, pt.x, pt.y);
			);
			
			// Disables dragging if element is disabled. This is a workaround
			// for wrong event order in IE. Following is a dummy listener that
			// is invoked as the last listener in IE.
			mxEvent.addListener(img, 'mousedown', function(evt)
			
				// do nothing
			);
			
			// This listener is always called first before any other listener
			// in all browsers.
			mxEvent.addListener(img, 'mousedown', function(evt)
			
				if (img.enabled == false)
				
					mxEvent.consume(evt);
				
			);
						
			mxUtils.makeDraggable(img, graph, funct);
			
			return img;
		

	</script>
</head>

<!-- Calls the main function after the page has loaded. Container is dynamically created. -->
<body onload="main();" >
</body>
</html>

请帮助我提前谢谢!!!

【问题讨论】:

【参考方案1】:

查看此 CodePen 链接,其中包含您提供的 sn-p 的修改版本。在其中,您可以添加新元素和更改文本,并查看表示图中关系的更新 json 字符串:https://codepen.io/tien-q-nguyen2/pen/GaQXBO

从我第一次发布这个答案时,我还稍微编辑了这个函数。

注意:根据您在原始问题中输入的预期输出,每个顶点元素只有一个父元素(在您给出的示例中为 "id":1,"parent":0

function getNodesFrom(graph)
    var cells = graph.getModel().cells;

    var vertices = [], edges = [];
    for (var key in cells) 
        if (cells[key].isVertex())
            vertices.push(cells[key]);
         
        else if (cells[key].isEdge())
            edges.push(cells[key]);
        
    

    var simpleVertices = [], simpleEdges = [];
    var newIndex = 0;
    var newIndexOf = [];
    vertices.forEach(function(vertex)
        simpleVertices.push(id: newIndex, value: vertex.value);
        newIndexOf[vertex.id] = newIndex++;
    );
    edges.forEach(function(edge)
        if (edge.target === null || edge.source === null) return;
        simpleEdges.push(
            parentId: newIndexOf[edge.source.id], 
            childId: newIndexOf[edge.target.id], 
            value: edge.value
        );
    );

    var edgesForParentIndex = [];
    var edgesForChildIndex = [];
    simpleEdges.forEach(function(edge)
        if (edgesForParentIndex[edge.parentId] === undefined)
            edgesForParentIndex[edge.parentId] = [];
        
        edgesForParentIndex[edge.parentId].push(edge);

        if (edgesForChildIndex[edge.childId] === undefined)
            edgesForChildIndex[edge.childId] = [];
        
        edgesForChildIndex[edge.childId].push(edge);
    );

    var nodes = [];
    simpleVertices.forEach(function(vertex)
        var node = ;
        node.id = vertex.id;
        if (edgesForChildIndex[node.id] === undefined)
            node.parent = '#';
         else 
            node.parent = edgesForChildIndex[node.id][0].parentId;
        
        node.text = (vertex.value === undefined || vertex.value === null) ? '' : vertex.value;
        node.child = [];
        if (edgesForParentIndex[node.id] === undefined)
            node.child.push(cid: null, connectionText: "");
         else 
            edgesForParentIndex[node.id].forEach(function(edge)
                var text = (edge.value === undefined || edge.value === null) ? '' : edge.value;
                node.child.push(cid: edge.childId, connectionText: text);
            );
        
        nodes.push(node);
    );

    return nodes;

【讨论】:

p13获取父子关系的资源

父子关系的资源我们怎么来获取一个公司有多个员工。employee不应该暴露成api,它应该体现出Company和Employee之间的关系。创建EmployeesController复数的形式。继承ControllerBase,并注入两个Repository如果注入为空则抛出异常来我们需要在... 查看详情

如何获取父子表(MS SQL Server/MSAccess)之间的参考信息?

】如何获取父子表(MSSQLServer/MSAccess)之间的参考信息?【英文标题】:Howtogetreferenceinformationbetweenparentandchildtables(MSSQLServer/MSAccess)?【发布时间】:2011-06-1406:28:09【问题描述】:是否可以通过某条记录获取子表是否引用了父表的... 查看详情

仅在父子实体具有 1 到 M 关系的核心数据中获取父实体的数据

】仅在父子实体具有1到M关系的核心数据中获取父实体的数据【英文标题】:FetchonlyParententity\'sdatainCoreDatawhereParentChildentityhas1toMrelationship【发布时间】:2018-04-0807:29:56【问题描述】:我有2个实体。国家和地区。国家与地区之间... 查看详情

对 system() 的调用不会在我的 Windows 进程之间创建父子关系

】对system()的调用不会在我的Windows进程之间创建父子关系【英文标题】:Acalltosystem()doesn\'tcreateaparent-childrelationbetweenmyprocessesinWindows【发布时间】:2012-04-2009:45:41【问题描述】:我正在使用Perl创建Windows服务。为此,我使用Win32::D... 查看详情

如何获取表之间的关系

】如何获取表之间的关系【英文标题】:Howtogetrelationshipbetweentables【发布时间】:2020-07-2912:58:23【问题描述】:您好,我正在为我的组织创建ER图。我怎样才能得到雪花表之间的关系谢谢【问题讨论】:你必须了解数据代表什么... 查看详情

p14获取父子关系的资源

通过CompanyId获取公司下面某一个员工运行测试这个employee的URI比较长返回结果companyId随便改一个这个时候返回了404companyId改回来。然后吧员工id随便改一个还是返回的是404结束  查看详情

进程之间的关系

...的时候、我们使用终端设备进行登录,但是由于终端设备连接的有限,因此登录的用户也就是有限的。随着位映射图形终端变得可用,开发出了窗口系统,它向用户提供了与主机系统进行交互的新方式。在这里、我简单介绍一下... 查看详情

vue父子组件兄弟组件之间的通信和访问

注意:比较复杂的嵌套类的通信问题都建议使用vuex一、父组件->子组件  (1)直接关系:    1.属性传值(props)    2. $children(数组)    3.$refs  (2)跨多层关系:    1. provide/inject二、子组件-&g... 查看详情

从json数据中获取父子关系中所有子节点的总和

】从json数据中获取父子关系中所有子节点的总和【英文标题】:GetsumofAllChildreninparentandchildrelationfromjsondata【发布时间】:2021-12-2607:28:27【问题描述】:我有一个Json数据,它有父、子、孙等关系,就像一棵树他们每个人都有Openin... 查看详情

如何使用 Laravel 获取具有表之间关系的数据

】如何使用Laravel获取具有表之间关系的数据【英文标题】:HowgetdatahavingrelationshipsbetweentablesusingLaravel【发布时间】:2020-06-1309:51:01【问题描述】:我有一个带有Laravel的API,我决定使用表之间的关系,我已经在所有迁移中使用这... 查看详情

如何获取视图之间的mysql依赖关系?

】如何获取视图之间的mysql依赖关系?【英文标题】:Howtoobtainmysqldependenciesbetweenviews?【发布时间】:2013-01-3012:13:03【问题描述】:我有一个mysql数据库,有60多个视图,一些是辅助的,一些是最终的。它们之间存在依赖关系。这... 查看详情

vuejs - 在组件之间共享 websocket 连接

...17-08-1609:44:58【问题描述】:开始使用小型vuejs应用程序。如何在根组件中打开websocket连接并在其他组件中重用相同的连接?我希望组件能够通过同一连接发送和接收。这些组件将绑定到路由,因此根组件和为路由渲染的组件之间... 查看详情

用于获取存储在单个表中的 n 级父子关系的 Postgresql 查询

】用于获取存储在单个表中的n级父子关系的Postgresql查询【英文标题】:Postgresqlqueryforgettingn-levelparent-childrelationstoredinasingletable【发布时间】:2013-01-1713:34:33【问题描述】:我有一个表示父子关系的表。关系可以深入到n级。我使... 查看详情

如何从 Vapor 3 中的 JSON 响应中保存父子关系

】如何从Vapor3中的JSON响应中保存父子关系【英文标题】:HowtosaveParent-ChildrelationfromaJSONresponseinVapor3【发布时间】:2019-10-0919:31:41【问题描述】:我正在使用Vapor3开发一个RESTAPI。此API使用另一个API创建稍后将由应用程序使用的内... 查看详情

如何使用 Fluent API 映射这种冗余的父子关系

】如何使用FluentAPI映射这种冗余的父子关系【英文标题】:HowdoImapthisredundantparent-childrelationshipusingFluentAPI【发布时间】:2015-07-2710:49:01【问题描述】:关于如何双重映射这种父子关系的任何建议,其中父级具有正常的一对多关系... 查看详情

如何使用物料清单的父子记录创建简单的数据关系

】如何使用物料清单的父子记录创建简单的数据关系【英文标题】:HowtocreateasimpledatarelationshipusingparentchildrecordsforaBillofMaterials【发布时间】:2016-12-2120:29:00【问题描述】:我正在尝试开发一个简单的BOM(物料清单)管理器,它... 查看详情

父子链的外连接

】父子链的外连接【英文标题】:outerjoinforparentchildchain【发布时间】:2010-04-1516:29:30【问题描述】:考虑下表和关系:父母--1:Many--孩子--1:Many--子孩子父母可能有或很多没有孩子记录。子项总是有子项记录。我想编写一个查询来... 查看详情

创建骨骼的那些事-如何快速的创建骨骼的父子关系

     我使用的2016的max版本。觉得这个版本的界面我还是很喜欢的。很好分类。     在3dmax中,我们在创建骨骼的父子关系时,在视图中选择时经常会很难选中要建立父子关系的两个骨骼,经常... 查看详情