graph = {
const myData = [...data].map((d, i) => {
return d;
});
let countries = data.sort((a, b) => {return b.country_total - a.country_total})
.reduce((acc, d) => {
if(acc.indexOf(d.country) < 0) {
acc.push(d.country);
}
return acc;
}, []);
const svg = d3.select(DOM.svg(width, height));
const radius = 5;
const sizeScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d.count)])
.range([2, 25]);
const genreBand = d3.scaleBand()
.domain(genres)
.range([0, genres.length]);
const countryBand = d3.scaleBand()
.domain(countries)
.range([0, countries.length]);
const colorScale = d3.scaleBand()
.domain(genres.sort(() => (Math.random() -1)));
const yForce = (type) => {
return d3.forceY(d => {
if(type=='center') return height/2;
const i = (type=='genre') ? genreBand(d.genre) : countryBand(d.country);
return 200 + Math.floor(i/3) * 120;
}).strength(.2);
}
const xForce = (type) => {
return d3.forceX(d => {
if(type=='center') return width/2;
const i = (type=='genre') ? genreBand(d.genre) : countryBand(d.country);
const colIndex = i % 3;
const col = width/3;
const gap = col/2;
return gap + col * colIndex;
}).strength(.2);
}
const force = d3.forceSimulation(myData)
.force("charge", d3.forceCollide().radius(d => (sizeScale(d.count) + 1)))
.force('x', yForce('center'))
.force('y', xForce('center'));
const node = svg.selectAll('.node')
.data(myData)
.enter().append('circle')
.attr('class', 'node')
.attr('r', d => (sizeScale(d.count)))
.attr('fill', d => d3.interpolateViridis(colorScale(d.genre)))
const tick = () => {
node
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
force.on('tick', tick);
const chartStyles = ['center', 'genre', 'country'];
let chartStyleIndex = 0;
svg.on('click', () => {
chartStyleIndex++;
force.force('x', xForce(chartStyles[chartStyleIndex % 3]))
.force('y', yForce(chartStyles[chartStyleIndex % 3]))
.alphaTarget(0.2)
.restart();
});
return svg.node();
}