gpt4 book ai didi

javascript - d3力布局初始结构

转载 作者:行者123 更新时间:2023-11-30 00:01:01 25 4
gpt4 key购买 nike

是否可以为 d3 强制布局提供某种结构?我想展示员工和用户之间的关系,员工可以有很多用户。

然而,最初的布局虽然正确,但却难以理解。

enter image description here

红色轮廓的节点是员工,蓝色轮廓的是用户,理想情况下,让用户在员工下方会很好,如果存在的话,几乎处于强制层次结构布局中?

var width = document.querySelector('.visualisation').clientWidth,
height = 500;

var svg = d3.select(".visualisation").append("svg")
.attr("width", width)
.attr("height", height);

var force = d3.layout.force()
.gravity(.05)
.linkDistance(100)
.charge(-300)
.size([width, height]);

var sw = [],
su = [],
workbase = [],
links = [],
edges = [],
simplified = [];

d3.json("test_example.json", function(error, json) {
if (error) throw error;
console.log(json);
var users = [];
json.forEach(function(data){
if(data.workbase == "Cherry Tree Lodge") {
data.weight = 1;
links.push({
target : data.user_id,
source : data.staff_id,
});
users.push(data);
}
});

console.log(nodes);

// json.forEach(function(data) {

// console.log(json);
users.forEach(function(d) {
if(_.findWhere(sw, { name: d.staff_name}) == undefined) {
sw.push({
name : d.staff_name,
id : d.staff_id,
role : d.role,
weight:1,
type : "worker"
});
}
if(_.findWhere(su, { name: d.service_user}) == undefined) {
su.push({
name : d.service_user,
type : "user",
id : d.user_id,
weight:1
});
}
});

var nodes = sw.concat(su);

console.log(nodes);

nodes.forEach(function(data){
if(typeof data.linked_to != "undefined") {
links.push({
target: _.findIndex(nodes, function(user) {
return user.id == data.linked_to;
}),
source: data.id
});
}
});

console.log(links);
// //console.log(json);console.log(links)
links.forEach(function(e){
var sourceNode = nodes.filter(function(n) { return n.id === e.source})[0];
var targetNode = nodes.filter(function(n) { return n.id === e.target})[0];
edges.push({ source: sourceNode, target: targetNode });
});
console.log(edges);
// console.log(nodes);
force
.nodes(nodes)
.links(edges)
.on("tick", tick)
.start();

var link = svg.selectAll(".link")
.data(edges)
.enter().append("line")
.attr("class", "link");

var node = svg.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);

// node.append("defs")
// .append("pattern")
// .attr("id", function(d){
// return "image-" + d.id;
// })
// .attr("height", 50)
// .attr("width", 50)
// .attr("x", 0)
// .attr("y", 0)
// .append("image")
// .attr("xlink:href", function(d) {
// return d.image;
// })
// .attr('height',60)
// .attr('width',60)
// .attr('x',0)
// .attr('y',0);

node.append("circle")
.attr("class", function(d){
return d.type;
})
.attr("r", 25);
// .on("mouseover", showDetails)
// .on("mouseout", removeDetails);

node.append("text")
.attr("x", 0)
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function(d){
//return d.name;
});

// // node.append("svg:a")
// // .attr("xlink:href", function(d){ return "" })
// // .append("text")
// // .attr("dx", 12)
// // .attr("dy", ".35em")
// // .text(function(d) { return d.name})


function tick(e) {
var k = 6 * e.alpha;

// Push sources up and targets down to form a weak tree.
link
.each(function(d) { d.source.y -= k, d.target.y += k; })
.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; });

node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
}

});

最佳答案

您可以通过使用 d3.forceY() 设置沿 y 轴的位置来实现此目的。根据API :

Creates a new positioning force along the y-axis towards the given position y.

因此,我使用 type 创建了一个数组来指定用户和员工:

var nodes = [
{"id": 1, "name": "staff1", "type": "staff"},
{"id": 2, "name": "staff2", "type": "staff"},
{"id": 3, "name": "user1", "type": "user"},
{"id": 4, "name": "user2", "type": "user"},
{"id": 5, "name": "user3", "type": "user"},
{"id": 6, "name": "staff3", "type": "staff"},
{"id": 7, "name": "user4", "type": "user"},
{"id": 8, "name": "user5", "type": "user"},
{"id": 9, "name": "user6", "type": "user"},
{"id": 10, "name": "user7", "type": "user"},
{"id": 11, "name": "user8", "type": "user"},
{"id": 12, "name": "user19", "type": "user"}
];

然后,我使用类型来设置位置:

var simulation = d3.forceSimulation()
.force('y', d3.forceY((d) => d.type === "staff" ? height/5 : 4*height/5).strength(2))

这是一个演示:

var nodes = [
{"id": 1, "name": "staff1", "type": "staff"},
{"id": 2, "name": "staff2", "type": "staff"},
{"id": 3, "name": "user1", "type": "user"},
{"id": 4, "name": "user2", "type": "user"},
{"id": 5, "name": "user3", "type": "user"},
{"id": 6, "name": "staff3", "type": "staff"},
{"id": 7, "name": "user4", "type": "user"},
{"id": 8, "name": "user5", "type": "user"},
{"id": 9, "name": "user6", "type": "user"},
{"id": 10, "name": "user7", "type": "user"},
{"id": 11, "name": "user8", "type": "user"},
{"id": 12, "name": "user19", "type": "user"}
];

var links = [
{source: 1, target: 8},
{source: 1, target: 3},
{source: 1, target: 4},
{source: 1, target: 9},
{source: 1, target: 10},
{source: 1, target: 11},
{source: 2, target: 5},
{source: 2, target: 6},
{source: 2, target: 7},
{source: 2, target: 12},
{source: 2, target: 4},
{source: 2, target: 8},
{source: 6, target: 7},
{source: 6, target: 8},
{source: 6, target: 9},
{source: 6, target: 5},
{source: 6, target: 3},
{source: 6, target: 9},
]

var index = 10;
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
node,
link;

var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; }))
.force('y', d3.forceY((d) => d.type === "staff" ? height/5 : 4*height/5).strength(2))
.force("charge", d3.forceManyBody())
.force("collide", d3.forceCollide(30))
.force("center", d3.forceCenter(width / 2, height / 2));

update();
function update() {
link = svg.selectAll(".link")
.data(links, function(d) { return d.target.id; })

link = link.enter()
.append("line")
.attr("class", "link");

node = svg.selectAll(".node")
.data(nodes, function(d) { return d.id; })

node = node.enter()
.append("g")
.attr("class", "node")
.on("click", click)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));

node.append("circle")
.attr("r", 6)
.attr("fill", (d)=> d.type === "user" ? "blue" : "red")

node.append("title")
.text(function(d) { return d.id; });

node.append("text")
.attr("dx", 10)
.text(function(d) { return d.name; });

simulation
.nodes(nodes)
.on("tick", ticked);

simulation.force("link")
.links(links);
}

function click(d) {
nodes.push({id: index, name: "server " + index});
links.push({source: d.id, target: index});
index++;
update();
}

function ticked() {
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("transform", function(d) { return "translate(" + d.x + ", " + d.y + ")"; });
}

function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart()
}

function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}

function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = undefined;
d.fy = undefined;
}
.link {
stroke: #aaa;
}

.node {
pointer-events: all;
stroke: none;
stroke-width: 40px;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="400" height="400"></svg>

关于javascript - d3力布局初始结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40523107/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com