beeswarm = context => {
let data = [],
chartWidth = width,
chartHeight = 100,
marginLeft = 10,
marginRight = 10,
marginTop = 10,
marginBottom = 17,
x = d => d[0],
xMin, xMax,
radius = d => 20,
radiusMax = 20,
padding = d => 1,
circleFill = d => "#000",
circleStroke = d => "#000",
tickValues, tickFormat,
forceTicks = 300;
function chart(context){
const innerWidth = chartWidth - marginLeft - marginRight;
const innerHeight = chartHeight - marginTop - marginBottom;
const xScale = chart.xScale();
const radiusScale = d3.scaleSqrt()
.domain(d3.extent(data, radius))
.range([0, radiusMax]);
const force = d3.forceSimulation(data)
.force("x", d3.forceX(d => xScale(x(d))))
.force("y", d3.forceY(innerHeight / 2))
.force("collide", d3.forceCollide(d => padding(d) + radiusScale(radius(d))))
.stop();
for (let i = 0; i < forceTicks; i++) force.tick();
let g = context.select("g");
if (!g._groups[0][0]){
g = context.append("g");
}
g.attr("transform", `translate(${[marginLeft, marginTop]})`);
const axis = d3.axisBottom(xScale);
if (tickValues){
axis.tickValues(tickValues);
}
if (tickFormat){
axis.tickFormat(tickFormat);
}
g.append("g")
.call(axis)
.attr("transform", `translate(0, ${innerHeight})`)
g.selectAll("circle")
.data(data)
.enter().append("circle")
.style("fill", circleFill)
.style("stroke", circleStroke)
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("r", d => radiusScale(radius(d)));
}
chart.data = _ => _ ? (data = _, chart) : data;
chart.chartWidth = _ => _ ? (chartWidth = _, chart) : chartWidth;
chart.chartHeight = _ => _ ? (chartHeight = _, chart) : chartHeight;
chart.marginLeft = _ => _ ? (marginLeft = _, chart) : marginLeft;
chart.marginRight = _ => _ ? (marginRight = _, chart) : marginRight;
chart.marginTop = _ => _ ? (marginTop = _, chart) : marginTop;
chart.marginBottom = _ => _ ? (marginBottom = _, chart) : marginBottom;
chart.x = _ => _ ? (x = _, chart) : x;
chart.xMax = _ => _ ? (xMax = _, chart) : xMax;
chart.xMin = _ => _ ? (xMin = _, chart) : xMin;
chart.radius = _ => _ ? (radius = _, chart) : radius;
chart.radiusMax = _ => _ ? (radiusMax = _, chart) : radiusMax;
chart.padding = _ => _ ? (padding = _, chart) : padding;
chart.circleFill = _ => _ ? (circleFill = _, chart) : circleFill;
chart.circleStroke = _ => _ ? (circleStroke = _, chart) : circleStroke;
chart.tickValues = _ => _ ? (tickValues = _, chart) : tickValues;
chart.tickFormat = _ => _ ? (tickFormat = _, chart) : tickFormat;
chart.forceTicks = _ => _ ? (forceTicks = _, chart) : forceTicks;
chart.xScale = _ => d3.scaleLinear()
.domain(xMin && xMax ? [xMin, xMax] : xMin ? [xMin, d3.max(data, x)] : xMax ? [d3.min(data, x), xMax] : d3.extent(data, x))
.range([0, chart.chartWidth() - chart.marginLeft() - chart.marginRight()]);
return chart;
}