[英]Fix node position based on another value in d3.js
我有一個部隊指揮的布局。 節點是從json值派生的,這些json名稱的名稱為group,是節點,源,目標和值是鏈接。 json可以將值“ size”作為節點的一部分,我想看看是否可以使用該值來確定節點的放置位置0,即尺寸越大,在畫布上越高放置。
我有兩個問題。 a)我不知道d3.js是否會在json之上攜帶額外的元素,以及b)我不確定如何根據此'size'元素更改y屬性。
我嘗試過的代碼是:
var width = 1400,
height = 500
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-100)
.linkDistance(130)
.size([width, height]);
var svg = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.call(d3.behavior.zoom().scaleExtent([1, 8]).on("zoom", zoom))
.append("g");
function zoom() {
svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
var endpoint = window.location.href+".json"
d3.json(endpoint, function(graph) {
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("marker-end", "url(#suit)");
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", function(d) { return d.group * 3; })
.attr("cy", function(d) { return d.group; })
.style("fill", function(d) { return color(d.group); })
.call(force.drag)
.on('mouseover', connectedNodes)
.on('mouseout', UnconnectedNodes)
.on("click", function(d) { getprofile2(d); });
function getprofile2(d){
$.ajax({
url: "/graph/show",
type: "GET",
dataType: 'html',
data: {name: d.name},
success: function(result) {
$('.bchart-content').html(result);
addGraph(result);
}
});
}
node.append("title")
.text(function(d) { return d.name; });
node.append("circle")
.attr("r", function(d) { return d.group * 3; });
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; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
//Toggle stores whether the highlighting is on
var toggle = 0;
//Create an array logging what is connected to what
var linkedByIndex = {};
for (i = 0; i < graph.nodes.length; i++) {
linkedByIndex[i + "," + i] = 1;
};
graph.links.forEach(function (d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
});
//This function looks up whether a pair are neighbours
function neighboring(a, b) {
return linkedByIndex[a.index + "," + b.index];
}
function connectedNodes() {
if (toggle == 0) {
//Reduce the opacity of all but the neighbouring nodes
d = d3.select(this).node().__data__;
node.style("opacity", function (o) {
return neighboring(d, o) | neighboring(o, d) ? 1 : 0.1;
});
link.style("opacity", function (o) {
return d.index==o.source.index | d.index==o.target.index ? 1 : 0.1;
});
//Reduce the op
toggle = 1;
} else {
//Put them back to opacity=1
node.style("opacity", 1);
link.style("opacity", 1);
toggle = 0;
}
}
function UnconnectedNodes() {
node.style("opacity", 1);
link.style("opacity", 1);
toggle = 0;
}
graphRec=JSON.parse(JSON.stringify(graph));
function threshold(thresh) {
graph.links.splice(0, graph.links.length);
for (var i = 0; i < graphRec.links.length; i++) {
if (graphRec.links[i].value > thresh) {graph.links.push(graphRec.links[i]);}
}
restart();
}
//Restart the visualisation after any node and link changes
function restart() {
link = link.data(graph.links);
link.exit().remove();
link.enter().insert("line", ".node").attr("class", "link");
node = node.data(graph.nodes);
node.enter().insert("circle", ".cursor").attr("class", "node").attr("r", 5).call(force.drag);
force.start();
}
});
但是什么都沒有改變。
我的數據如下所示:
{
"nodes":[
{
"name":"Et",
"group":5
"size":14
},
{
"name":"Non Qui",
"group":5,
"size":19
},
{
"name":"Officiis",
"group":1
"size":13
},
{
"name":"Bilbo",
"group":1
"size":10
}
],
"links":[
{
"source":1,
"target":2,
"value":2
},
{
"source":1,
"target":3,
"value":1
}
]
}
這是一個如何調整重力函數以產生您想要的效果的示例。 我還加了些搖晃以幫助擴散...
var width = 960, height = 500, padding = 0, // separation between nodes maxRadius = 12; var n = 1000, // total number of nodes m = 10; // number of distinct layers var color = d3.scale.category10() .domain(d3.range(m)); var y = d3.scale.ordinal() .domain(d3.range(m)) .rangePoints([height, 0], 1); var nodes = d3.range(n).map(function() { var i = Math.floor(Math.random() * m), v = (i + 10) / m * -Math.log(Math.random()); return { radius: Math.sqrt(v) * maxRadius, color: color(i), cy: y(i) }; }); var force = d3.layout.force() .nodes(nodes) .size([width, height]) .gravity(0) .charge(0) .on("tick", tick) .start(); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); var circle = svg.selectAll("circle") .data(nodes) .enter().append("circle") .attr("r", function(d) { return d.radius; }) .style("fill", function(d) { return d.color; }) .call(force.drag); function tick(e) { var a = e.alpha; circle .each(gravity(.2 * a)) .each(collide(.5)) .attr("cx", function(d) { return brownian(dx, a); }) .attr("cy", function(d) { return brownian(dy, a); }); force.alpha(a / 0.99 * 0.999) } var brownian = (function(w) { return function(x, a) { return x + (Math.random() - 0.5) * w * a } })(10); // Move nodes toward cluster focus. function gravity(alpha) { return function(d) { dy += (d.cy - dy) * alpha; // dx += (d.cx - dx) * alpha; }; } // Resolve collisions between nodes. function collide(alpha) { var quadtree = d3.geom.quadtree(nodes); return function(d) { var r = d.radius + maxRadius + padding, nx1 = dx - r, nx2 = dx + r, ny1 = dy - r, ny2 = dy + r; quadtree.visit(function(quad, x1, y1, x2, y2) { if (quad.point && (quad.point !== d)) { var x = dx - quad.point.x, y = dy - quad.point.y, l = Math.sqrt(x * x + y * y), r = d.radius + quad.point.radius + (d.color !== quad.point.color) * padding; if (l < r) { l = (l - r) / l * alpha; dx -= x *= l; dy -= y *= l; quad.point.x += x; quad.point.y += y; } } return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1; }); }; }
circle { stroke: #fff; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
根據您的數據,代碼應類似於:
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", function(d) { return d.group * 3; })
.attr("cy", function(d) { return d.size; })
.style("fill", function(d) { return color(d.group); })
實際的“ cy”也可能取決於繪圖區域的最大高度,因此您可能需要相應地縮放比例。
希望這可以幫助 :)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.