Some improvement in the collision function by basing the collide vector on the depth of overlap. Still some annoying artifacts with the long pieces not getting dragged to the center properly.
<html>
<head>
<title>d3v4 Simple Word Cloud</title>
<meta charset="utf-8" />
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="d3-force.js"></script>
</head>
<style>
svg {
height: 500px;
width: 500px;
border: 1px solid gray;
}
</style>
<body>
<div id="viz">
<svg class="main">
</svg>
</div>
</body>
<footer>
<script>
d3.csv("words.csv",function(error,data) {createWordcloud(data)});
//d3.csv("words.csv",function(error,data) {roundWordCloud(data)});
function roundWordCloud(data) {
var simulation = d3.forceSimulation(data)
.force("x", d3.forceX().strength(0.002))
.force("y", d3.forceY().strength(0.002))
.force("collide", d3.forceCollide().radius(function(d) { return 5; })
.iterations(2))
.on("tick", updateNetwork);
var color = d3.scaleOrdinal(d3.schemeCategory10)
var nodeEnter = d3.select("svg.main")
.append("g")
.attr("transform", "translate(250,250)")
.selectAll("g.node")
.data(data)
.enter()
.append("g")
.attr("class", "node")
nodeEnter.append("circle")
.attr("r", 5)
.style("pointer-events", "none")
.style("fill", function (d,i) {return color(i)})
.style("stroke", function (d,i) {return color(i)})
.style("stroke-width", 1)
.style("fill-opacity", 0.2)
function updateNetwork(e) {
d3.select("svg.main").selectAll("g.node")
.attr("transform", function (d) {return "translate(" + d.x + "," + d.y + ")"});
}
}
function createWordcloud(data) {
var combinedData = [];
combinedData = data
var networkCenter = d3.forceCenter().x(250).y(250);
var textScale = d3.scaleLinear().domain([10,70]).range([2,10])
var forceX = d3.forceX(function (d) {return 250})
.strength(0.05)
var forceY = d3.forceY(function (d) {return 250})
.strength(0.05)
var collide = d3.forceRectCollide(function (d,i) {
return i%2 === 0 ? [[-(d.text.length * textScale(d.frequency)),-15],[(d.text.length * textScale(d.frequency)),15]] : [[-15,-(d.text.length * textScale(d.frequency))],[15,(d.text.length * textScale(d.frequency))]]
})
.strength(1)
.iterations(2)
var color = d3.scaleOrdinal(d3.schemeCategory10)
var force = d3.forceSimulation(combinedData)
.force("center", networkCenter)
.force("x", forceX)
.force("y", forceY)
.force("collide", collide)
.on("tick", updateNetwork);
var nodeEnter = d3.select("svg.main").selectAll("g.node")
.data(combinedData)
.enter()
.append("g")
.attr("class", "node")
nodeEnter.append("rect")
.attr("height", function (d,i) {
return i%2 === 0 ? 30 : d.text.length * textScale(d.frequency) * 2
})
.attr("width", function (d,i) {
return i%2 === 0 ? d.text.length * textScale(d.frequency) * 2 : 30
})
.attr("y", function (d,i) {
return i%2 === 0 ? -15 : -(d.text.length * textScale(d.frequency))
})
.attr("x", function (d,i) {
return i%2 === 0 ? -(d.text.length * textScale(d.frequency)) : -15
})
.style("pointer-events", "none")
.style("fill", function (d,i) {return color(i)})
.style("stroke", function (d,i) {return color(i)})
.style("stroke-width", 1)
.style("fill-opacity", 0.2)
function updateNetwork(e) {
d3.select("svg.main").selectAll("g.node")
.attr("transform", function (d) {return "translate(" + d.x + "," + d.y + ")"});
}
}
</script>
</footer>
</html>
text,frequency
layout,63
function,61
data,47
return,36
attr,29
chart,28
array,24
style,24
layouts,22
values,22
need,21
nodes,21
pie,21
use,21
figure,20
circle,19
we'll,19
zoom,19
append,17
elements,17