xxxxxxxxxx
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1"/>
<title>Custom Force Manipulation</title>
<link rel="stylesheet" type="text/css" href="../../css/styles.css"/>
<script type="text/javascript" src="../../lib/d3.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<style type="text/css">
.touch{
fill-opacity: .2
}
</style>
</head>
<body>
<script type="text/javascript">
var svg = d3.select("body").append("svg"),
colors = d3.scaleOrdinal(d3.schemeCategory20c),
r = 4.5,
w = 1290,
h = 800;
svg.attr("width", w).attr("height", h);
var force = d3.forceSimulation()
.velocityDecay(0.8)
.alphaDecay(0)
.force("charge", d3.forceManyBody().strength(-30))
.force("x", d3.forceX(w / 2))
.force("y", d3.forceY(h / 2))
.force("collision", d3.forceCollide(r + 0.5).strength(1));
var nodes = [], centers = [];
for (var i = 0; i < 5; ++i) {
for (var j = 0; j < 50; ++j) {
nodes.push({
x: w / 2 + offset(),
y: h / 2 + offset(),
color: colors(i), // <-A
type: i // <-B
});
}
}
force.nodes(nodes);
function offset() {
return Math.random() * 100;
}
function boundX(x) {
return x > (w - r) ? (w - r): (x > r ? x : r);
}
function boundY(y){
return y > (h - r) ? (h - r) : (y > r ? y : r);
}
svg.selectAll("circle")
.data(nodes).enter()
.append("circle")
.attr("class", "node")
.attr("cx", function (d) {return d.x;})
.attr("cy", function (d) {return d.y;})
.attr("fill", function(d){return d.color;})
.attr("r", 1e-6)
.transition()
.attr("r", r);
force.on("tick", function() {
var k = 0.1;
nodes.forEach(function(node) {
var center = centers[node.type];
if(center){
node.x += (center[0] - node.x) * k; // <-C
node.y += (center[1] - node.y) * k; // <-D
}
});
svg.selectAll("circle")
.attr("cx", function (d) {return boundX(d.x);})
.attr("cy", function (d) {return boundY(d.y);});
});
d3.select("body")
.on("touchstart", touch)
.on("touchend", touch);
function touch() {
d3.event.preventDefault();
centers = d3.touches(svg.node());
var g = svg.selectAll("g.touch")
.data(centers, function (d) {
return d.identifier;
});
g.enter()
.append("g")
.attr("class", "touch")
.attr("transform", function (d) {
return "translate(" + d[0] + "," + d[1] + ")";
})
.append("circle")
.attr("class", "touch")
.attr("fill", function(d){return colors(d.identifier);})
.transition()
.attr("r", 50);
g.exit().remove();
}
</script>
<script id="jsbin-source-html" type="text/html">
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1"/>
<title>Custom Force Manipulation</title>
<link rel="stylesheet" type="text/css" href="../../css/styles.css"/>
<script type="text/javascript" src="../../lib/d3.js"><\/script>
<script src="https://d3js.org/d3.v4.min.js"><\/script>
<style type="text/css">
.touch{
fill-opacity: .2
}
</style>
</head>
<body>
<script type="text/javascript">
var svg = d3.select("body").append("svg"),
colors = d3.scaleOrdinal(d3.schemeCategory20c),
r = 4.5,
w = 1290,
h = 800;
svg.attr("width", w).attr("height", h);
var force = d3.forceSimulation()
.velocityDecay(0.8)
.alphaDecay(0)
.force("charge", d3.forceManyBody().strength(-30))
.force("x", d3.forceX(w / 2))
.force("y", d3.forceY(h / 2))
.force("collision", d3.forceCollide(r + 0.5).strength(1));
var nodes = [], centers = [];
for (var i = 0; i < 5; ++i) {
for (var j = 0; j < 50; ++j) {
nodes.push({
x: w / 2 + offset(),
y: h / 2 + offset(),
color: colors(i), // <-A
type: i // <-B
});
}
}
force.nodes(nodes);
function offset() {
return Math.random() * 100;
}
function boundX(x) {
return x > (w - r) ? (w - r): (x > r ? x : r);
}
function boundY(y){
return y > (h - r) ? (h - r) : (y > r ? y : r);
}
svg.selectAll("circle")
.data(nodes).enter()
.append("circle")
.attr("class", "node")
.attr("cx", function (d) {return d.x;})
.attr("cy", function (d) {return d.y;})
.attr("fill", function(d){return d.color;})
.attr("r", 1e-6)
.transition()
.attr("r", r);
force.on("tick", function() {
var k = 0.1;
nodes.forEach(function(node) {
var center = centers[node.type];
if(center){
node.x += (center[0] - node.x) * k; // <-C
node.y += (center[1] - node.y) * k; // <-D
}
});
svg.selectAll("circle")
.attr("cx", function (d) {return boundX(d.x);})
.attr("cy", function (d) {return boundY(d.y);});
});
d3.select("body")
.on("touchstart", touch)
.on("touchend", touch);
function touch() {
d3.event.preventDefault();
centers = d3.touches(svg.node());
var g = svg.selectAll("g.touch")
.data(centers, function (d) {
return d.identifier;
});
g.enter()
.append("g")
.attr("class", "touch")
.attr("transform", function (d) {
return "translate(" + d[0] + "," + d[1] + ")";
})
.append("circle")
.attr("class", "touch")
.attr("fill", function(d){return colors(d.identifier);})
.transition()
.attr("r", 50);
g.exit().remove();
}
<\/script>
</body>
</html></script>
</body>
</html>
https://d3js.org/d3.v4.min.js
https://d3js.org/d3.v4.min.js