layerchart 2.0.0-next.7 → 2.0.0-next.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Chart.svelte +2 -2
- package/dist/components/Spline.svelte +1 -1
- package/dist/components/charts/BarChart.svelte +53 -38
- package/dist/docs/Code.svelte +4 -4
- package/dist/docs/Code.svelte.d.ts +4 -4
- package/dist/docs/Json.svelte +10 -1
- package/dist/docs/Json.svelte.d.ts +8 -5
- package/dist/docs/TilesetField.svelte +20 -19
- package/dist/docs/TilesetField.svelte.d.ts +5 -22
- package/dist/utils/scales.svelte.d.ts +3 -2
- package/dist/utils/scales.svelte.js +7 -3
- package/dist/utils/ticks.js +7 -1
- package/package.json +1 -1
|
@@ -844,12 +844,12 @@
|
|
|
844
844
|
if (verbose === true) {
|
|
845
845
|
if (width <= 0 && isMounted === true) {
|
|
846
846
|
console.warn(
|
|
847
|
-
|
|
847
|
+
`[LayerChart] Target div has zero or negative width (${width}). Did you forget to set an explicit width in CSS on the container?`
|
|
848
848
|
);
|
|
849
849
|
}
|
|
850
850
|
if (height <= 0 && isMounted === true) {
|
|
851
851
|
console.warn(
|
|
852
|
-
|
|
852
|
+
`[LayerChart] Target div has zero or negative height (${height}). Did you forget to set an explicit height in CSS on the container?`
|
|
853
853
|
);
|
|
854
854
|
}
|
|
855
855
|
}
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
|
|
85
85
|
<script lang="ts" generics="TData">
|
|
86
86
|
import { onMount, type ComponentProps } from 'svelte';
|
|
87
|
-
import { scaleBand, scaleLinear } from 'd3-scale';
|
|
87
|
+
import { scaleBand, scaleLinear, scaleTime } from 'd3-scale';
|
|
88
88
|
import { stack, stackOffsetDiverging, stackOffsetExpand, stackOffsetNone } from 'd3-shape';
|
|
89
89
|
import { format } from '@layerstack/utils';
|
|
90
90
|
import { cls } from '@layerstack/tailwind';
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
import { asAny } from '../../utils/types.js';
|
|
110
110
|
import type { Insets } from '../../utils/rect.svelte.js';
|
|
111
111
|
import type { SeriesData, SimplifiedChartProps, SimplifiedChartPropsObject } from './types.js';
|
|
112
|
-
import type
|
|
112
|
+
import { isScaleTime, type AnyScale } from '../../utils/scales.svelte.js';
|
|
113
113
|
import { createLegendProps, SeriesState } from './utils.svelte.js';
|
|
114
114
|
import { setTooltipMetaContext } from '../tooltip/tooltipMetaContext.js';
|
|
115
115
|
import DefaultTooltip from './DefaultTooltip.svelte';
|
|
@@ -171,15 +171,56 @@
|
|
|
171
171
|
const isStackSeries = $derived(seriesLayout.startsWith('stack'));
|
|
172
172
|
const isGroupSeries = $derived(seriesLayout === 'group');
|
|
173
173
|
|
|
174
|
+
const chartData: Array<TData & { stackData?: any }> = $derived.by(() => {
|
|
175
|
+
let _chartData = (
|
|
176
|
+
seriesState.allSeriesData.length ? seriesState.allSeriesData : chartDataArray(data)
|
|
177
|
+
) as Array<TData & { stackData?: any }>;
|
|
178
|
+
if (isStackSeries) {
|
|
179
|
+
const seriesKeys = seriesState.visibleSeries.map((s) => s.key);
|
|
180
|
+
|
|
181
|
+
const offset =
|
|
182
|
+
seriesLayout === 'stackExpand'
|
|
183
|
+
? stackOffsetExpand
|
|
184
|
+
: seriesLayout === 'stackDiverging'
|
|
185
|
+
? stackOffsetDiverging
|
|
186
|
+
: stackOffsetNone;
|
|
187
|
+
const stackData = stack()
|
|
188
|
+
.keys(seriesKeys)
|
|
189
|
+
.value((d, key) => {
|
|
190
|
+
const s = series.find((d) => d.key === key)!;
|
|
191
|
+
return accessor(s.value ?? s.key)(d as any);
|
|
192
|
+
})
|
|
193
|
+
.offset(offset)(chartDataArray(data)) as any[];
|
|
194
|
+
|
|
195
|
+
_chartData = _chartData.map((d, i) => {
|
|
196
|
+
return {
|
|
197
|
+
...d,
|
|
198
|
+
stackData: stackData.map((sd) => sd[i]),
|
|
199
|
+
};
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
return _chartData;
|
|
203
|
+
});
|
|
204
|
+
|
|
174
205
|
const xScale = $derived(
|
|
175
|
-
xScaleProp ??
|
|
206
|
+
xScaleProp ??
|
|
207
|
+
(isVertical
|
|
208
|
+
? scaleBand().padding(bandPadding)
|
|
209
|
+
: accessor(xProp)(chartData[0]) instanceof Date // TODO: also check for Array<Date> instances (ex. x={['start', 'end']})
|
|
210
|
+
? scaleTime()
|
|
211
|
+
: scaleLinear())
|
|
176
212
|
);
|
|
177
|
-
const xBaseline = $derived(isVertical ? undefined : 0);
|
|
213
|
+
const xBaseline = $derived(isVertical || isScaleTime(xScale) ? undefined : 0);
|
|
178
214
|
|
|
179
215
|
const yScale = $derived(
|
|
180
|
-
yScaleProp ??
|
|
216
|
+
yScaleProp ??
|
|
217
|
+
(isVertical
|
|
218
|
+
? accessor(yProp)(chartData[0]) instanceof Date // TODO: also check for Array<Date> instances (ex. y={['start', 'end']})
|
|
219
|
+
? scaleTime()
|
|
220
|
+
: scaleLinear()
|
|
221
|
+
: scaleBand().padding(bandPadding))
|
|
181
222
|
);
|
|
182
|
-
const yBaseline = $derived(isVertical ? 0 : undefined);
|
|
223
|
+
const yBaseline = $derived(isVertical || isScaleTime(yScale) ? 0 : undefined);
|
|
183
224
|
|
|
184
225
|
const x1Scale = $derived(
|
|
185
226
|
isGroupSeries && isVertical ? scaleBand().padding(groupPadding) : undefined
|
|
@@ -214,37 +255,6 @@
|
|
|
214
255
|
return d && typeof d === 'object' && 'stackData' in d;
|
|
215
256
|
}
|
|
216
257
|
|
|
217
|
-
const chartData: Array<TData & { stackData?: any }> = $derived.by(() => {
|
|
218
|
-
let _chartData = (
|
|
219
|
-
seriesState.allSeriesData.length ? seriesState.allSeriesData : chartDataArray(data)
|
|
220
|
-
) as Array<TData & { stackData?: any }>;
|
|
221
|
-
if (isStackSeries) {
|
|
222
|
-
const seriesKeys = seriesState.visibleSeries.map((s) => s.key);
|
|
223
|
-
|
|
224
|
-
const offset =
|
|
225
|
-
seriesLayout === 'stackExpand'
|
|
226
|
-
? stackOffsetExpand
|
|
227
|
-
: seriesLayout === 'stackDiverging'
|
|
228
|
-
? stackOffsetDiverging
|
|
229
|
-
: stackOffsetNone;
|
|
230
|
-
const stackData = stack()
|
|
231
|
-
.keys(seriesKeys)
|
|
232
|
-
.value((d, key) => {
|
|
233
|
-
const s = series.find((d) => d.key === key)!;
|
|
234
|
-
return accessor(s.value ?? s.key)(d as any);
|
|
235
|
-
})
|
|
236
|
-
.offset(offset)(chartDataArray(data)) as any[];
|
|
237
|
-
|
|
238
|
-
_chartData = _chartData.map((d, i) => {
|
|
239
|
-
return {
|
|
240
|
-
...d,
|
|
241
|
-
stackData: stackData.map((sd) => sd[i]),
|
|
242
|
-
};
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
return _chartData;
|
|
246
|
-
});
|
|
247
|
-
|
|
248
258
|
function getBarsProps(s: SeriesData<TData, typeof Bars>, i: number): ComponentProps<typeof Bars> {
|
|
249
259
|
const isFirst = i == 0;
|
|
250
260
|
const isLast = i == seriesState.visibleSeries.length - 1;
|
|
@@ -278,7 +288,12 @@
|
|
|
278
288
|
y: isVertical ? valueAccessor : undefined,
|
|
279
289
|
x1: isVertical && isGroupSeries ? (d) => s.value ?? s.key : undefined,
|
|
280
290
|
y1: !isVertical && isGroupSeries ? (d) => s.value ?? s.key : undefined,
|
|
281
|
-
rounded:
|
|
291
|
+
rounded:
|
|
292
|
+
isStackLayout && i !== seriesState.visibleSeries.length - 1
|
|
293
|
+
? 'none'
|
|
294
|
+
: Array.isArray(xProp) || Array.isArray(yProp)
|
|
295
|
+
? 'all'
|
|
296
|
+
: 'edge',
|
|
282
297
|
radius: 4,
|
|
283
298
|
strokeWidth: 1,
|
|
284
299
|
insets: stackInsets,
|
package/dist/docs/Code.svelte
CHANGED
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
class: className,
|
|
15
15
|
}: {
|
|
16
16
|
source: string | null;
|
|
17
|
-
language
|
|
18
|
-
highlightedSource
|
|
19
|
-
classes
|
|
17
|
+
language?: string;
|
|
18
|
+
highlightedSource?: string;
|
|
19
|
+
classes?: {
|
|
20
20
|
root?: string;
|
|
21
21
|
pre?: string;
|
|
22
22
|
code?: string;
|
|
23
23
|
};
|
|
24
|
-
class
|
|
24
|
+
class?: string;
|
|
25
25
|
} = $props();
|
|
26
26
|
</script>
|
|
27
27
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import 'prism-svelte';
|
|
2
2
|
type $$ComponentProps = {
|
|
3
3
|
source: string | null;
|
|
4
|
-
language
|
|
5
|
-
highlightedSource
|
|
6
|
-
classes
|
|
4
|
+
language?: string;
|
|
5
|
+
highlightedSource?: string;
|
|
6
|
+
classes?: {
|
|
7
7
|
root?: string;
|
|
8
8
|
pre?: string;
|
|
9
9
|
code?: string;
|
|
10
10
|
};
|
|
11
|
-
class
|
|
11
|
+
class?: string;
|
|
12
12
|
};
|
|
13
13
|
declare const Code: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
14
14
|
type Code = ReturnType<typeof Code>;
|
package/dist/docs/Json.svelte
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { type ComponentProps } from 'svelte';
|
|
2
3
|
import JsonTree from 'svelte-json-tree';
|
|
3
4
|
import { cls } from '@layerstack/tailwind';
|
|
4
5
|
|
|
5
|
-
const {
|
|
6
|
+
const {
|
|
7
|
+
value,
|
|
8
|
+
defaultExpandedPaths = ['$'],
|
|
9
|
+
class: className,
|
|
10
|
+
}: {
|
|
11
|
+
value: ComponentProps<JsonTree>['value'];
|
|
12
|
+
defaultExpandedPaths?: ComponentProps<JsonTree>['defaultExpandedPaths'];
|
|
13
|
+
class?: string;
|
|
14
|
+
} = $props();
|
|
6
15
|
</script>
|
|
7
16
|
|
|
8
17
|
<div class={cls('overflow-auto px-4 py-2 bg-[#1e1e1e]', className)}>
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { type ComponentProps } from 'svelte';
|
|
2
|
+
import JsonTree from 'svelte-json-tree';
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
value: ComponentProps<JsonTree>['value'];
|
|
5
|
+
defaultExpandedPaths?: ComponentProps<JsonTree>['defaultExpandedPaths'];
|
|
6
|
+
class?: string;
|
|
7
|
+
};
|
|
8
|
+
declare const Json: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
6
9
|
type Json = ReturnType<typeof Json>;
|
|
7
10
|
export default Json;
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { SelectField, Switch } from 'svelte-ux';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
let { doubleScale = $bindable(devicePixelRatio > 1), serviceUrl = $bindable() } = $props();
|
|
5
5
|
|
|
6
6
|
// TODO: Access via context, or possibly global state
|
|
7
7
|
const ACCESS_TOKEN =
|
|
8
8
|
'pk.eyJ1IjoidGVjaG5pcTM1IiwiYSI6ImNsZTR5cDd0ZjAyNm8zdnFvczhzdnFpcXkifQ.-LAr8sl5BZ3y-H0pDyD1qA';
|
|
9
9
|
|
|
10
10
|
// https://docs.mapbox.com/api/maps/styles/
|
|
11
|
-
|
|
11
|
+
const mapboxv1 = $derived((style: string) => (x: number, y: number, z: number) => {
|
|
12
12
|
return `https://api.mapbox.com/styles/v1/mapbox/${style}/tiles/${z}/${x}/${y}${
|
|
13
13
|
doubleScale ? '@2x' : ''
|
|
14
14
|
}?access_token=${ACCESS_TOKEN}`;
|
|
15
|
-
};
|
|
15
|
+
});
|
|
16
16
|
|
|
17
17
|
// https://docs.mapbox.com/api/maps/raster-tiles/
|
|
18
18
|
// https://docs.mapbox.com/data/tilesets/reference/mapbox-streets-v8/
|
|
19
|
-
|
|
19
|
+
const mapboxv4 = $derived((tileset: string) => (x: number, y: number, z: number) => {
|
|
20
20
|
return `https://${'abc'[Math.abs(x + y) % 3]}.tiles.mapbox.com/v4/${tileset}/${z}/${x}/${y}${
|
|
21
21
|
doubleScale ? '@2x' : ''
|
|
22
22
|
}.png?access_token=${ACCESS_TOKEN}`;
|
|
23
|
-
};
|
|
23
|
+
});
|
|
24
24
|
|
|
25
25
|
// https://apps.nationalmap.gov/services/
|
|
26
26
|
const nationalmap = (tileset: string) => (x: number, y: number, z: number) => {
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
return `https://${s}.tile.opentopomap.org/${z}/${x}/${y}.png`;
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
const services = $derived<Record<string, Record<string, Function>>>({
|
|
58
58
|
'mapbox v1': {
|
|
59
59
|
'streets-v11': mapboxv1('streets-v11'),
|
|
60
60
|
'light-v10': mapboxv1('light-v10'),
|
|
@@ -100,24 +100,25 @@
|
|
|
100
100
|
// 'ArcGIS Vector': {
|
|
101
101
|
// 'Community Map', url: arcgisVector('World_Basemap_v2'),
|
|
102
102
|
// }
|
|
103
|
-
} as Record<string, Record<string, Function>>;
|
|
104
|
-
|
|
105
|
-
$: serviceOptions = Object.entries(services).flatMap(([group, service]) => {
|
|
106
|
-
return Object.entries(service).map(([label, value]) => {
|
|
107
|
-
return { label, value: `${group}:${label}`, group, serviceUrl: value };
|
|
108
|
-
});
|
|
109
103
|
});
|
|
110
104
|
|
|
111
|
-
|
|
112
|
-
|
|
105
|
+
const serviceOptions = $derived(
|
|
106
|
+
Object.entries(services).flatMap(([group, service]) => {
|
|
107
|
+
return Object.entries(service).map(([label, value]) => {
|
|
108
|
+
return { label, value: `${group}:${label}`, group, serviceUrl: value };
|
|
109
|
+
});
|
|
110
|
+
})
|
|
111
|
+
);
|
|
113
112
|
|
|
114
|
-
|
|
113
|
+
const getServiceUrl = $derived((option: string) => {
|
|
115
114
|
const [selectedService, selectedTileset] = selected.split(':');
|
|
116
115
|
return services[selectedService][selectedTileset];
|
|
117
|
-
};
|
|
116
|
+
});
|
|
118
117
|
|
|
119
|
-
let selected = 'mapbox v1:streets-v11';
|
|
120
|
-
|
|
118
|
+
let selected = $state('mapbox v1:streets-v11');
|
|
119
|
+
$effect(() => {
|
|
120
|
+
serviceUrl = getServiceUrl(selected);
|
|
121
|
+
});
|
|
121
122
|
</script>
|
|
122
123
|
|
|
123
124
|
<SelectField
|
|
@@ -128,7 +129,7 @@
|
|
|
128
129
|
toggleIcon={null}
|
|
129
130
|
stepper
|
|
130
131
|
>
|
|
131
|
-
<div slot="append"
|
|
132
|
+
<div slot="append" onclick={(e) => e.stopPropagation()} role="none">
|
|
132
133
|
<div class="text-[10px] text-surface-content/50 text-center">2x</div>
|
|
133
134
|
<Switch bind:checked={doubleScale} size="md" />
|
|
134
135
|
</div>
|
|
@@ -1,23 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
$$events?: Events;
|
|
7
|
-
$$slots?: Slots;
|
|
8
|
-
}): Exports & {
|
|
9
|
-
$set?: any;
|
|
10
|
-
$on?: any;
|
|
11
|
-
};
|
|
12
|
-
z_$$bindings?: Bindings;
|
|
13
|
-
}
|
|
14
|
-
declare const TilesetField: $$__sveltets_2_IsomorphicComponent<{
|
|
15
|
-
doubleScale?: boolean;
|
|
16
|
-
serviceUrl?: Function;
|
|
17
|
-
}, {
|
|
18
|
-
click: MouseEvent;
|
|
19
|
-
} & {
|
|
20
|
-
[evt: string]: CustomEvent<any>;
|
|
21
|
-
}, {}, {}, string>;
|
|
22
|
-
type TilesetField = InstanceType<typeof TilesetField>;
|
|
1
|
+
declare const TilesetField: import("svelte").Component<{
|
|
2
|
+
doubleScale?: any;
|
|
3
|
+
serviceUrl?: any;
|
|
4
|
+
}, {}, "doubleScale" | "serviceUrl">;
|
|
5
|
+
type TilesetField = ReturnType<typeof TilesetField>;
|
|
23
6
|
export default TilesetField;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ScaleBand } from 'd3-scale';
|
|
1
|
+
import { type ScaleBand, type ScaleTime } from 'd3-scale';
|
|
2
2
|
import { type MotionProp, type MotionOptions, type SpringOptions, type TweenOptions } from './motion.svelte.js';
|
|
3
3
|
import type { Accessor } from './common.js';
|
|
4
4
|
import type { OnlyObjects } from './types.js';
|
|
@@ -23,6 +23,8 @@ export type AnyScale<TInput extends SingleDomainType = any, TOutput extends Sing
|
|
|
23
23
|
thresholds?: () => TInput[];
|
|
24
24
|
quantiles?: () => TInput[];
|
|
25
25
|
};
|
|
26
|
+
export declare function isScaleBand(scale: AnyScale<any, any>): scale is ScaleBand<any>;
|
|
27
|
+
export declare function isScaleTime(scale: AnyScale<any, any>): scale is ScaleTime<any, any>;
|
|
26
28
|
export declare function getRange(scale: any): any[];
|
|
27
29
|
export type SingleDomainType = number | string | Date | null | undefined;
|
|
28
30
|
export type DomainType = (number | string | Date | null | undefined)[] | null | undefined;
|
|
@@ -45,7 +47,6 @@ export declare function createMotionScale<Domain, Range>(scale: AnyScale, motion
|
|
|
45
47
|
* https://gist.github.com/LuisSevillano/d53a1dc529eef518780c6df99613e2fd
|
|
46
48
|
*/
|
|
47
49
|
export declare function scaleBandInvert(scale: ScaleBand<any>): (value: number) => any;
|
|
48
|
-
export declare function isScaleBand(scale: AnyScale<any, any>): scale is ScaleBand<any>;
|
|
49
50
|
/**
|
|
50
51
|
* Generic way to invert a scale value, handling scaleBand and continuous scales (linear, time, etc).
|
|
51
52
|
* Useful to map mouse event location (x,y) to domain value
|
|
@@ -5,6 +5,13 @@ import { Spring, Tween } from 'svelte/motion';
|
|
|
5
5
|
function isAnyScale(scale) {
|
|
6
6
|
return typeof scale === 'function' && typeof scale.range === 'function';
|
|
7
7
|
}
|
|
8
|
+
export function isScaleBand(scale) {
|
|
9
|
+
return typeof scale.bandwidth === 'function';
|
|
10
|
+
}
|
|
11
|
+
export function isScaleTime(scale) {
|
|
12
|
+
const domain = scale.domain();
|
|
13
|
+
return domain[0] instanceof Date || domain[1] instanceof Date;
|
|
14
|
+
}
|
|
8
15
|
export function getRange(scale) {
|
|
9
16
|
if (isAnyScale(scale)) {
|
|
10
17
|
return scale.range();
|
|
@@ -54,9 +61,6 @@ export function scaleBandInvert(scale) {
|
|
|
54
61
|
return domain[Math.max(0, Math.min(index, domain.length - 1))];
|
|
55
62
|
};
|
|
56
63
|
}
|
|
57
|
-
export function isScaleBand(scale) {
|
|
58
|
-
return typeof scale.bandwidth === 'function';
|
|
59
|
-
}
|
|
60
64
|
/**
|
|
61
65
|
* Generic way to invert a scale value, handling scaleBand and continuous scales (linear, time, etc).
|
|
62
66
|
* Useful to map mouse event location (x,y) to domain value
|
package/dist/utils/ticks.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { timeYear, timeMonth, timeWeek, timeDay, timeHour, timeMinute, timeSecond, timeMillisecond, } from 'd3-time';
|
|
2
2
|
import { format } from 'date-fns';
|
|
3
3
|
import { formatDate, PeriodType, getDuration, fail } from '@layerstack/utils';
|
|
4
|
-
import { isScaleBand } from './scales.svelte.js';
|
|
4
|
+
import { isScaleBand, isScaleTime } from './scales.svelte.js';
|
|
5
5
|
// TODO: Use PeriodType along with Duration to format (and possibly select intervals)
|
|
6
6
|
const majorTicks = [
|
|
7
7
|
{
|
|
@@ -170,6 +170,12 @@ export function resolveTickVals(scale, ticks, placement) {
|
|
|
170
170
|
? scale.domain().filter((_, i) => i % ticks === 0)
|
|
171
171
|
: scale.domain();
|
|
172
172
|
}
|
|
173
|
+
// if (isScaleTime(scale)) {
|
|
174
|
+
// const interval = getMajorTicks(scale.domain()[0], scale.domain()[1])!;
|
|
175
|
+
// // const interval = getMinorTicks(scale.domain()[0], scale.domain()[1]);
|
|
176
|
+
// return scale.ticks(interval);
|
|
177
|
+
// }
|
|
178
|
+
// Ticks from scale
|
|
173
179
|
if (scale.ticks && typeof scale.ticks === 'function') {
|
|
174
180
|
if (placement) {
|
|
175
181
|
return scale.ticks(ticks ?? (placement === 'left' || placement === 'right' ? 4 : undefined));
|
package/package.json
CHANGED