前端开发框架总结之利用Jtopo实现网络拓扑功能(四)
上文我们讲了拓扑容器相关的交互设计和实现思路以及一些关键技术细节。至此,我们已经覆盖了结点创建、连线创建、容器创建、结点添加等常用场景,本文我们继续我们的拓扑管理开发之旅。
- 拓扑元素序列化
拓扑元素创建好了,位置也摆好了,结点关联关系也建立了,容器分组关系也明确了。接下来就是如何把这些‘辛苦’布局的场景保存下来以便下次就来的时候还能完完整整的看到呢。这时我们就用到了拓扑元素的序列化了。
官网的API中有现成的序列化和反序列方法,我们不妨拿来试下效果。what?序列化方法直接报错?原来是因为我的scene中只设置了backgroundColor,好吧,制作图片,设置backgroud属性,然后再试。what?反序列化后我的容器和连线全不见了。好吧让我们分析下,序列化后的数据。结果发现序列化后的数据中竟然都没有记录连线和结点的关联关系。还有其他好多重要关联数据都没有,怪不得没法反序列化出我们想要的结果呢。好吧,只能实现我们自己的序列化方法了。
首先是确定序列化数据的格式。我采用了官方使用json格式的数据。(js中操作json数据还是很方便的)
然后是确定具体json内容。这个根据各个人的需求确认自己要保存哪些信息。但是大致的层次是不会错的。我这里采用了三大层。第一层为stage的信息,第二层为scene的信息,第三次为拓扑元素的信息,包括node,textnode,link,container。拓扑关系,比如连线、容器等与结点的关系,是使用node的virtualId属性进行关联的。这里有一些小细节要主要处理,但大体思路不难。比如,container的数据结构中就要把为了固定容器四个角的结点和普通结点进行区分开来保存。
js片段,具体属性可以自己丰富。
function getJsonData() {
var data = new Object();
data.stage = new Object();
data.stage.scene = new Object();
data.stage.scene.nodes = [];
data.stage.scene.textNodes = [];
data.stage.scene.links = [];
data.stage.scene.containers = [];
data.stage.wheelZoom = stage.wheelZoom;
var nodeList = scene.find('node');
nodeList.forEach(function (item) {
var node = new Object();
node.bound = item.getBound();
node.type = item.type;
node.fontColor = item.fontColor;
node.text = item.text;
node.deviceId = item.deviceId;
node.elementType = item.elementType;
node.alpha = item.alpha;
node.virtualId = item.virtualId;
data.stage.scene.nodes.push(node);
});
var textNodeList = scene.find('TextNode');
textNodeList.forEach(function (item) {
var textNode = new Object();
textNode.bound = item.getBound();
textNode.font = item.font;
textNode.fontColor = item.fontColor;
textNode.text = item.text;
textNode.elementType = item.elementType;
textNode.alpha = item.alpha;
textNode.virtualId = item.virtualId;
data.stage.scene.textNodes.push(textNode);
});
var linkList = scene.find('link');
linkList.forEach(function (item) {
if(item.nodeA.virtualId && item.nodeZ.virtualId){
var link = new Object();
link.startId = item.nodeA.virtualId;
link.endId = item.nodeZ.virtualId;
link.strokeColor = item.strokeColor;
link.lineWidth = item.lineWidth;
data.stage.scene.links.push(link);
}
});
var containerList = scene.find('container');
containerList.forEach(function (item) {
var container = new Object();
container.text = item.text;
container.bound = item.getBound();
container.borderColor = item.borderColor;
container.borderWidth = item.borderWidth;
container.borderRadius = item.borderRadius; // 圆角
container.fillColor = item.fillColor;
container.alpha = item.alpha;
container.virtualId = item.virtualId;
container.elementType = item.elementType;
container.childs = [];
container.corners = [];
item.childs.forEach(function (child) {
if(child.virtualId == item.virtualId){
var corner = new Object();
corner.bound = child.getBound();
corner.virtualId = item.virtualId;
container.corners.push(corner);
}
else{
var childNode = scene.findElements(function (childNode) {
return childNode.virtualId == child.virtualId;
});
if(childNode && childNode.length > 0){
container.childs.push(child.virtualId);
}
}
});
data.stage.scene.containers.push(container);
});
return JSON.stringify(data);
}
- 拓扑元素反序列化
反序列化的过程主要是Json格式数据协议的解析和拓扑元素的创建。
这里会用到scene查找拓扑结点的方法,另外就是要注意创建顺序就能很好的把之前创建的拓扑图给还原出来。按照Node、Link、Container的顺序来创建就可以了。
直接上代码js
function createTopoFromJson(jsonStr) {
var data = JSON.parse(jsonStr);
if(data){
//设置滚轮缩放比例。
stage.wheelZoom = data.stage.wheelZoom;
//创建Node。
if(data.stage.scene.nodes){
data.stage.scene.nodes.forEach(function (item) {
var node = new JTopo.Node(item.text);
node.setLocation(item.bound.left, item.bound.top);
node.setImage(getImageByType(item.type));
node.setSize(item.bound.width,item.bound.height);
node.fontColor = item.fontColor;
node.addEventListener('mousedrag',nodeMouseDrag);
node.addEventListener('mouseup',nodeMouseUp);
node.addEventListener('dbclick',nodeDbClick);
node.addEventListener('click',nodeClick);
node.deviceId = item.deviceId;
node.type = item.type;
node.virtualId = item.virtualId;
scene.add(node);
});
}
//创建TextNode。
if(data.stage.scene.textNodes){
data.stage.scene.textNodes.forEach(function (item) {
var textNode = new JTopo.TextNode(item.text);
textNode.setLocation(item.bound.left, item.bound.top);
textNode.fontColor = item.fontColor;
textNode.font = item.font;
textNode.alpha = item.alpha;
textNode.virtualId = item.virtualId;
textNode.addEventListener('mousedrag',nodeMouseDrag);
textNode.addEventListener('dbclick',textDbClick);
textNode.addEventListener('mouseup',linkMouseUp);
scene.add(textNode);
});
}
//创建Link。
if(data.stage.scene.links){
data.stage.scene.links.forEach(function (item) {
//查找起点
var nodeA = scene.findElements(function (node) {
return node.virtualId == item.startId;
});
var nodeZ = scene.findElements(function (node) {
return node.virtualId == item.endId;
});
if(nodeA && nodeA.length >0 && nodeZ && nodeZ.length >0){
var link = new JTopo.Link(nodeA[0], nodeZ[0]);
link.lineWidth = item.lineWidth;
link.strokeColor = item.strokeColor;
scene.add(link);
link.addEventListener('mouseup',linkMouseUp);
}
});
}
//创建container。
if(data.stage.scene.containers){
data.stage.scene.containers.forEach(function (item) {
var container = new JTopo.Container(item.text);
container.borderColor = item.borderColor;
container.borderWidth = item.borderWidth;
container.borderRadius = item.borderRadius;
container.fillColor = item.fillColor;
container.alpha = item.alpha;
container.virtualId = item.virtualId;
container.setLocation(item.bound.left, item.bound.top);
item.corners.forEach(function (corner) {
var node = new JTopo.Node();
node.setLocation(corner.bound.left,corner.bound.top);
node.virtualId = corner.virtualId;
container.add(node);
});
scene.add(container);
item.childs.forEach(function (child) {
var node = scene.findElements(function (node) {
return node.virtualId == child;
});
if(node && node.length > 0){
container.add(node[0]);
node[0].removeEventListener('mousedrag');
};
});
container.addEventListener('mouseover',containerMouseOver);
container.addEventListener('mouseup',containerMouseUp);
container.addEventListener('mouseup',linkMouseUp);
});
}
}
}