Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/pink-hornets-rest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'layerchart': patch
---

refactor: Replace `date-fns` usage with existing `d3-time` to reduce bundle size
1 change: 0 additions & 1 deletion packages/layerchart/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@
"d3-shape": "^3.2.0",
"d3-tile": "^1.0.0",
"d3-time": "^3.1.0",
"date-fns": "^4.1.0",
"lodash-es": "^4.17.21",
"runed": "^0.28.0"
},
Expand Down
6 changes: 3 additions & 3 deletions packages/layerchart/src/lib/components/MonthPath.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
</script>

<script lang="ts">
import { timeWeek, timeYear } from 'd3-time';
import { endOfMonth } from 'date-fns';
import { timeWeek, timeMonth, timeYear } from 'd3-time';
import { endOfInterval } from '$lib/utils/date.js';
import { cls } from '@layerstack/tailwind';
import { layerClass } from '$lib/utils/attributes.js';
import Spline, { type SplinePropsWithoutHTML } from './Spline.svelte';
Expand All @@ -58,7 +58,7 @@
const startWeek = $derived(timeWeek.count(timeYear(date), date));

// end of month
const monthEnd = $derived(endOfMonth(date));
const monthEnd = $derived(endOfInterval(date, timeMonth));
const endDayOfWeek = $derived(monthEnd.getDay());
const endWeek = $derived(timeWeek.count(timeYear(monthEnd), monthEnd));

Expand Down
12 changes: 12 additions & 0 deletions packages/layerchart/src/lib/utils/date.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { type TimeInterval } from 'd3-time';

/**
* Get the date at the end of the interval
* Similar to `interval.ceil(date)` except:
* - returns end of day instead of start of next day
* - properly handles start of day (i.e. not return same date)
*/
export function endOfInterval(date: Date, interval: TimeInterval) {
// Can not use `new Date(+interval.ceil(date) - 1)`; as `.ceil()` will return same date when start of the day (matching `.floor()`)
return new Date(interval.offset(interval.floor(date), 1).getTime() - 1);
}
12 changes: 6 additions & 6 deletions packages/layerchart/src/lib/utils/genData.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { addMinutes, startOfDay, startOfToday, subDays } from 'date-fns';
import { timeMinute, timeDay } from 'd3-time';
import { cumsum } from 'd3-array';
import { randomNormal } from 'd3-random';

Expand Down Expand Up @@ -65,7 +65,7 @@ export function createDateSeries<TKey extends string>(options: {
keys?: TKey[];
value?: 'number' | 'integer';
}) {
const now = startOfToday();
const now = timeDay.floor(new Date());

const count = options.count ?? 10;
const min = options.min;
Expand All @@ -74,7 +74,7 @@ export function createDateSeries<TKey extends string>(options: {

return Array.from({ length: count }).map((_, i) => {
return {
date: subDays(now, count - i - 1),
date: timeDay.offset(now, -count + i),
...Object.fromEntries(
keys.map((key) => {
return [
Expand All @@ -99,11 +99,11 @@ export function createTimeSeries<TKey extends string>(options: {
const max = options.max;
const keys = options.keys ?? ['value'];

let lastStartDate = startOfDay(new Date());
let lastStartDate = timeDay.floor(new Date());

const timeSeries = Array.from({ length: count }).map((_, i) => {
const startDate = addMinutes(lastStartDate, getRandomInteger(0, 60));
const endDate = addMinutes(startDate, getRandomInteger(5, 60));
const startDate = timeMinute.offset(lastStartDate, getRandomInteger(0, 60));
const endDate = timeMinute.offset(startDate, getRandomInteger(5, 60));
lastStartDate = startDate;
return {
name: `item ${i + 1}`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
} from 'layerchart';
import { curveBasis, curveCatmullRom, curveStepAfter } from 'd3-shape';
import { group } from 'd3-array';
import { Button, Field, ToggleGroup, ToggleOption, Kbd, Switch } from 'svelte-ux';
import { timeDay } from 'd3-time';
import { Button, Field, Kbd, Switch } from 'svelte-ux';
import { format, sortFunc } from '@layerstack/utils';
import { addDays } from 'date-fns';
import { cls } from '@layerstack/tailwind';

import Preview from '$lib/docs/Preview.svelte';
Expand Down Expand Up @@ -55,11 +55,11 @@

const now = new Date();
const denseDateSeriesData = randomWalk({ count: 1000 }).map((value, i) => ({
date: addDays(now, i),
date: timeDay.offset(now, i),
value: 10 + value,
}));
const denseDateSeriesData2 = randomWalk({ count: 1000 }).map((value, i) => ({
date: addDays(now, i),
date: timeDay.offset(now, i),
value: 10 + value,
}));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<script lang="ts">
import { scaleBand, scaleOrdinal, scaleTime } from 'd3-scale';
import { range } from 'd3-array';
import { timeDay } from 'd3-time';
import { State } from 'svelte-ux';
import { format } from '@layerstack/utils';
import { cls } from '@layerstack/tailwind';
import { subDays } from 'date-fns';
import { mdiChevronLeft, mdiChevronRight } from '@mdi/js';

import {
Expand Down Expand Up @@ -32,13 +32,27 @@
let { data } = $props();

const now = new Date();
let xDomain = $state([subDays(now, 60), subDays(now, 30)]) as DomainType | undefined;
let xDomain = $state([timeDay.offset(now, -60), timeDay.offset(now, -30)]) as
| DomainType
| undefined;

const seriesData = [
randomWalk({ count: 100 }).map((value, i) => ({ date: subDays(now, i), value: 10 + value })),
randomWalk({ count: 100 }).map((value, i) => ({ date: subDays(now, i), value: 10 + value })),
randomWalk({ count: 100 }).map((value, i) => ({ date: subDays(now, i), value: 10 + value })),
randomWalk({ count: 100 }).map((value, i) => ({ date: subDays(now, i), value: 10 + value })),
randomWalk({ count: 100 }).map((value, i) => ({
date: timeDay.offset(now, -i),
value: 10 + value,
})),
randomWalk({ count: 100 }).map((value, i) => ({
date: timeDay.offset(now, -i),
value: 10 + value,
})),
randomWalk({ count: 100 }).map((value, i) => ({
date: timeDay.offset(now, -i),
value: 10 + value,
})),
randomWalk({ count: 100 }).map((value, i) => ({
date: timeDay.offset(now, -i),
value: 10 + value,
})),
];

const randomData = range(200).map((d) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
<script lang="ts">
import { startOfYear, endOfYear } from 'date-fns';
import { scaleThreshold } from 'd3-scale';
import { range } from 'd3-array';
import { timeYear } from 'd3-time';

import { Calendar, Chart, Group, Text, Tooltip, Layer } from 'layerchart';

import Preview from '$lib/docs/Preview.svelte';
import { createDateSeries } from '$lib/utils/genData.js';
import { shared } from '../../shared.svelte.js';
import { endOfInterval } from '$lib/utils/date.js';

const now = new Date();
const firstDayOfYear = startOfYear(now);
const lastDayOfYear = endOfYear(now);
const firstDayOfYear = timeYear.floor(now);
const lastDayOfYear = endOfInterval(now, timeYear);

const data = createDateSeries({ count: 365 * 4, min: 10, max: 100, value: 'integer' }).map(
(d) => {
Expand Down Expand Up @@ -146,7 +147,7 @@
<Layer type={shared.renderContext}>
{#each range(2019, 2024) as year, i}
{@const start = new Date(year, 0, 1)}
{@const end = endOfYear(start)}
{@const end = endOfInterval(start, timeYear)}
<Group y={140 * i}>
<Text
value={year}
Expand Down
11 changes: 5 additions & 6 deletions packages/layerchart/src/routes/docs/components/Pie/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<script lang="ts">
import { format } from 'date-fns';
import { sum } from 'd3-array';
import { cls } from '@layerstack/tailwind';
import { format as formatUtil } from '@layerstack/utils';
import { format } from '@layerstack/utils';

import { Arc, Chart, Group, Layer, Pie, Text, Tooltip } from 'layerchart';

Expand Down Expand Up @@ -278,7 +277,7 @@
{#snippet children({ getArcTextProps })}
{@const textProps = getArcTextProps('centroid')}
<Text
value={formatUtil(arc.data.value / dataSum, 'percent')}
value={format(arc.data.value / dataSum, 'percent')}
{...textProps}
dy={-8}
class={cls('text-base', colors.content)}
Expand Down Expand Up @@ -411,7 +410,7 @@
</Layer>
<Tooltip.Root>
{#snippet children({ data })}
<Tooltip.Header>{format(data.date, 'eee, MMMM do')}</Tooltip.Header>
<Tooltip.Header value={data.date} format="day" />
<Tooltip.List>
<Tooltip.Item label="value" value={data.value} format="integer" valueAlign="right" />
<Tooltip.Item
Expand Down Expand Up @@ -461,7 +460,7 @@
>
{#snippet children({ getArcTextProps })}
<Text
value={formatUtil(arc.data.value / dataSum, 'percent')}
value={format(arc.data.value / dataSum, 'percent')}
{...getArcTextProps('centroid')}
class={cls('text-base', colors.content)}
/>
Expand All @@ -475,7 +474,7 @@

<Tooltip.Root>
{#snippet children({ data })}
<Tooltip.Header>{format(data.date, 'eee, MMMM do')}</Tooltip.Header>
<Tooltip.Header value={data.date} format="day" />
<Tooltip.List>
<Tooltip.Item label="value" value={data.value} format="integer" valueAlign="right" />
<Tooltip.Item
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import { scaleTime } from 'd3-scale';
import { addMinutes, startOfDay } from 'date-fns';
import { timeMinute, timeDay } from 'd3-time';
import { Duration } from 'svelte-ux';

import { BarChart, Points, Tooltip } from 'layerchart';
Expand All @@ -10,12 +10,12 @@
import { shared } from '../../shared.svelte.js';

const count = 10;
const now = startOfDay(new Date());
const now = timeDay.floor(new Date());
let lastStartDate = now;

const data = Array.from({ length: count }).map((_, i) => {
const startDate = addMinutes(lastStartDate, getRandomInteger(0, 60));
const endDate = addMinutes(startDate, getRandomInteger(0, 60));
const startDate = timeMinute.offset(lastStartDate, getRandomInteger(0, 60));
const endDate = timeMinute.offset(startDate, getRandomInteger(0, 60));
lastStartDate = startDate;
return {
name: `Item ${i + 1}`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
randomNormal,
randomUniform,
} from 'd3-random';
import { timeDays, timeMonths, timeWeeks } from 'd3-time';
import { subDays } from 'date-fns';
import { timeDay, timeMonth, timeWeek } from 'd3-time';

import { BarChart, Tooltip, thresholdTime } from 'layerchart';
import { MenuField, RangeField, NumberStepper, State } from 'svelte-ux';
Expand Down Expand Up @@ -46,7 +45,9 @@
const now = new Date();
let dateRange = $state(10);
const randomDateData = $derived(
Array.from({ length: randomCount }, () => getRandomDate(subDays(now, dateRange), now)) as any[]
Array.from({ length: randomCount }, () =>
getRandomDate(timeDay.offset(now, -dateRange), now)
) as any[]
); // TODO: Make typescript happy

let renderContext = $derived(shared.renderContext as 'svg' | 'canvas');
Expand Down Expand Up @@ -284,7 +285,7 @@
</Preview>
</State>

<State initial={{ intervalValue: 'weeks', intervalFunc: timeWeeks }} let:value let:set>
<State initial={{ intervalValue: 'weeks', intervalFunc: timeWeek.range }} let:value let:set>
{@const binByTime = bin().thresholds(
(_data, min, max) =>
value?.intervalFunc(new Date(min), new Date(max)).map((d) => d.valueOf()) ?? []
Expand All @@ -298,9 +299,9 @@
<MenuField
label="Interval"
options={[
{ label: 'Days', value: 'days', interval: timeDays },
{ label: 'Weeks', value: 'weeks', interval: timeWeeks },
{ label: 'Months', value: 'months', interval: timeMonths },
{ label: 'Days', value: 'days', interval: timeDay.range },
{ label: 'Weeks', value: 'weeks', interval: timeWeek.range },
{ label: 'Months', value: 'months', interval: timeMonth.range },
]}
value={value?.intervalValue}
on:change={(e) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { scaleBand } from 'd3-scale';
import { range } from 'd3-array';
import { getDay, getWeek } from 'date-fns';
import { timeWeek, timeYear } from 'd3-time';

import { Highlight, ScatterChart, Tooltip } from 'layerchart';

Expand All @@ -24,9 +24,9 @@
<div class="h-[300px] p-4 border rounded-sm">
<ScatterChart
{data}
x={(d) => getWeek(d.date)}
x={(d) => timeWeek.count(timeYear(d.date), d.date)}
xScale={scaleBand()}
y={(d) => getDay(d.date)}
y={(d) => d.date.getDay()}
yScale={scaleBand()}
yDomain={range(7)}
r="value"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<script lang="ts">
import { scaleTime, scaleThreshold } from 'd3-scale';
import { format } from 'date-fns';

import { Axis, Chart, Highlight, Labels, Layer, Points, Tooltip } from 'layerchart';

Expand Down Expand Up @@ -65,7 +64,7 @@

<Tooltip.Root>
{#snippet children({ data })}
<Tooltip.Header>{format(data.date, 'eee, MMMM do')}</Tooltip.Header>
<Tooltip.Header value={data.date} format="day" />
<Tooltip.List>
<Tooltip.Item label="value" value={data.value} />
</Tooltip.List>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<script lang="ts">
import { format } from 'date-fns';

import { BarChart, Tooltip } from 'layerchart';
import { format } from '@layerstack/utils';

import Preview from '$lib/docs/Preview.svelte';
import { createDateSeries } from '$lib/utils/genData.js';
Expand Down Expand Up @@ -103,7 +102,7 @@
>
{#snippet children({ data })}
<div class="whitespace-nowrap">
{format(data.date, 'eee, MMM do')}
{format(data.date, 'day')}
</div>
<div class="font-semibold">
{data.value}
Expand Down Expand Up @@ -141,7 +140,7 @@
xOffset={0}
>
{#snippet children({ data })}
<Tooltip.Header>{format(data.date, 'eee, MMM do')}</Tooltip.Header>
<Tooltip.Header value={data.date} format="day" />
<Tooltip.List>
<Tooltip.Item label="value" value={data.value} />
</Tooltip.List>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<script lang="ts">
import { format } from 'date-fns';

import { LineChart, Tooltip } from 'layerchart';
import { format } from '@layerstack/utils';

import Preview from '$lib/docs/Preview.svelte';
import { createDateSeries } from '$lib/utils/genData.js';
Expand Down Expand Up @@ -86,7 +85,7 @@
>
{#snippet children({ data })}
<div class="whitespace-nowrap">
{format(data.date, 'eee, MMM do')}
{format(data.date, 'day')}
</div>
<div class="font-semibold">
{data.value}
Expand Down Expand Up @@ -127,7 +126,7 @@
>
{#snippet children({ data })}
<div class="whitespace-nowrap">
{format(data.date, 'eee, MMM do')}
{format(data.date, 'day')}
</div>
<div class="font-semibold">
{data.value}
Expand Down
Loading