- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试将 localStorage 与我的力导向图一起使用。我在每个 simulation.on("end", function())
中都保存了 graph
变量,这可以正常工作。但是,当我重新加载页面时,使用 localStorage.getItem
并拖动节点,然后链接不再与节点连接。
你能帮我解决这个奇怪的问题吗?
请查看下面的截图和代码: localStorage-update-screenshot
'use strict';
var test = [];
var datatable;
var index = [];
var graph;
getLocal();
// load and save data
function getLocal() {
if (localStorage.getItem("graph") === null) {
graph = {
"nodes": [{'id': 1, 'lable': 1, 'group': 'search'}, {'id': 2, 'lable': 2, 'group': '1'}, {'id': 3, 'lable': 3, 'group': '2'}],
"links": [{'source': 1, 'target': 2, 'value': "1-2"},{'source': 2, 'target': 1, 'value': "2-1"},{'source': 1, 'target': 3, 'value': "1-3"},{'source': 2, 'target': 3, 'value': "2-3"}]
}} else {
graph = JSON.parse(localStorage.getItem("graph"));
};
};
// Graph variables
var firstLinks = true;
var w = 1680; //window.innerWidth;
var h = 850; //window.innerHeight;
var svg = d3.select("#svgData"),
scheme = ['#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#ffff33','#a65628','#f781bf','#999999'],
width = +svg.attr(w),
height = +svg.attr(h),
color = d3.scaleOrdinal(d3.schemeCategory10);
//color = d3.scaleOrdinal(scheme);
// elements for data join
var link = svg.append("g").attr("class", "link").selectAll(".link"),
value = svg.append("g").selectAll(".link"),
node = svg.append("g").attr("class", "node").selectAll(".node"),
lable = svg.append("g").selectAll(".node"),
image = svg.append("g").selectAll(".node");
// simulation initialization
var simulation = d3.forceSimulation()
.force("charge", d3.forceManyBody().strength(-30).distanceMax(300))
//.force('collision', d3.forceCollide().radius(30))
//.force("center", d3.forceCenter(w / 2, h / 2))
.force("link", d3.forceLink().id(function(d) { return d.id; }).distance(function (d) { if (d.length) {return d.length; } else { return 300;}}))
.force("x", d3.forceX().x(function(d) { if (d.group == "search") {return w / 2; } else { return " ";}}))
.force("y", d3.forceY().y(function(d) { if (d.group == "search") {return h / 2; } else { return h / 3;}}));
//.force("center", d3.forceCenter(w / 2, h / 2));
var marker = d3.select("#svgData").append('defs')
.append('marker')
.attr("id", "Triangle")
.attr('viewBox', '-0 -5 10 10')
.attr("refX", 25)
.attr("refY", 0)
.attr("markerUnits", 'userSpaceOnUse')
.attr("orient", 'auto')
.attr("markerWidth", 13)
.attr("markerHeight", 13)
.attr('xoverflow', 'visible')
.append('path')
.attr("d", 'M 0,-5 L 10 ,0 L 0,5');
// Add search result to graph data
function QuickSearch(value) {
var new_node = {};
new_node = {'id': value, 'lable': value, 'group': 'search'};
graph.nodes.findIndex(x => x.id == new_node.id) == -1 ? graph.nodes.push(new_node) : console.log("object already exists")
update();
};
update();
function update() {
// DATA JOIN
link = link.data(graph.links, d => d.id);
// EXIT
// Remove old links
link.exit().remove();
// ENTER
// Create new links as needed.
link = link.enter().append("path")
.attr("id", function(_, i) {
return "path" + i
})
.attr("marker-end", "url(#Triangle)")
.merge(link);
// DATA JOIN
value = value.data(graph.links, d => d.id);
// EXIT
value.exit().remove();
// ENTER
value = value.enter().append("text")
.attr("dy", -4)
.append("textPath")
.attr("xlink:href", function(_, i) {
return "#path" + i
})
.attr("startOffset", "50%")
.text(function(d) {
return d.value;
})
.merge(value);
// DATA JOIN
node = node.data(graph.nodes, d => d.id);
// EXIT
node.exit().remove();
// ENTER
node = node.enter().append("circle")
.attr('stroke-width', 3)
.attr('stroke', function(d) { if (d.group == "addr") {return '#1f77b4'; } else {return color(d.group)}})
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.merge(node);
// DATA JOIN
lable = lable.data(graph.nodes, d => d.id);
// EXIT
lable.exit().remove();
// ENTER
lable = lable.enter().append("text")
.text(function (d) {
if(d.id.length > 10)
return d.id.substring(0,10)+'...';
else
return d.id;
})
.merge(lable);
// Set nodes, links, and alpha target for simulation
simulation.nodes(graph.nodes).on("tick", ticked);
simulation.force("link").links(graph.links).distance(function (d) { if (d.length) {return d.length; } else { return 200;}});
simulation.alphaTarget(1).restart();
simulation.on("end", function() {
node.each(function(d) {
d.fx = d.x;
d.fy = d.y;
});
localStorage.setItem("graph", JSON.stringify(graph));
console.log("saving");
});
function ticked() {
node
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
lable
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y - 30; });
link
.attr("d", function(d) {
return "M" + d.source.x + "," + d.source.y
+ "L" + d.target.x + "," + d.target.y;
})
.attr("stroke-dasharray", function() {
return this.getTotalLength() - 25;
});
value
.attr("x", function(d) { return (d.source.x + d.target.x)/2; })
.attr("y", function(d) { return ((d.source.y + d.target.y)/2) - 10; });
}
// Zoom
var zoom = d3.zoom()
.scaleExtent([0, 10])
.on("zoom", zoomed);
d3.select("#svgData").call(zoom);
function zoomed() {
const currentTransform = d3.event.transform;
svg.selectAll("g").attr("transform", currentTransform);
}
function slided(d) {
zoom.scaleTo(svg, d3.select(this).property("value"));
}
// drag nodes
function dragstarted(d){
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d){
d.fx = d3.event.x;
d.fy = d3.event.y;
//fix_nodes(d);
}
function dragended(d){
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = d.x;
d.fy = d.y;
}
// Preventing other nodes from moving while dragging one node
function fix_nodes(this_node) {
node.each(function(d) {
if (this_node != d) {
d.fx = d.x;
d.fy = d.y;
}
});
}
};
var deleteLeafs = function() {
var source = [];
var target = [];
link.each(function (d) {
source.push(d.source.index);
target.push(d.target.index);
});
node.each(function (d, i) {
if (i in source && i in target ) {
index.push(d);
}
})
};
最佳答案
D3-force 将链接中的源和目标属性从给定节点的某个标识符替换为节点的对象引用本身。因此,所有链接都由源对象和目标对象引用组成,节点对象引用自身。
使用 JSON.parse 和 JSON.stringify 存储/重新创建数据不会导致链接和节点共享对象引用的对象:节点和链接包含对不同对象的对象引用(即使它们看起来相同) :
下面查看链接源是否与节点相同,它是在力初始化之后,但在解析和字符串化之后不是。
var graph = {
nodes: [
{id: 1},
{id: 2}
],
links : [
{source: 1, target: 2}
]
}
var force = d3.forceSimulation()
.nodes(graph.nodes)
.force("link", d3.forceLink().id(d=>d.id).links(graph.links));
// force only:
console.log(graph.nodes[0] == graph.links[0].source);
// parsed:
graph = JSON.parse(JSON.stringify(graph))
console.log(graph.nodes[0] == graph.links[0].source);
// For comparison:
console.log("graph.nodes[0]:")
console.log(graph.nodes[0])
console.log("graph.links[0].source:")
console.log(graph.links[0].source)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
如果您只是创建/删除节点,您可以每次都从起始链接数组重新加载链接,只存储节点。然后,通过重新初始化节点和链接,您应该得到一个新的力布局,其中节点位置(以及链接)位于它们的最后位置。
如果您要添加/删除链接,那么您可以使用另一种解析对象的方法,例如 Flatted ,这似乎适用于强制布局:
var graph = {
nodes: [
{id: 1},
{id: 2}
],
links : [
{source: 1, target: 2}
]
}
var force = d3.forceSimulation()
.nodes(graph.nodes)
.force("link", d3.forceLink().id(d=>d.id).links(graph.links));
// force only:
console.log(graph.nodes[0] == graph.links[0].source);
// parsed:
graph = Flatted.parse(Flatted.stringify(graph))
console.log(graph.nodes[0] == graph.links[0].source);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/flatted@3.1.1/min.js"></script>
关于javascript - D3v4力向图-localStorage断开链接和节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66184275/
是否可以在蓝牙设备连接到 iOS 或从 iOS 断开连接时收到通知,即使我的应用程序处于后台?在 Android 上,我使用 ACTION_ACL_CONNECTED 和 ACTION_ACL_DIS
我对使用 Delphi 使用 USB 设备感到不舒服,并且对编写设备驱动程序的细节几乎一无所知(尽管我在学习使用 GoASM 进行汇编时遇到过一些)。 该设备可以是 USB 调制解调器或 USB 打印
我正在使用 java/servlet 和前端 JSP 开发 Web 应用程序。 我的页面为用户显示一些信息。 是否有任何适当的方法来检查网络连接是否处于 Activity 状态(开/关)以及支持所有浏
这个问题在这里已经有了答案: C# -- TcpListener.Start() causing SocketException with message "Only one usage of ea
我想向我的应用程序添加功能,以允许在 Windows 操作系统上检测播放/捕获设备的到达和断开连接。就像在 Skype 中一样 - 当您拔下设备时 - 它会显示设备丢失的通知,例如要求您选择另一个。
如何断开 org. apache. http. client.HttpClient 对象? 我正在这样创建它,但它没有任何 disconnect() 或 getHttpConnectionManage
我们正在开发一个 .NET 应用程序,其中一个要求是监视系统是否连接到 Internet。 我们能够获得“以太网电缆断开连接”的 .NET 事件,但如果调制解调器被重置,则不会触发此事件。我不想一直通
我正在尝试与使用自签名证书的后端服务器建立 websocket 连接。在 Firefox 中,我为自签名证书添加了一个异常(exception)。 但是我的 websocket 连接 wss://连接
我正在使用由 Excel 生成的用户窗体来修改 PowerPoint 演示文稿(这是避免需要启用宏的电子表格的迂回方法)。该表单工作得很好,但每次我将焦点放在它上时,Excel 应用程序都会获得焦点(
您好,我成功地开始了视频通话,但是当我断开视频通话时,摄像头 LED 指示灯仍然亮着。我怎样才能完全断开通话? Video.createLocalVideoTrack().then(track =>
您好,我成功地开始了视频通话,但是当我断开视频通话时,摄像头 LED 指示灯仍然亮着。我怎样才能完全断开通话? Video.createLocalVideoTrack().then(track =>
我正在尝试断开客户端与服务器的连接,但服务器仍将其视为已连接。我找不到解决这个问题的方法,关机、断开连接和关闭都不起作用。 我与客户端断开连接并检查服务器的一些代码: 客户: private vo
我正在使用 magic record 来完成我所有的核心数据工作。 一切都很好,除了有时我在后台进行更新时我需要从上下文中分离或断开实体。 例如 ButtonList = [Buttons MR_fi
我正在尝试实现一个颜色选择器,它从屏幕上各处的像素中获取颜色。为此,我计划使用全局鼠标 Hook 来监听 WM_MOUSEMOVE,以便在鼠标四处移动时更新颜色,并监听鼠标点击以确认 (WM_LBUT
我有一个使用 C# 编写的 TLS 连接的客户端/服务器 TCP 场景。 客户端在安静并恢复后无法传递消息(不活动时间约为 25 分钟)。但如果我让客户聊天(每 30 秒),就没有问题。 客户端和服务
我编写的这段代码完美运行,但我担心每 2 秒执行一次 ping 操作会消耗太多资源,或者可能导致互联网连接出现一些问题。 new Thread(() => {
关闭带有附加 MediaPlayer 的 MediaController 的正确方法是什么? 您不能执行 mediaController.setMediaPlayer(null) - 立即调用 upd
从我的笔记本电脑上断开外接显示器后,我丢失了一些应用程序,因为断开连接的显示器仍设置为默认显示器。我的一些窗口试图在断开连接的显示器上显示。 我有一个解决方法,例如右键单击应用程序图标并选择移动,然后
是否可以将分片节点从分片集中取出并独立运行? 例如,每个分片都有一个特定的客户。 谢谢。 最佳答案 是的,这是可能的。 MongoDB“主”节点不知道分片。只有路由器(和配置服务器)知道。如果您使用正
我正在探索 Cassandra 及其复制系统。为此,我在本地创建了 3 个节点并测试了不同的场景。我想暂停节点之间的通信,用相同的键写入不同的值,然后观察它们将决定什么。 那么问题来了:如何限制节点在
我是一名优秀的程序员,十分优秀!