html - 更新图形布局 d3 库的问题
问题描述
我正在开发一个通过图形表示模式的项目。为了创建图表,我使用以 json 格式托管的数据。可以在链接中看到https://jsfiddle.net/obordies25/d4s12qhn/2/
var width = 960,
height = 500,
resolution = 150,
r = 15;
var graph = {
"nodes": [
{"task": "1", "label": "1", "social": "I", "id": 1, "x": 150, "y": 450},
{"task": "2", "label": "2", "social": "T", "id": 2, "x": 300, "y": 150},
{"task": "3", "label": "3", "social": "G", "id": 3, "x": 450, "y": 300}
],
"links": [
{"source": "1", "target": "2", "type": "N:1"},
{"source": "2", "target": "3", "type": "1:N"},
{"source": "1", "target": "3", "type": "1:1"}
]
}
var margin = {
top: -5,
right: -5,
bottom: -5,
left: -5
};
var colors = d3.scale.category20();
var svg = d3.select('body').append('svg')
.attr('width', width)
.attr('height', height)//;
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.right + ")");
var force = d3.layout.force()
.charge(-200)
.linkDistance(50)
.gravity(0)
.charge(0)
.size([width + margin.left + margin.right, height + margin.top + margin.bottom])
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on('drag', dragged);
var rect = svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all");
svg.selectAll('.vertical')
.data(d3.range(1, width / resolution))
.enter().append('line')
.attr('class', 'vertical')
.attr('x1', function(d) { return d * resolution; })
.attr('y1', 0)
.attr('x2', function(d) { return d * resolution; })
.attr('y2', height);
svg.selectAll('.horizontal')
.data(d3.range(1, height / resolution))
.enter().append('line')
.attr('class', 'horizontal')
.attr('x1', 0)
.attr('y1', function(d) { return d * resolution; })
.attr('x2', width)
.attr('y2', function(d) { return d * resolution; });
svg.append('defs').append('marker')
.attr({'id':'arrowhead',
'viewBox':'-0 -5 10 10',
'refX':40,
'refY':0,
'orient':'auto',
'markerWidth':5,
'markerHeight':5,
'xoverflow':'visible'})
.append('svg:path')
.attr('d', 'M 0,-5 L 10 ,0 L 0,5')
.attr('fill', '#777')
.style('stroke','none');
var link = svg.selectAll("line.link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.attr('marker-end','url(#arrowhead)')
.attr("data-source", function (d) {
return d.source;
})
.attr("data-target", function (d) {
return d.target;
})
.attr("x1", function (d) {
for (let node of graph.nodes) {
if (node.task === d.source)
return node.x;
}
})
.attr("x2", function (d) {
for (let node of graph.nodes) {
if (node.task === d.target)
return node.x;
}
})
.attr("y1", function (d) {
for (let node of graph.nodes) {
if (node.task === d.source)
return node.y;
}
})
.attr("y2", function (d) {
for (let node of graph.nodes) {
if (node.task === d.target)
return node.y;
}
})
.style("stroke-width", function(d) {
return Math.sqrt(d.value);
});
const links = graph.links.map(l => {
const source = graph.nodes.find(n => n.task === l.source);
const target = graph.nodes.find(n => n.task === l.target);
return {...l, source, target};
});
const linkLabel = svg.selectAll("g.link-label")
.data(links)
.enter()
.append("g")
.attr("class", "link-label")
.attr('transform', d => `translate(${(d.source.x + d.target.x) / 2},${(d.source.y + d.target.y) / 2})`);
linkLabel.append('circle')
.attr('r', 20)
.style("fill", '#ffffff');
linkLabel.append('text')
.text(d => d.type)
.classed('label', true)
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'middle')
.style('stroke', 'none')
.style('fill', 'black')
var node = svg.selectAll("svg.node")
.data(graph.nodes)
.enter().append('g');
//.attr('transform', d => `translate(${d.x},${d.y})`);
node.append("circle")
.attr("class", "node")
.attr('task_id', d => d.task)
.attr('social', d => d.social)
.attr('cx', function(d) { return d.x; })
.attr('cy', function(d) { return d.y; })
.attr('r', r * 2)
.on("mouseover", function(d) {
d3.select(this).attr("r", 40).style("fill", "#FF7F0E"); //#d62728
})
.on("mouseout", function(d) {
d3.select(this).attr("r", 30).style("fill", "#ccc").style('stroke', 'none');
})
.call(drag);//
node.append("text")
.attr("class", "label")
.attr('social', d => d.social)
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'middle')
.attr('dx', function(d) { return d.x; })
.attr('dy', function(d) { return d.y; })
.text(function(d) { return d.social; });
force.on("tick", function () {
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; });
linkLabel.attr('transform', d => `translate(${(d.source.x + d.target.x) / 2},${(d.source.y + d.target.y) / 2})`);
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
//node.attr('transform', d => `translate(${d.x}, ${d.y}`);
force
.nodes(nodes)
.links(links)
.start();
});
function dragged(d) {
var x = d3.event.x,
y = d3.event.y,
taskId = d.task;
//console.log('task!!!: ', taskId);
gridX = round(Math.max(r, Math.min(width - r, x)), resolution),
gridY = round(Math.max(r, Math.min(height - r, y)), resolution);
//--------------------------------------------------
var result = graph.nodes.filter(obj => {
return obj.x === gridX;
})
if (result.length == 2) {
patterIntegrity(taskId);
}
//--------------------------------------------------
d3.select(this).attr('cx', d.x = gridX).attr('cy', d.y = d.y); // previously = gridY);
d3.select(this).attr('dx', d.x = gridX).attr('dy', d.y = d.y); // previously = gridY);
d3.selectAll(`[data-source='${d.task}']`).attr('x1', d.x).attr('y1', d.y);
d3.selectAll(`[data-target='${d.task}']`).attr('x2', d.x).attr('y2', d.y);
d3.select(`text[social='${d.social}']`).attr('dx', d.x).attr('dy', d.y)
linkLabel.attr('transform', d => `translate(${(d.source.x + d.target.x) / 2},${(d.source.y + d.target.y) / 2})`);
}
function round(p, n) {
return p % n < n / 2 ? p - (p % n) : p + n - (p % n);
}
function patterIntegrity(taskId) {
for (var i = taskId; i < graph.nodes.length; i++) {
for (var k = 0; k < graph.nodes.length; k++) {
//console.log('graph.nodes[i].x: ', graph.nodes[i].x,' graph.nodes[k].x: ', graph.nodes[k].x,' i: ', i,' task_i: ',graph.nodes[i].task, ' task_k: ',graph.nodes[k].task,' k: ',k);
if (graph.nodes[i].x == graph.nodes[k].x && graph.nodes[k].task > i+1) {
graph.nodes[k].x += resolution;
//console.log(graph);
} else if (graph.nodes[i].x == graph.nodes[k].x && graph.nodes[k].task < i) {
graph.nodes[k].x -= resolution;
}
}
}
//console.log(graph);
}
.node, .link-label {
fill:#ccc;
stroke: #fff;
stroke-width: 2px;
}
.node-active {
stroke: #555;
stroke-width: 1.5px;
}
link-active {
stroke: #555;
stroke-opacity: 5;
}
line {
stroke: rgb(212, 212, 212);
stroke-width: 1px;
shape-rendering: crispEdges;
}
.overlay {
fill: none;
pointer-events: all;
}
.link{
stroke: #ccc;
stroke-width: 2px;
}
svg {
box-sizing: border-box;
border: 1px solid rgb(212, 212, 212);
}
path {
fill: none;
stroke: #0000FF;
stroke-width: 1px;
}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>[AF-PATTERN-EDITOR]</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="robots" content="noindex, nofollow">
<meta name="googlebot" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<body>
<script src="https://d3js.org/d3.v3.js" charset="utf-8"></script>
<script type="text/javascript">
</script>
</body>
</html>
从代码片段中可以看出,对 json 图形变量(函数“patternIntegrity”)进行更新不会更新图形布局。通过将“I”节点向右移动,它应该更新“T”和“G”节点的位置以及它们之间的链接。但是,在当前版本中,仅更新了“N:1”、“1:1”和“1:N”节点之间的链接标签的位置。
我做错了什么,有什么提示吗?
解决方案
推荐阅读
- express - 如何使用 Express 和 Mongodb 将当前用户作为作者添加到博客
- javascript - object.splice 没有从数组中删除数据
- python - 如何检查文本值中的值是否存在于二维数组中?
- functional-programming - “我在解析函数定义时卡住了:”:如何正确定义 Elm 函数?
- python - 在 .之前和之后分隔文本
。(美人汤) - javascript - 在选择带有“datetime-local”输入的日期后,是否可以将时间设置为默认值?
- java - JAVA FX Deploy 部分中未解决对符号“WixUI:WixUI_InstallDir”的引用
- android - Firebase storag getDownloadUrl Image 未在 ViewHolder Android 中显示
- javascript - 对象属性在使用 Number() 设置后被视为 null,即使它记录为具有值
- javascript - 对象数组的操作