我是d3的初学者因此这个问题......我的网络中有一堆节点,链接和组,如下所示:
我想对它实施一个d3-force,以便每个组都有自己的力量,当一个组被采取行动时,另一个组不会受到影响。
注意节点5,因为它是一个单例,所以组0。所以所有单身人士都会有0人组。
network = {
"nodes" : [
{
"id":0,
"x":0,
"y":0,
"group":1
},
{
"id":1,
"x":11,
"y":-11,
"group":1
},
{
"id":2,
"x":22,
"y":-22,
"group":1
},
{
"id":3,
"x":33,
"y":-33,
"group":2
},
{
"id":4,
"x":44,
"y":-44,
"group":2
},
{
"id":5,
"x":55,
"y":-55,
"group":0
}],
"links" : [
{
"from": 0,
"to" : 1
},
{
"from": 1,
"to" : 2
},
{
"from": 3,
"to" : 4
}
]
}
答案 0 :(得分:1)
以下是一个如何进行操作的示例,请注意我必须重新重写分组功能,因为您的内容存在错误。
var networkData = {
"nodes": [{
"id": "0",
"x": 1509.9862,
"y": -609.1013,
"row_count": 2
}, {
"id": "1",
"x": 1645.9578,
"y": -85.06705,
"row_count": 3
}, {
"id": "2",
"x": 1948.1533,
"y": -469.3646,
"row_count": 2
}, {
"id": "3",
"x": 1490.8839,
"y": -705.9929,
"row_count": 2
}, {
"id": "4",
"x": 2370.9739,
"y": -114.61766,
"row_count": 2
}, {
"id": "5",
"x": 1788.3419,
"y": -460.89978,
"row_count": 2
}, {
"id": "6",
"x": 1601.6083,
"y": -459.14755,
"row_count": 2
}, {
"id": "7",
"x": 1967.1221,
"y": -179.95412,
"row_count": 2
}, {
"id": "8",
"x": 2305.796,
"y": -398.09714,
"row_count": 2
}, {
"id": "9",
"x": 2075.197,
"y": -119.19522,
"row_count": 2
}, {
"id": "10",
"x": 144.70703,
"y": -492.124,
"row_count": 2
}, {
"id": "11",
"x": 1782.7756,
"y": -95.29288,
"row_count": 2
}, {
"id": "12",
"x": 2490.2249,
"y": -395.42737,
"row_count": 4
}, {
"id": "13",
"x": 1434.9111,
"y": -507.22018,
"row_count": 2
}, {
"id": "14",
"x": 1918.9606,
"y": -132.97313,
"row_count": 2
}, {
"id": "15",
"x": 150.78381,
"y": -375.75558,
"row_count": 4
}, {
"id": "16",
"x": 117.40755,
"y": -313.40042,
"row_count": 2
}, {
"id": "17",
"x": 128.44798,
"y": -569.65533,
"row_count": 2
}, {
"id": "18",
"x": 2241.112,
"y": -397.3375,
"row_count": 5
}, {
"id": "19",
"x": 93.45022,
"y": -510.2351,
"row_count": 2
}, {
"id": "20",
"x": 2554.5647,
"y": -395.42737,
"row_count": 2
}, {
"id": "21",
"x": 1552.0585,
"y": -175.00697,
"row_count": 2
}, {
"id": "22",
"x": 1839.4581,
"y": -137.50499,
"row_count": 2
}, {
"id": "23",
"x": 88.88344,
"y": -374.78418,
"row_count": 2
}, {
"id": "24",
"x": 1588.2749,
"y": -583.3556,
"row_count": 2
}, {
"id": "25",
"x": 115.34364,
"y": -439.38092,
"row_count": 5
}, {
"id": "26",
"x": 1527.4338,
"y": -425.7689,
"row_count": 2
}, {
"id": "27",
"x": 1466.7098,
"y": -580.9009,
"row_count": 1
}, {
"id": "28",
"x": 1614.1482,
"y": -508.55847,
"row_count": 1
}, {
"id": "29",
"x": 1653.5695,
"y": -705.9929,
"row_count": 2
}, {
"id": "30",
"x": 1555.2239,
"y": -705.9929,
"row_count": 2
}, {
"id": "31",
"x": 2226.4775,
"y": -111.886284,
"row_count": 2
}, {
"id": "32",
"x": 1458.8619,
"y": -462.99728,
"row_count": 2
}, {
"id": "33",
"x": 1541.3425,
"y": -599.3965,
"row_count": 1
}, {
"id": "34",
"x": 1572.1593,
"y": -445.52554,
"row_count": 1
}, {
"id": "35",
"x": 1804.5553,
"y": -705.9929,
"row_count": 2
}, {
"id": "36",
"x": 2299.7493,
"y": -113.641975,
"row_count": 2
}, {
"id": "37",
"x": 1447.5342,
"y": -536.6993,
"row_count": 1
}, {
"id": "38",
"x": 1633.1509,
"y": -212.4338,
"row_count": 2
}, {
"id": "39",
"x": 1782.9479,
"y": -406.7332,
"row_count": 2
}, {
"id": "40",
"x": 1955.5413,
"y": -705.9929,
"row_count": 2
}, {
"id": "41",
"x": 2151.4285,
"y": -111.490974,
"row_count": 2
}, {
"id": "42",
"x": 1598.4803,
"y": -553.35645,
"row_count": 1
}, {
"id": "43",
"x": 1500.1262,
"y": -441.0764,
"row_count": 2
}, {
"id": "44",
"x": 1496.883,
"y": -587.66406,
"row_count": 1
}, {
"id": "45",
"x": 1596.4176,
"y": -483.6955,
"row_count": 1
}, {
"id": "46",
"x": 1455.5319,
"y": -492.96527,
"row_count": 2
}, {
"id": "47",
"x": 1563.5104,
"y": -579.53015,
"row_count": 1
}, {
"id": "48",
"x": 2037.2152,
"y": -292.1214,
"row_count": 2
}, {
"id": "49",
"x": 282.7343,
"y": -516.7465,
"row_count": 2
}, {
"id": "50",
"x": 167.14136,
"y": -428.0224,
"row_count": 2
}, {
"id": "51",
"x": 2003.0924,
"y": -437.64548,
"row_count": 2
}, {
"id": "52",
"x": 99.81963,
"y": -175.3665,
"row_count": 2
}, {
"id": "53",
"x": 179.92572,
"y": -468.74872,
"row_count": 3
}, {
"id": "54",
"x": 1717.0072,
"y": -705.9929,
"row_count": 2
}, {
"id": "55",
"x": 2007.9512,
"y": -233.56764,
"row_count": 2
}, {
"id": "56",
"x": 1542.7771,
"y": -445.58582,
"row_count": 1
}, {
"id": "57",
"x": 1617.18,
"y": -149.27104,
"row_count": 5
}, {
"id": "58",
"x": 1469.2253,
"y": -555.9452,
"row_count": 1
}, {
"id": "59",
"x": 1595.1055,
"y": -524.9397,
"row_count": 1
}, {
"id": "60",
"x": 1484.0056,
"y": -464.2597,
"row_count": 1
}, {
"id": "61",
"x": 1523.9562,
"y": -581.0812,
"row_count": 1
}, {
"id": "62",
"x": 2425.8848,
"y": -395.42737,
"row_count": 4
}, {
"id": "63",
"x": 108.56919,
"y": -243.38808,
"row_count": 4
}, {
"id": "64",
"x": 1867.9934,
"y": -705.9929,
"row_count": 2
}, {
"id": "65",
"x": 1996.9839,
"y": -123.64043,
"row_count": 3
}, {
"id": "66",
"x": 1948.1533,
"y": -405.92636,
"row_count": 2
}, {
"id": "67",
"x": 1572.0945,
"y": -470.88098,
"row_count": 1
}, {
"id": "68",
"x": 1465.1875,
"y": -518.3188,
"row_count": 1
}, {
"id": "69",
"x": 1572.8579,
"y": -554.43756,
"row_count": 1
}, {
"id": "70",
"x": 2106.5273,
"y": -705.9929,
"row_count": 2
}, {
"id": "71",
"x": 1519.5193,
"y": -458.15424,
"row_count": 1
}, {
"id": "72",
"x": 1494.6997,
"y": -561.67957,
"row_count": 2
}, {
"id": "73",
"x": 1579.804,
"y": -504.15784,
"row_count": 1
}, {
"id": "74",
"x": 1482.025,
"y": -489.7116,
"row_count": 1
}, {
"id": "75",
"x": 2175.6614,
"y": -396.56552,
"row_count": 2
}, {
"id": "76",
"x": 1541.8685,
"y": -563.2375,
"row_count": 1
}, {
"id": "77",
"x": 1547.088,
"y": -472.80585,
"row_count": 1
}, {
"id": "78",
"x": 1485.3854,
"y": -532.9362,
"row_count": 1
}, {
"id": "79",
"x": 89.103745,
"y": -110.00311,
"row_count": 2
}, {
"id": "80",
"x": 1555.3121,
"y": -116.60735,
"row_count": 2
}, {
"id": "81",
"x": 1426.544,
"y": -705.9929,
"row_count": 2
}, {
"id": "82",
"x": 1566.833,
"y": -530.323,
"row_count": 2
}, {
"id": "83",
"x": 1688.4487,
"y": -172.91998,
"row_count": 2
}, {
"id": "84",
"x": 68.698006,
"y": -573.6171,
"row_count": 2
}, {
"id": "85",
"x": 1764.1693,
"y": -158.18617,
"row_count": 2
}, {
"id": "86",
"x": 219.68867,
"y": -397.56903,
"row_count": 2
}, {
"id": "87",
"x": 1730.5239,
"y": -424.70016,
"row_count": 2
}, {
"id": "88",
"x": 1837.7125,
"y": -415.37985,
"row_count": 2
}, {
"id": "89",
"x": 2439.1343,
"y": -114.35799,
"row_count": 2
}, {
"id": "90",
"x": 1852.3489,
"y": -475.04614,
"row_count": 3
}, {
"id": "91",
"x": 1715.4718,
"y": -70.03096,
"row_count": 2
}, {
"id": "92",
"x": 2018.9792,
"y": -705.9929,
"row_count": 2
}, {
"id": "93",
"x": 2169.9653,
"y": -705.9929,
"row_count": 2
}, {
"id": "94",
"x": 1508.6908,
"y": -480.54773,
"row_count": 4
}, {
"id": "95",
"x": 1699.9895,
"y": -126.77199,
"row_count": 2
}, {
"id": "96",
"x": 2110.977,
"y": -395.80646,
"row_count": 3
}, {
"id": "97",
"x": 2123.8252,
"y": -164.62895,
"row_count": 2
}, {
"id": "98",
"x": 1517.4421,
"y": -551.2502,
"row_count": 1
}, {
"id": "99",
"x": 266.0747,
"y": -450.88815,
"row_count": 2
}, {
"id": "100",
"x": 1555.2823,
"y": -497.76593,
"row_count": 1
}, {
"id": "101",
"x": 1497.4402,
"y": -510.5418,
"row_count": 1
}, {
"id": "102",
"x": 1542.789,
"y": -536.3863,
"row_count": 1
}, {
"id": "103",
"x": 1528.8363,
"y": -494.63577,
"row_count": 1
}, {
"id": "104",
"x": 1515.9209,
"y": -525.9001,
"row_count": 1
}, {
"id": "105",
"x": 1526.9814,
"y": -515.76776,
"row_count": 1
}, {
"id": "106",
"x": 1737.522,
"y": -129.01044,
"row_count": 2
}],
"links": [{
"from": 1,
"to": 57
}, {
"from": 1,
"to": 91
}, {
"from": 2,
"to": 51
}, {
"from": 2,
"to": 66
}, {
"from": 3,
"to": 30
}, {
"from": 3,
"to": 81
}, {
"from": 4,
"to": 36
}, {
"from": 4,
"to": 89
}, {
"from": 5,
"to": 87
}, {
"from": 5,
"to": 88
}, {
"from": 5,
"to": 90
}, {
"from": 7,
"to": 14
}, {
"from": 7,
"to": 55
}, {
"from": 7,
"to": 65
}, {
"from": 8,
"to": 18
}, {
"from": 9,
"to": 41
}, {
"from": 9,
"to": 65
}, {
"from": 9,
"to": 97
}, {
"from": 10,
"to": 25
}, {
"from": 10,
"to": 50
}, {
"from": 10,
"to": 53
}, {
"from": 11,
"to": 22
}, {
"from": 11,
"to": 85
}, {
"from": 11,
"to": 91
}, {
"from": 11,
"to": 106
}, {
"from": 12,
"to": 20
}, {
"from": 12,
"to": 62
}, {
"from": 14,
"to": 22
}, {
"from": 14,
"to": 65
}, {
"from": 15,
"to": 16
}, {
"from": 15,
"to": 23
}, {
"from": 15,
"to": 25
}, {
"from": 15,
"to": 50
}, {
"from": 15,
"to": 86
}, {
"from": 16,
"to": 23
}, {
"from": 16,
"to": 63
}, {
"from": 17,
"to": 19
}, {
"from": 17,
"to": 84
}, {
"from": 18,
"to": 75
}, {
"from": 19,
"to": 25
}, {
"from": 19,
"to": 84
}, {
"from": 21,
"to": 57
}, {
"from": 21,
"to": 80
}, {
"from": 22,
"to": 85
}, {
"from": 23,
"to": 25
}, {
"from": 25,
"to": 50
}, {
"from": 25,
"to": 53
}, {
"from": 29,
"to": 54
}, {
"from": 31,
"to": 36
}, {
"from": 31,
"to": 41
}, {
"from": 35,
"to": 64
}, {
"from": 38,
"to": 57
}, {
"from": 38,
"to": 83
}, {
"from": 39,
"to": 87
}, {
"from": 39,
"to": 88
}, {
"from": 40,
"to": 92
}, {
"from": 41,
"to": 97
}, {
"from": 48,
"to": 55
}, {
"from": 49,
"to": 99
}, {
"from": 50,
"to": 53
}, {
"from": 50,
"to": 86
}, {
"from": 51,
"to": 66
}, {
"from": 52,
"to": 63
}, {
"from": 52,
"to": 79
}, {
"from": 57,
"to": 80
}, {
"from": 57,
"to": 83
}, {
"from": 70,
"to": 93
}, {
"from": 75,
"to": 96
}, {
"from": 83,
"to": 85
}, {
"from": 83,
"to": 95
}, {
"from": 83,
"to": 106
}, {
"from": 85,
"to": 95
}, {
"from": 85,
"to": 106
}, {
"from": 86,
"to": 99
}, {
"from": 88,
"to": 90
}, {
"from": 91,
"to": 106
}, {
"from": 95,
"to": 106
}],
"node_count": 107,
"link_count": 77
}
/* creating groups */
// union-find is a data structure that can union two sets and check
// whether two element in the same set.
var rootNode = {};
function group2(nodes, links) {
nodes.forEach((n, i) => n._gid = i + 1);
const nodeMap = nodes.reduce((result, node) => {
result[node.id] = node;
return result
}, {});
const linkedNodes = (node, group) => {
return links.filter(link => link.source == node.id || link.target == node.id)
.map(link => nodeMap[link.source] === node ? nodeMap[link.target] : nodeMap[link.source])
.filter(n => n.group != group)
}
const infect = (node, group) => {
node.group = group;
linkedNodes(node, group).map(n => infect(n, group))
}
let n = nodes.find(node => !node.group);
while (n) {
infect(n, n._gid);
n = nodes.find(node => !node.group)
}
}
/*
function group(nodes, links) {
// create n set with each set has the node as its only element
links.forEach(function(link, i) {
link.source = link.from;
link.target = link.to;
});
nodes.forEach(function(node, i) {
node.weight = 1;
rootNode[node.id] = node.id;
});
// union each set that has a link between them
links.forEach(function(link, i) {
union(link.from, link.to);
});
// for each unioned set, group nodes together
var id = 1;
var groupIdCnt = {};
var groupIds = {};
var groups = {};
nodes.forEach(function(node, i) {
var f = find(node.id);
if (typeof groupIds[f] === 'undefined') {
groupIds[f] = id;
groupIdCnt[id] = 1;
id++;
} else {
groupIdCnt[groupIds[f]]++;
}
if (groupIdCnt[groupIds[f]] === 1) {
node['group'] = 0;
//console.log(node)
} else {
node['group'] = groupIds[f];
//console.log(node)
}
if (typeof groups[node['group']] === 'undefined') {
groups[node['group']] = [];
}
groups[node['group']].push(node);
});
return Object.values(groups);
}
// find rootNode of each set
function find(node) {
// if it is the root, return
if (rootNode[node] === node) {
return node;
}
// if not, find the rootNode and point to it
rootNode[node] = find(rootNode[node]);
return rootNode[node];
}
// update the rootNode of set which includes node1 to the rootNode of set which includes node 2
function union(node1, node2) {
rootNode[find(node1)] = find(node2);
} */
var links = networkData.links;
var nodes = networkData.nodes;
for (var i = 0; i < nodes.length; i++) {
nodes[i].level = 1;
}
for (var i = 0; i < links.length; i++) {
links[i].source = links[i].from;
links[i].target = links[i].to;
}
var groups = group2(nodes, links)
/** ====== D3 FORCE CODE =======*/
function getNodeColor(node, neighbors) {
return node.level === 1 ? 'red' : 'gray'
}
function getLinkColor(node, link) {
return isNeighborLink(node, link) ? 'green' : '#000'
}
var width = 600
var height = 600
var color = d3.scaleOrdinal(d3.schemeCategory10);
var svg = d3.select('svg')
svg.attr('width', width).attr('height', height)
// simulation setup with all forces
var linkForce = d3
.forceLink()
.id(function(link) {
return link.id
})
.strength(function(link) {
return 1
})
var chargeForce = d3.forceManyBody()
.strength(function(node) {
if (links.find(link => link.source == node.id || link.target == node.id)) {
return -100
} else {
return 0
}
}).distanceMax([100])
var simulation = d3
.forceSimulation()
.force('link', linkForce)
.force('charge', chargeForce)
.force('center', d3.forceCenter(width / 2, height / 2))
var dragDrop = d3.drag().on('start', function(node) {
simulation.nodes().forEach(n => {
if (n.group != node.group) {
n.fx = n.x
n.fy = n.y
}
})
}).on('drag', function(node) {
simulation.alphaTarget(0.7).restart()
node.fx = d3.event.x
node.fy = d3.event.y
}).on('end', function(node) {
simulation.nodes().forEach(node => {
node.fx = null
node.fy = null
})
simulation.alphaTarget(0).restart()
})
var linkElements = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(links)
.enter().append("line")
.attr("stroke-width", 1)
.attr("stroke", "rgba(50, 50, 50, 0.2)")
var nodeElements = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("r", 5)
.attr("fill", d => color(d.group))
.call(dragDrop)
simulation.nodes(nodes).on('tick', () => {
nodeElements
.attr('cx', function(node) {
return node.x
})
.attr('cy', function(node) {
return node.y
})
linkElements
.attr('x1', function(link) {
return link.source.x
})
.attr('y1', function(link) {
return link.source.y
})
.attr('x2', function(link) {
return link.target.x
})
.attr('y2', function(link) {
return link.target.y
})
})
simulation.force("link").links(links)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="1000" height="600"></svg>