<script>
import { LayerCake, Svg } from 'layercake';
import { scaleOrdinal, scaleBand } from 'd3-scale';
import ForceLayout from './_components/CirclePackForce.svelte';
import data from './_data/dots.json';
const xKey = 'category';
const rKey = 'value';
const zKey = 'category';
let groupBy = 'true';
const seriesColors = ['#f0c', '#0cf', '#fc0'];
let manyBodyStrength = 3;
let xStrength = 0.1;
</script>
<div class="input-container">
<label><input type="radio" bind:group={groupBy} value="true" />Group by category</label>
<label><input type="radio" bind:group={groupBy} value="false" />Clump together</label>
</div>
<div class="chart-container">
<LayerCake
{data}
x={xKey}
r={rKey}
z={zKey}
xScale={scaleBand()}
rRange={[3, 12]}
zScale={scaleOrdinal()}
zRange={seriesColors}
>
<Svg>
<ForceLayout {manyBodyStrength} {xStrength} groupBy={JSON.parse(groupBy)} nodeStroke="#000" />
</Svg>
</LayerCake>
</div>
<style>
.chart-container {
width: 100%;
height: 250px;
}
label {
cursor: pointer;
}
input {
margin-right: 7px;
}
</style>
<script>
import { getContext } from 'svelte';
import { forceSimulation, forceX, forceManyBody, forceCollide, forceCenter } from 'd3-force';
const { data, width, height, xScale, xGet, rGet, zGet } = getContext('LayerCake');
export let manyBodyStrength = 5;
export let xStrength = 0.1;
export let nodeColor = undefined;
export let nodeStroke = '#fff';
export let nodeStrokeWidth = 1;
export let groupBy = true;
const initialNodes = $data.map(d => ({ ...d }));
const simulation = forceSimulation(initialNodes);
let nodes = [];
simulation.on('tick', () => {
nodes = simulation.nodes();
});
$: {
simulation
.force(
'x',
forceX()
.x(d => {
return groupBy === true ? $xGet(d) + $xScale.bandwidth() / 2 : $width / 2;
})
.strength(xStrength)
)
.force('center', forceCenter($width / 2, $height / 2))
.force('charge', forceManyBody().strength(manyBodyStrength))
.force(
'collision',
forceCollide().radius(d => {
return $rGet(d) + nodeStrokeWidth / 2;
})
)
.force('center', forceCenter($width / 2, $height / 2))
.alpha(1)
.restart();
}
</script>
{#each nodes as point}
<circle
class="node"
r={$rGet(point)}
fill={nodeColor || $zGet(point)}
stroke={nodeStroke}
stroke-width={nodeStrokeWidth}
cx={point.x}
cy={point.y}
>
</circle>
{/each}
[
{ "category": "a", "value": 0 },
{ "category": "a", "value": 2 },
{ "category": "a", "value": 5 },
{ "category": "a", "value": 23 },
{ "category": "a", "value": 12 },
{ "category": "a", "value": 50 },
{ "category": "a", "value": 7 },
{ "category": "a", "value": 20 },
{ "category": "a", "value": 15 },
{ "category": "a", "value": 30 },
{ "category": "a", "value": 2 },
{ "category": "b", "value": 10 },
{ "category": "b", "value": 12 },
{ "category": "b", "value": 15 },
{ "category": "b", "value": 3 },
{ "category": "b", "value": 2 },
{ "category": "b", "value": 5 },
{ "category": "b", "value": 35 },
{ "category": "b", "value": 2 },
{ "category": "b", "value": 5 },
{ "category": "b", "value": 20 },
{ "category": "b", "value": 12 },
{ "category": "c", "value": 5 },
{ "category": "c", "value": 4 },
{ "category": "c", "value": 2 },
{ "category": "c", "value": 32 },
{ "category": "c", "value": 25 },
{ "category": "c", "value": 40 },
{ "category": "c", "value": 35 },
{ "category": "c", "value": 25 },
{ "category": "c", "value": 19 },
{ "category": "c", "value": 25 },
{ "category": "c", "value": 10 }
]