强制有向图和本地存储
Forced-Directed Graph and localstorage
我试图在localStorage中拖放后存储节点位置,但当我重新加载页面时,链接是我保存它们的地方,节点也是,但链接和节点没有链接,所以节点只是离开了它们的初始位置。
这是我的代码,我使用的是angular。
angular.module('core').controller('HomeController', ['$scope',
function($scope) {
$scope.graph = {
width : 500,
height : 400,
color : d3.scale.category20(),
force : '',
drag : '',
dragstart : function(d) {
d.x = d3.event.x;
d.y = d3.event.y;
},
dragend : function(d) {
var graphTmp = { "nodes" : $scope.graph.node.data(), "links" : $scope.graph.link.data()};
localStorage.setItem('graph',JSON.stringify(graphTmp));
},
link : [],
node : [],
links : [],
nodes : []
};
$scope.svg = d3.select("body").append("svg")
.attr("width", $scope.graph.width)
.attr("height", $scope.graph.height);
$scope.savedGraph = {};
$scope.draw = function(){
$scope.graph.force = d3.layout.force()
.charge(-120)
.linkDistance(30)
.size([$scope.graph.width, $scope.graph.height]);
$scope.graph.force
.nodes($scope.graph.nodes)
.links($scope.graph.links)
.start();
$scope.graph.link = $scope.svg.selectAll(".link")
.data($scope.graph.links)
.enter().append("line")
.attr("class", "link")
.style({'stroke' : 'gray', 'stroke-width' : '1px'});
$scope.graph.drag = $scope.graph.force.drag()
.on("dragstart", $scope.graph.dragstart)
.on("dragend", $scope.graph.dragend);
$scope.graph.node = $scope.svg.selectAll(".node")
.data($scope.graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 5)
.style("fill", function(d) { return $scope.graph.color(d.group); })
.call($scope.graph.drag);
$scope.graph.node
.append("title")
.text(function(d) { return d.name; });
$scope.graph.force.on("tick", function() {
$scope.graph.link
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
$scope.graph.node
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
};
if(localStorage.getItem('graph') === null){
$scope.graph.nodes = [
{"name":"Myriel","group":1},
{"name":"Napoleon","group":1},
{"name":"Mlle.Baptistine","group":1},
{"name":"Mme.Magloire","group":1},
{"name":"CountessdeLo","group":1},
{"name":"Geborand","group":1},
{"name":"Champtercier","group":1},
{"name":"Cravatte","group":1},
{"name":"Count","group":1}
];
$scope.graph.links = [
{"source":1,"target":0,"value":1},
{"source":2,"target":0,"value":8},
{"source":3,"target":0,"value":10},
{"source":3,"target":2,"value":6},
{"source":4,"target":0,"value":1}
];
$scope.draw();
}
else {
var graphTmp = $.parseJSON(localStorage.getItem('graph'));
$scope.graph.links = graphTmp.links;
$scope.graph.nodes = graphTmp.nodes;
$scope.draw();
}
有人知道为什么吗?我认为这是因为节点和链接不能只使用node.data()和link_data()数据链接在一起。我可以存储更多的数据吗?
谢谢!
问题是,最初当您加载链接(本地存储中没有数据)时,它具有以下结构:
$scope.graph.links = [{
"source": 1,
"target": 0,
"value": 1
}, {
"source": 2,
"target": 0,
"value": 8
}, {
"source": 3,
"target": 0,
"value": 10
}, {
"source": 3,
"target": 2,
"value": 6
}, {
"source": 4,
"target": 0,
"value": 1
}];
现在,强制布局将使用节点中的源对象替换源索引。
拖动时,保存节点和链接(链接对象将保存源和目标的节点对象)。
现在,当您从本地存储加载并解析链接时,链接源/目标将具有与节点对象不同的对象(因为它是深度克隆的)。
因此,节点上的拖动更改将不会反映在链接源/目标对象上。因此,链接被分离。
这个问题的解决方案是始终将链接的索引形式存储在本地存储中。我在这里通过保留另一个对象initLinks 来做到这一点
$scope.graph.nodes = [{
"name": "Myriel",
"group": 1
}, {
"name": "Napoleon",
"group": 1
}, {
"name": "Mlle.Baptistine",
"group": 1
}, {
"name": "Mme.Magloire",
"group": 1
}, {
"name": "CountessdeLo",
"group": 1
}, {
"name": "Geborand",
"group": 1
}, {
"name": "Champtercier",
"group": 1
}, {
"name": "Cravatte",
"group": 1
}, {
"name": "Count",
"group": 1
}];
$scope.graph.links = [{
"source": 1,
"target": 0,
"value": 1
}, {
"source": 2,
"target": 0,
"value": 8
}, {
"source": 3,
"target": 0,
"value": 10
}, {
"source": 3,
"target": 2,
"value": 6
}, {
"source": 4,
"target": 0,
"value": 1
}];
$scope.graph.initLinks = angular.copy($scope.graph.links);
在保存到本地存储时,我执行此
var graphTmp = {
"nodes": $scope.graph.nodes,
"links": $scope.graph.initLinks
};
localStorage.setItem('graph', JSON.stringify(graphTmp));
当从本地存储加载时,我做这个
var graphTmp = JSON.parse(localStorage.getItem('graph'));
$scope.graph.links = graphTmp.links;
$scope.graph.initLinks = angular.copy(graphTmp.links);
$scope.graph.nodes = graphTmp.nodes;
$scope.draw();
此处的工作代码
希望这能有所帮助!
扩展cyrils
答案,如果链接中有复杂数据。您可能希望用对象引用的索引来替换对象引用本身。则保留所有其他数据。请注意,在我的应用程序中,我将链接数据单独保存在localstorage
中。节点与另一个密钥一起保存。
store(key: string, data: any) {
if (key === 'links') {
// replace all targets and source with indexes, we do not need to serialize the values.
localStorage.setItem(key, JSON.stringify(data, (k, v) => {
if (k === 'source' || k === 'target') {
return v.index;
} else {
return v;
}
}));
} else {
localStorage.setItem(key, JSON.stringify(data));
}
}
相关文章:
- 如何在d3力有向图中最初限制节点数
- 如何在Vis JS有向图中逐个显示节点
- D3有向图中链接动画的速度问题
- D3 AngularJs力有向图
- 在有向图中循环SVG圆
- 强制有向图和本地存储
- 如何使用dagred3.js(javascript库)将点击事件添加到有向图中
- 在Javascript Infovis工具/强制有向图中改变节点形状
- 如何防止力有向图中链接的重叠
- 在d3js的力有向图的链接上显示工具提示
- 缩放到D3强制有向图上的点击节点
- D3力有向图问题:节点堆叠在坐标(0,0)
- 从d3有向图的数组中移除重复的边
- 什么是“价值”?用d3表示力有向图
- 加载JSON对象到D3力有向图
- D3 js力有向图-突出两点之间的路径
- 带有SVG和Javascript的交互式有向图
- 在javascript中从边列表制作有向图
- 为什么我不能得到D3强制有向图链接标签的工作
- D3.js箭头有向图:添加节点/链接的飞行