Small multiples (animated domain transition)
An example of how to do small multiples with the same rendering component. Because we want to calculate and store the extents for each series, we have to put the Layer Cake component in a wrapper component, called SmallMultipleWrapper.svelte below.
- +page.svelte
- ./_components/SmallMultipleWrapper.svelte
- ./_data/pointSeries.js
- ./_components/Line.svelte
<script>
import { calcExtents, flatten } from 'layercake';
import SmallMultipleWrapper from './_components/SmallMultipleWrapper.svelte';
// A list of series, each a list of { x, y } points
import pointSeries from './_data/pointSeries.js';
/** @type {Record<string, (d: any) => any>} */
const extentGetters = {
x: d => d.x,
y: d => d.y
};
// The extents across every series, for the shared scale option
const fullExtents = calcExtents(flatten(pointSeries), extentGetters);
// Order the charts by each series' last value, on a copy so the import stays as it is
const sortedSeries = [...pointSeries].sort((a, b) => b[b.length - 1].y - a[a.length - 1].y);
/** @type {'shared'|'individual'} */
let scale = $state('individual');
</script>
<div class="input-container">
<label><input type="radio" bind:group={scale} value="individual" />Individual scale</label>
<label><input type="radio" bind:group={scale} value="shared" />Shared scale</label>
</div>
<div class="group-container">
{#each sortedSeries as data}
<div class="small-multiple-container">
<SmallMultipleWrapper {data} {fullExtents} {scale} {extentGetters} />
</div>
{/each}
</div>
<style>
.group-container {
height: calc(100% - 40px);
width: 100%;
}
.input-container {
margin-bottom: 7px;
}
label {
cursor: pointer;
}
input {
margin-right: 7px;
}
/* Give the wrapper a width and height. LayerCake fills it. */
.small-multiple-container {
position: relative;
display: inline-block;
width: 11%;
height: 30%;
}
</style><!--
@component
Draws one small multiple: a line chart whose domains ease between its own extents and the shared extents of the whole set. Used by the [small multiples example](https://layercake.graphics/example/SmallMultiples).
-->
<script>
import { LayerCake, Svg, calcExtents } from 'layercake';
import { Tween } from 'svelte/motion';
import * as eases from 'svelte/easing';
import Line from './Line.svelte';
/**
* @typedef {Object} Props
* @property {Array<Object>} data - The rows for this one chart.
* @property {Record<string, [any, any]>} fullExtents - The x and y extents across every chart, as `calcExtents` returns them. Used when `scale` is 'shared'.
* @property {'shared'|'individual'} scale - Whether the domains come from every chart or from this chart's own rows.
* @property {Record<string, (d: any) => any>} extentGetters - The x and y accessors, e.g. `{ x: d => d.x, y: d => d.y }`.
*/
/** @type {Props} */
let { data, fullExtents, scale, extentGetters } = $props();
const tweenOptions = {
duration: 300,
easing: eases.cubicInOut
};
let extents = $derived(calcExtents(data, extentGetters));
// Each domain eases to its new target whenever `scale` flips or the rows change
const xDomain = Tween.of(() => (scale === 'shared' ? fullExtents.x : extents.x), tweenOptions);
const yDomain = Tween.of(() => (scale === 'shared' ? fullExtents.y : extents.y), tweenOptions);
</script>
<LayerCake
padding={{ top: 2, right: 6, bottom: 2, left: 6 }}
x={extentGetters.x}
y={extentGetters.y}
{data}
xDomain={xDomain.current}
yDomain={yDomain.current}
>
<Svg>
<Line stroke="#000" />
</Svg>
</LayerCake>export default [
[
{ x: 0, y: 0.3513332305465124 },
{ x: 1, y: -0.47850548294493284 },
{ x: 2, y: -0.8631762284263558 },
{ x: 3, y: -1.7484233826606137 },
{ x: 4, y: -1.5706727472497415 },
{ x: 5, y: -3.289713739464341 },
{ x: 6, y: -3.9730820042995005 },
{ x: 7, y: -2.745530296666686 },
{ x: 8, y: -3.5791092007187646 },
{ x: 9, y: -2.6641758464410152 }
],
[
{ x: 0, y: -2.1768831333979946 },
{ x: 1, y: -3.9534632619125096 },
{ x: 2, y: -3.899114148630141 },
{ x: 3, y: -3.9827562738951876 },
{ x: 4, y: -4.580294736167417 },
{ x: 5, y: -3.856065008784584 },
{ x: 6, y: -3.7484016156069195 },
{ x: 7, y: -4.251249481201894 },
{ x: 8, y: -4.469618989456487 },
{ x: 9, y: -4.402688785575379 }
],
[
{ x: 0, y: 0.8587657948567446 },
{ x: 1, y: 0.5079352772290244 },
{ x: 2, y: 2.701251831225464 },
{ x: 3, y: 5.837115995564179 },
{ x: 4, y: 6.760908500285659 },
{ x: 5, y: 6.0834936334060785 },
{ x: 6, y: 7.320640580003705 },
{ x: 7, y: 8.480047690829132 },
{ x: 8, y: 9.105945107644933 },
{ x: 9, y: 9.426539155610454 }
],
[
{ x: 0, y: 2.095248369393952 },
{ x: 1, y: 1.765188669621648 },
{ x: 2, y: 0.5467739943527758 },
{ x: 3, y: -0.3507100722398887 },
{ x: 4, y: 0.2983588210197782 },
{ x: 5, y: 0.5105812148122781 },
{ x: 6, y: 1.5437157564970827 },
{ x: 7, y: 2.3653169559429537 },
{ x: 8, y: 1.90924018284514 },
{ x: 9, y: 2.1356513687796674 }
],
[
{ x: 0, y: 0.5488385729500312 },
{ x: 1, y: 1.8670789082642192 },
{ x: 2, y: 2.206540934969421 },
{ x: 3, y: 3.055554299010695 },
{ x: 4, y: 0.4967425647902308 },
{ x: 5, y: 2.327901093516326 },
{ x: 6, y: 0.8992924851467803 },
{ x: 7, y: 1.8817986624215481 },
{ x: 8, y: 2.3891551227372205 },
{ x: 9, y: 1.133778319314648 }
],
[
{ x: 0, y: -0.3562898099723935 },
{ x: 1, y: 0.20565872246731903 },
{ x: 2, y: -0.1162117685820413 },
{ x: 3, y: 0.8631383539123323 },
{ x: 4, y: 3.2890516402408663 },
{ x: 5, y: 3.0857377702871545 },
{ x: 6, y: 1.0370651586546682 },
{ x: 7, y: -1.0186438338583623 },
{ x: 8, y: 0.14241054172118361 },
{ x: 9, y: 0.8412068911584337 }
],
[
{ x: 0, y: -0.7654061779170572 },
{ x: 1, y: -0.032595953968226454 },
{ x: 2, y: 0.2678472728835137 },
{ x: 3, y: 0.08563601239405039 },
{ x: 4, y: -0.0013330703820842171 },
{ x: 5, y: 1.4703345017728822 },
{ x: 6, y: 1.3856274424774901 },
{ x: 7, y: -0.20599108956133416 },
{ x: 8, y: -0.7751447950252981 },
{ x: 9, y: 0.47169212501954916 }
],
[
{ x: 0, y: -1.1732177326141833 },
{ x: 1, y: -2.7527274224702065 },
{ x: 2, y: -2.2211792447108714 },
{ x: 3, y: -1.017590856110545 },
{ x: 4, y: 0.6779112439466795 },
{ x: 5, y: 0.270071953934581 },
{ x: 6, y: -0.6558848145557117 },
{ x: 7, y: -0.057309434562747286 },
{ x: 8, y: -0.7458264810903046 },
{ x: 9, y: 0.5001744113836739 }
],
[
{ x: 0, y: -0.546732244433788 },
{ x: 1, y: -0.07416764769549289 },
{ x: 2, y: -1.6595417109999924 },
{ x: 3, y: -3.171184337736065 },
{ x: 4, y: -2.7367845673789564 },
{ x: 5, y: -2.4028017878731487 },
{ x: 6, y: -3.3855251261635013 },
{ x: 7, y: -3.914712672393975 },
{ x: 8, y: -3.0652727151850634 },
{ x: 9, y: -4.3807147718164945 }
],
[
{ x: 0, y: 0.5002117874054588 },
{ x: 1, y: -1.3975943832928739 },
{ x: 2, y: -2.547911521154404 },
{ x: 3, y: -1.5969200501057434 },
{ x: 4, y: -1.1764040680662173 },
{ x: 5, y: -1.492868534196866 },
{ x: 6, y: -1.8865830283320832 },
{ x: 7, y: -1.3073578086443587 },
{ x: 8, y: 0.12280679226177948 },
{ x: 9, y: -2.4386679354191343 }
],
[
{ x: 0, y: -0.8135433681734914 },
{ x: 1, y: -1.221075788028858 },
{ x: 2, y: -0.2744306894025812 },
{ x: 3, y: 0.7083803705971968 },
{ x: 4, y: -0.30123497298530666 },
{ x: 5, y: -0.12098193043768593 },
{ x: 6, y: 0.7779616569301503 },
{ x: 7, y: 0.24278467122340208 },
{ x: 8, y: 2.12035553113487 },
{ x: 9, y: 1.5777631433830899 }
],
[
{ x: 0, y: -1.2807077385033618 },
{ x: 1, y: -1.60918596863346 },
{ x: 2, y: -1.1252711445818604 },
{ x: 3, y: 0.1123443278338252 },
{ x: 4, y: 0.6765953813677427 },
{ x: 5, y: -0.24953981170929884 },
{ x: 6, y: -0.7245587949132168 },
{ x: 7, y: -0.1322418860127922 },
{ x: 8, y: -2.0267241146650887 },
{ x: 9, y: -2.203025286852793 }
],
[
{ x: 0, y: -0.5646593880324497 },
{ x: 1, y: 0.019675233652433954 },
{ x: 2, y: 1.1125492696390593 },
{ x: 3, y: -0.21768925566531694 },
{ x: 4, y: -0.43002048847289853 },
{ x: 5, y: 0.1472531927930274 },
{ x: 6, y: 0.9536777882928407 },
{ x: 7, y: 1.7662231600360088 },
{ x: 8, y: 2.3107906857269036 },
{ x: 9, y: 0.03169262048875865 }
],
[
{ x: 0, y: -1.4703405378184384 },
{ x: 1, y: -3.6660782113882835 },
{ x: 2, y: -2.1234430449995942 },
{ x: 3, y: -0.31491835255274725 },
{ x: 4, y: 0.2519911763297693 },
{ x: 5, y: -0.7593130835875026 },
{ x: 6, y: 0.27946963886864307 },
{ x: 7, y: -0.38601550782775373 },
{ x: 8, y: -1.7086440970313155 },
{ x: 9, y: -2.2184975489863223 }
],
[
{ x: 0, y: 1.075613382572133 },
{ x: 1, y: 1.5858773914182227 },
{ x: 2, y: 0.8770573429185515 },
{ x: 3, y: 1.2917422132464667 },
{ x: 4, y: 0.9866084663257535 },
{ x: 5, y: 1.1136430669870276 },
{ x: 6, y: 2.5087234218660477 },
{ x: 7, y: 3.897378190589307 },
{ x: 8, y: 3.4944058027154106 },
{ x: 9, y: 3.3350669636577703 }
],
[
{ x: 0, y: -0.769481078391433 },
{ x: 1, y: -1.7663885001671653 },
{ x: 2, y: -3.700748337973364 },
{ x: 3, y: -2.90481913516788 },
{ x: 4, y: -4.653428298468029 },
{ x: 5, y: -5.690638211312513 },
{ x: 6, y: -3.762776837320062 },
{ x: 7, y: -4.125948059447033 },
{ x: 8, y: -6.369088532937904 },
{ x: 9, y: -6.130469306897179 }
],
[
{ x: 0, y: -0.6060612391774423 },
{ x: 1, y: -0.1661630609170786 },
{ x: 2, y: -0.8301060910250655 },
{ x: 3, y: -0.7516298932551538 },
{ x: 4, y: 0.06309968596601889 },
{ x: 5, y: 0.23024684564640405 },
{ x: 6, y: -0.3769683028829788 },
{ x: 7, y: -0.8912667423333008 },
{ x: 8, y: -1.2396819684201017 },
{ x: 9, y: -0.38895690194817045 }
],
[
{ x: 0, y: -0.9114218426959718 },
{ x: 1, y: -0.060301791732889076 },
{ x: 2, y: -0.9270741950807107 },
{ x: 3, y: -2.0675258449919967 },
{ x: 4, y: -0.08373718479615966 },
{ x: 5, y: -0.742766389679131 },
{ x: 6, y: -0.3113686704234539 },
{ x: 7, y: 1.3283998112889834 },
{ x: 8, y: 1.7758763727813693 },
{ x: 9, y: 3.81386918977139 }
],
[
{ x: 0, y: 1.7176790534482675 },
{ x: 1, y: 2.0432025798611404 },
{ x: 2, y: 3.6581604675933796 },
{ x: 3, y: 2.940918317727456 },
{ x: 4, y: 1.7185613645563316 },
{ x: 5, y: 1.7819340726171955 },
{ x: 6, y: 0.6507861853791468 },
{ x: 7, y: 2.5951771651052367 },
{ x: 8, y: 3.519960937767535 },
{ x: 9, y: 3.197786396503866 }
],
[
{ x: 0, y: -0.3038191596502425 },
{ x: 1, y: -1.3685608331479382 },
{ x: 2, y: 0.5634023938007005 },
{ x: 3, y: 0.7985300339161426 },
{ x: 4, y: 0.015410817527624188 },
{ x: 5, y: 0.9718003621065988 },
{ x: 6, y: 1.2175926771772418 },
{ x: 7, y: -0.45971510207922317 },
{ x: 8, y: -1.7925772720518218 },
{ x: 9, y: -2.797757779872802 }
],
[
{ x: 0, y: 0.8863594890626845 },
{ x: 1, y: 0.4805543692922663 },
{ x: 2, y: -0.21233113644620377 },
{ x: 3, y: -0.5651934422185125 },
{ x: 4, y: 0.6977913923481813 },
{ x: 5, y: 1.9747582290228265 },
{ x: 6, y: 0.9058940775608975 },
{ x: 7, y: 2.164448517902702 },
{ x: 8, y: 1.200779603279385 },
{ x: 9, y: 0.27011411254519535 }
],
[
{ x: 0, y: 0.8102833184946229 },
{ x: 1, y: 1.4974853704340667 },
{ x: 2, y: -0.2511326270639147 },
{ x: 3, y: -1.4887219856377514 },
{ x: 4, y: -2.054165795834861 },
{ x: 5, y: -0.7110079453402081 },
{ x: 6, y: 1.2224455696568188 },
{ x: 7, y: 0.10576404901318259 },
{ x: 8, y: -0.5577986193258884 },
{ x: 9, y: -0.8307701610339031 }
],
[
{ x: 0, y: -0.754339359890586 },
{ x: 1, y: -0.28422901710237364 },
{ x: 2, y: 0.4575829777241672 },
{ x: 3, y: 0.6214246890384195 },
{ x: 4, y: 1.1950848608542208 },
{ x: 5, y: 0.12829030929988217 },
{ x: 6, y: 0.9916165486492478 },
{ x: 7, y: 0.07713732189769096 },
{ x: 8, y: 1.3185227211734212 },
{ x: 9, y: 1.3790849065109583 }
],
[
{ x: 0, y: -1.0383242310768992 },
{ x: 1, y: -0.36189660554379044 },
{ x: 2, y: 1.7026078322176184 },
{ x: 3, y: 2.4581042624776677 },
{ x: 4, y: 1.2587470748265426 },
{ x: 5, y: 0.17311307445802093 },
{ x: 6, y: -0.2972726991489642 },
{ x: 7, y: -1.0284350477870043 },
{ x: 8, y: -0.4409267468949597 },
{ x: 9, y: -1.721194506127408 }
],
[
{ x: 0, y: 0.9497890648486154 },
{ x: 1, y: -0.7840480109209655 },
{ x: 2, y: -3.0537174943564764 },
{ x: 3, y: -4.003323211985304 },
{ x: 4, y: -3.650725391139404 },
{ x: 5, y: -5.195623583848551 },
{ x: 6, y: -6.579180832109046 },
{ x: 7, y: -6.410177263118323 },
{ x: 8, y: -7.023259052330267 },
{ x: 9, y: -6.216863081739327 }
],
[
{ x: 0, y: -0.4428908643957123 },
{ x: 1, y: -0.8778820735472277 },
{ x: 2, y: -0.1642563408395692 },
{ x: 3, y: -0.22904137849126743 },
{ x: 4, y: 0.48944499719915696 },
{ x: 5, y: 1.813325690012508 },
{ x: 6, y: 2.354462578631868 },
{ x: 7, y: 2.8557880465926715 },
{ x: 8, y: 3.6456850324758125 },
{ x: 9, y: 4.145717439210561 }
],
[
{ x: 0, y: 0.13059426813587155 },
{ x: 1, y: 0.3755092236260167 },
{ x: 2, y: 1.8320734188682832 },
{ x: 3, y: 1.7688926504783191 },
{ x: 4, y: 2.7160551052985875 },
{ x: 5, y: 3.5367959655320327 },
{ x: 6, y: 4.489059997755517 },
{ x: 7, y: 3.4576184763756963 },
{ x: 8, y: 2.629075492886139 },
{ x: 9, y: 1.9224087765098758 }
]
];<!--
@component
Generates an SVG line shape.
-->
<script>
import { getLayerCakeContext } from 'layercake';
const k = getLayerCakeContext();
/**
* @typedef {Object} Props
* @property {string} [stroke='#ab00d6'] - The line's stroke color.
*/
/** @type {Props} */
let { stroke = '#ab00d6' } = $props();
let path = $derived(
'M' +
k.data
.map(d => {
return k.xGet(d) + ',' + k.yGet(d);
})
.join('L')
);
</script>
<path class="path-line" d={path} {stroke}></path>
<style>
.path-line {
fill: none;
stroke-linejoin: round;
stroke-linecap: round;
stroke-width: 2px;
}
</style>