Skip to content

Commit 925a086

Browse files
committed
[Brush] Begin to support scaleBand() (Bar charts)
1 parent 5b2cb90 commit 925a086

File tree

3 files changed

+75
-7
lines changed

3 files changed

+75
-7
lines changed

.changeset/metal-windows-wait.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'layerchart': minor
3+
---
4+
5+
[Brush] Support scaleBand() (Bar charts)

packages/layerchart/src/lib/components/Brush.svelte

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import { clamp, cls } from 'svelte-ux';
77
import Frame from './Frame.svelte';
88
import { localPoint } from '$lib/utils/event.js';
9+
import { scaleInvert } from '$lib/utils/scales.js';
910
import Group from './Group.svelte';
1011
1112
const { xScale, yScale, width, height, padding } = getContext('LayerCake');
@@ -61,21 +62,22 @@
6162
) => void
6263
) {
6364
return (e: PointerEvent) => {
65+
// TODO: Handle scaleBand domains
6466
const start = {
6567
xDomain: [xDomain[0] ?? xDomainMin, xDomain[1] ?? xDomainMax],
6668
yDomain: [yDomain[0] ?? yDomainMin, yDomain[1] ?? yDomainMax],
6769
value: {
68-
x: $xScale.invert(localPoint(frameEl, e)?.x - $padding.left),
69-
y: $yScale.invert(localPoint(frameEl, e)?.y - $padding.top),
70+
x: scaleInvert($xScale, localPoint(frameEl, e)?.x - $padding.left),
71+
y: scaleInvert($yScale, localPoint(frameEl, e)?.y - $padding.top),
7072
},
7173
};
7274
7375
dispatch('brushStart', { xDomain, yDomain });
7476
7577
const onPointerMove = (e: PointerEvent) => {
7678
fn(start, {
77-
x: $xScale.invert(localPoint(frameEl, e)?.x - $padding.left),
78-
y: $yScale.invert(localPoint(frameEl, e)?.y - $padding.top),
79+
x: scaleInvert($xScale, localPoint(frameEl, e)?.x - $padding.left),
80+
y: scaleInvert($yScale, localPoint(frameEl, e)?.y - $padding.top),
7981
});
8082
8183
// if (xDomain[0] === xDomain[1] || yDomain[0] === yDomain[1]) {

packages/layerchart/src/routes/docs/components/Brush/+page.svelte

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
<script lang="ts">
2-
import { scaleOrdinal, scaleTime } from 'd3-scale';
3-
import { range } from 'd3-array';
4-
import { PeriodType, State, cls, format } from 'svelte-ux';
2+
import { scaleBand, scaleOrdinal, scaleTime } from 'd3-scale';
3+
import { bin, range, sum } from 'd3-array';
4+
import { timeMonths } from 'd3-time';
5+
import { PeriodType, State, cls, format, formatDate } from 'svelte-ux';
56
import { subDays } from 'date-fns';
67
import { mdiChevronRight } from '@mdi/js';
78
@@ -19,6 +20,7 @@
1920
Rule,
2021
Tooltip,
2122
Svg,
23+
Bars,
2224
} from 'layerchart';
2325
2426
import Preview from '$lib/docs/Preview.svelte';
@@ -39,10 +41,69 @@
3941
const randomData = range(200).map((d) => {
4042
return { x: d, y: Math.random() };
4143
});
44+
45+
$: binByTime = bin()
46+
.thresholds((_data, min, max) => timeMonths(min, max))
47+
.value((d) => d.date);
48+
$: appleStockBinByMonth = binByTime(data.appleStock);
49+
// Simplify data for simplier brush example
50+
$: appleStockByMonth = appleStockBinByMonth.map((monthBin) => {
51+
return {
52+
date: monthBin.x0,
53+
value: sum(monthBin, (d) => d.value),
54+
};
55+
});
4256
</script>
4357

4458
<h1>Examples</h1>
4559

60+
<h2>Bar (scaleBand) support</h2>
61+
62+
<Preview data={appleStockByMonth}>
63+
<div class="border rounded p-4 grid gap-1">
64+
<State initial={[null, null]} let:value={xDomain} let:set>
65+
<div class="h-[300px]">
66+
<Chart
67+
_data={appleStockByMonth}
68+
data={appleStockByMonth.filter(
69+
(d) =>
70+
(xDomain[0] == null || d.date >= xDomain[0]) &&
71+
(xDomain[1] == null || d.date <= xDomain[1])
72+
)}
73+
x="date"
74+
xScale={scaleBand().padding(0.2)}
75+
y="value"
76+
yDomain={[0, null]}
77+
yNice
78+
padding={{ left: 24, bottom: 24 }}
79+
>
80+
<Svg>
81+
<Axis placement="left" grid rule />
82+
<Axis
83+
placement="bottom"
84+
rule
85+
ticks={(scale) => scaleTime(scale.domain(), scale.range()).ticks(4)}
86+
format={(value) => formatDate(value, PeriodType.Custom, { custom: 'MMM yyyy' })}
87+
/>
88+
<ChartClipPath>
89+
<Bars radius={4} strokeWidth={1} class="fill-primary" />
90+
</ChartClipPath>
91+
92+
<Brush
93+
axis="x"
94+
resetOnEnd
95+
on:brushEnd={(e) => {
96+
console.log(e.detail);
97+
set(e.detail.xDomain);
98+
}}
99+
/>
100+
</Svg>
101+
</Chart>
102+
</div>
103+
</State>
104+
</div>
105+
</Preview>
106+
46107
<h2>Styling via classes</h2>
47108

48109
<Preview data={data.appleStock}>

0 commit comments

Comments
 (0)