svelteplot 0.10.3-pr-475.2 → 0.10.3-pr-477.1

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.
@@ -0,0 +1,2 @@
1
+ export * from './plotDefaults.js';
2
+ export { usePlot } from './usePlot.svelte.js';
@@ -0,0 +1,2 @@
1
+ export * from './plotDefaults.js';
2
+ export { usePlot } from './usePlot.svelte.js';
package/dist/index.d.ts CHANGED
@@ -2,7 +2,6 @@ export { default as Plot } from './Plot.svelte';
2
2
  export { default as PlotCore } from './core/Plot.svelte';
3
3
  export * from './marks/index.js';
4
4
  export * from './transforms/index.js';
5
+ export * from './hooks/index.js';
5
6
  export { formatMonth } from './helpers/formats.js';
6
7
  export { default as wordwrap } from './helpers/wordwrap.js';
7
- export * from './hooks/plotDefaults.js';
8
- export { usePlot } from './hooks/usePlot.svelte.js';
package/dist/index.js CHANGED
@@ -2,9 +2,7 @@ export { default as Plot } from './Plot.svelte';
2
2
  export { default as PlotCore } from './core/Plot.svelte';
3
3
  export * from './marks/index.js';
4
4
  export * from './transforms/index.js';
5
+ export * from './hooks/index.js';
5
6
  // helpers
6
7
  export { formatMonth } from './helpers/formats.js';
7
8
  export { default as wordwrap } from './helpers/wordwrap.js';
8
- // hooks
9
- export * from './hooks/plotDefaults.js';
10
- export { usePlot } from './hooks/usePlot.svelte.js';
@@ -33,7 +33,7 @@
33
33
  import GroupMultiple from './helpers/GroupMultiple.svelte';
34
34
  import { resolveChannel, resolveProp, resolveStyles } from '../helpers/resolve.js';
35
35
  import { groups as d3Groups } from 'd3-array';
36
- import { area, type CurveFactory } from 'd3-shape';
36
+ import { area, type Area, type CurveFactory } from 'd3-shape';
37
37
  import callWithProps from '../helpers/callWithProps.js';
38
38
  import { maybeCurve } from '../helpers/curves.js';
39
39
  import { isValid } from '../helpers/index.js';
@@ -101,7 +101,7 @@
101
101
  y0: (d: ScaledDataRecord) => d.y1,
102
102
  y1: (d: ScaledDataRecord) => d.y2
103
103
  })
104
- })
104
+ }) as unknown as Area<ScaledDataRecord>
105
105
  );
106
106
 
107
107
  function groupAndSort(data: ScaledDataRecord[]) {
@@ -109,12 +109,11 @@
109
109
  ? d3Groups(data, (d) => resolveProp(groupByKey, d.datum)).map((d) => d[1])
110
110
  : [data];
111
111
  if (options.sort) {
112
- return groups.toSorted((a, b) =>
113
- resolveChannel('sort', a[0].datum, options) >
114
- resolveChannel('sort', b[0].datum, options)
115
- ? 1
116
- : -1
117
- );
112
+ return groups.toSorted((a, b) => {
113
+ const av = resolveChannel('sort', a[0].datum, options) as string | number | null;
114
+ const bv = resolveChannel('sort', b[0].datum, options) as string | number | null;
115
+ return av! > bv! ? 1 : -1;
116
+ });
118
117
  }
119
118
  return groups;
120
119
  }
@@ -125,8 +124,8 @@
125
124
  {data}
126
125
  channels={['x1', 'x2', 'y1', 'y2', 'fill', 'stroke', 'opacity', 'fillOpacity', 'strokeOpacity']}
127
126
  required={['x1', 'y1']}
128
- {...markProps}
129
- {...options}>
127
+ {...markProps as any}
128
+ {...options as any}>
130
129
  {#snippet children({ mark, usedScales, scaledData })}
131
130
  {@const grouped = groupAndSort(scaledData)}
132
131
  {#if canvas}
@@ -136,7 +135,7 @@
136
135
  {#each grouped as areaData, i (i)}
137
136
  {@const datum = areaData[0]}
138
137
  {#if areaData.length > 0}
139
- <Anchor {options} {datum}>
138
+ <Anchor options={options as any} {datum}>
140
139
  {@const title = resolveProp(options.title, datum.datum, '')}
141
140
  {@const [style, styleClass] = resolveStyles(
142
141
  plot,
@@ -1,4 +1,4 @@
1
- import { type CurveFactory } from 'd3-shape';
1
+ import { type Area, type CurveFactory } from 'd3-shape';
2
2
  import type { CurveName, DataRecord, ConstantAccessor, ChannelAccessor, LinkableMarkProps, RawValue } from '../types/index.js';
3
3
  import type { StackOptions } from '../transforms/stack.js';
4
4
  declare function $$render<Datum extends DataRecord>(): {
@@ -49,13 +49,17 @@
49
49
  BaseMarkProps,
50
50
  ConstantAccessor,
51
51
  ChannelAccessor,
52
- RawValue,
53
- PlotDefaults
52
+ RawValue
54
53
  } from '../types/index.js';
55
54
  import { resolveProp, resolveStyles } from '../helpers/resolve.js';
56
55
  import { coalesce, maybeNumber } from '../helpers/index.js';
57
56
  import Mark from '../Mark.svelte';
58
- import { arrowPath, maybeSweep, type SweepOption } from '../helpers/arrowPath.js';
57
+ import {
58
+ arrowPath,
59
+ maybeSweep,
60
+ type SweepFunc,
61
+ type SweepOption
62
+ } from '../helpers/arrowPath.js';
59
63
  import { replaceChannels } from '../transforms/rename.js';
60
64
  import { addEventHandlers } from './helpers/events.js';
61
65
  import GroupMultiple from './helpers/GroupMultiple.svelte';
@@ -87,10 +91,10 @@
87
91
  const args: ArrowMarkProps = $derived(
88
92
  sort(
89
93
  replaceChannels(
90
- { data: indexData(data), ...options },
94
+ { data: indexData(data as object[]), ...options },
91
95
  { y: ['y1', 'y2'], x: ['x1', 'x2'] }
92
96
  )
93
- )
97
+ ) as unknown as ArrowMarkProps
94
98
  );
95
99
  </script>
96
100
 
@@ -98,29 +102,37 @@
98
102
  type="arrow"
99
103
  required={['x1', 'x2', 'y1', 'y2']}
100
104
  channels={['x1', 'y1', 'x2', 'y2', 'opacity', 'stroke', 'strokeOpacity']}
101
- {...args}>
105
+ {...args as any}>
102
106
  {#snippet children({ usedScales, scaledData })}
103
- {@const sweep = maybeSweep(args.sweep)}
107
+ {@const sweep = maybeSweep(args.sweep) as SweepFunc}
104
108
  <GroupMultiple class="arrow" length={scaledData.length}>
105
109
  {#each scaledData as d, i (i)}
106
110
  {#if d.valid}
107
- {@const inset = resolveProp(args.inset, d.datum, 0)}
108
- {@const insetStart = resolveProp(args.insetStart, d.datum)}
109
- {@const insetEnd = resolveProp(args.insetEnd, d.datum)}
110
- {@const headAngle = resolveProp(args.headAngle, d.datum)}
111
- {@const headLength = resolveProp(args.headLength, d.datum)}
112
- {@const bend = resolveProp(args.bend, d.datum, 0)}
113
- {@const strokeWidth = resolveProp(args.strokeWidth, d.datum, 1)}
111
+ {@const datum = d.datum as unknown as Datum}
112
+ {@const inset = resolveProp(args.inset, datum, 0)}
113
+ {@const insetStart = resolveProp(args.insetStart, datum)}
114
+ {@const insetEnd = resolveProp(args.insetEnd, datum)}
115
+ {@const headAngle = (resolveProp(args.headAngle, datum, 60) ?? 60) as number}
116
+ {@const headLength = (resolveProp(args.headLength, datum, 8) ?? 8) as number}
117
+ {@const bendVal =
118
+ args.bend === true
119
+ ? 22.5
120
+ : (resolveProp(
121
+ args.bend as ConstantAccessor<number, Datum>,
122
+ datum,
123
+ 0
124
+ ) ?? 0)}
125
+ {@const strokeWidth = (resolveProp(args.strokeWidth, datum, 1) ?? 1) as number}
114
126
  {@const arrPath = arrowPath(
115
- d.x1,
116
- d.y1,
117
- d.x2,
118
- d.y2,
119
- maybeNumber(coalesce(insetStart, inset)),
120
- maybeNumber(coalesce(insetEnd, inset)),
127
+ d.x1 ?? 0,
128
+ d.y1 ?? 0,
129
+ d.x2 ?? 0,
130
+ d.y2 ?? 0,
131
+ maybeNumber(coalesce(insetStart, inset)) ?? 0,
132
+ maybeNumber(coalesce(insetEnd, inset)) ?? 0,
121
133
  headAngle,
122
134
  headLength,
123
- bend === true ? 22.5 : bend === false ? 0 : bend,
135
+ bendVal,
124
136
  strokeWidth,
125
137
  sweep
126
138
  )}
@@ -140,7 +152,7 @@
140
152
  class={[className]}
141
153
  {@attach addEventHandlers({
142
154
  plot,
143
- options,
155
+ options: options as any,
144
156
  datum: d?.datum
145
157
  })}>
146
158
  {#if options.onmouseenter || options.onclick}
@@ -10,7 +10,10 @@
10
10
  RawValue,
11
11
  ConstantAccessor,
12
12
  FacetContext,
13
- ChannelName
13
+ ChannelName,
14
+ TickFormatFunction,
15
+ DataRecord,
16
+ ScaledChannelName
14
17
  } from '../types/index.js';
15
18
  import type * as CSS from 'csstype';
16
19
  import autoTimeFormat from '../helpers/autoTimeFormat.js';
@@ -22,7 +25,7 @@
22
25
 
23
26
  interface AxisXMarkProps extends Omit<
24
27
  BaseMarkProps<Datum>,
25
- 'fillOpacity' | 'paintOrder' | 'title' | 'href' | 'target'
28
+ 'fillOpacity' | 'paintOrder' | 'title' | 'href' | 'target' | 'textAnchor'
26
29
  > {
27
30
  /** custom tick values to display on the axis */
28
31
  data?: Datum[];
@@ -72,7 +75,7 @@
72
75
 
73
76
  let markProps: AxisXMarkProps = $props();
74
77
 
75
- const DEFAULTS: Omit<AxisXMarkProps, 'data' | ChannelName> = {
78
+ const DEFAULTS = {
76
79
  tickSize: 6,
77
80
  tickPadding: 3,
78
81
  tickFontSize: 11,
@@ -87,7 +90,7 @@
87
90
  const { ticks: magicTicks } = $derived({ ...DEFAULTS, ...markProps });
88
91
 
89
92
  const {
90
- data,
93
+ data = [] as Datum[],
91
94
  automatic = false,
92
95
  title,
93
96
  anchor,
@@ -105,12 +108,12 @@
105
108
  text = true,
106
109
  ...options
107
110
  }: AxisXMarkProps = $derived({
108
- data: Array.isArray(magicTicks) ? magicTicks : [],
111
+ data: (Array.isArray(magicTicks) ? magicTicks : []) as Datum[],
109
112
  tickCount: typeof magicTicks === 'number' ? magicTicks : undefined,
110
113
  interval: typeof magicTicks === 'string' ? magicTicks : undefined,
111
114
  ...DEFAULTS,
112
115
  ...markProps
113
- });
116
+ } as AxisXMarkProps);
114
117
 
115
118
  const plot = usePlot();
116
119
 
@@ -138,15 +141,14 @@
138
141
  );
139
142
 
140
143
  const useCompactNotation = $derived.by(() => {
141
- const range =
142
- extent(plot.scales.x.domain).filter(
143
- (d): d is number => typeof d === 'number' && Number.isFinite(d)
144
- ) ?? [];
145
-
146
- if (range[0] === undefined || range[1] === undefined) return false;
147
- const crossesZero = range[0] <= 0 && range[1] >= 0;
144
+ const numericDomain = plot.scales.x.domain.filter(
145
+ (d): d is number => typeof d === 'number' && Number.isFinite(d)
146
+ );
147
+ if (numericDomain.length < 2) return false;
148
+ const [min, max] = extent(numericDomain) as [number, number];
149
+ const crossesZero = min <= 0 && max >= 0;
148
150
  if (crossesZero) return true;
149
- const magnitudes = range.map((d) =>
151
+ const magnitudes = [min, max].map((d) =>
150
152
  d === 0 ? -Infinity : Math.floor(Math.log10(Math.abs(d)))
151
153
  );
152
154
  return magnitudes[0] !== magnitudes[1];
@@ -158,7 +160,7 @@
158
160
  typeof tickFmt === 'function'
159
161
  ? tickFmt
160
162
  : plot.scales.x.type === 'band' || plot.scales.x.type === 'point'
161
- ? (d) => d
163
+ ? (d: RawValue) => String(d)
162
164
  : plot.scales.x.type === 'time'
163
165
  ? // time scale
164
166
  typeof tickFmt === 'object'
@@ -172,9 +174,9 @@
172
174
  Intl.NumberFormat(plot.options.locale, {
173
175
  // use compact notation if range covers multiple magnitudes
174
176
  ...(useCompactNotation ? { notation: 'compact' } : {}),
175
- ...DEFAULTS.numberFormat,
177
+ ...getPlotDefaults().numberFormat,
176
178
  style: plot.options.x.percent ? 'percent' : 'decimal'
177
- }).format(d)
179
+ }).format(d as number)
178
180
  );
179
181
 
180
182
  const optionsLabel = $derived(plot.options?.x?.label);
@@ -223,13 +225,13 @@
223
225
  type="axisX"
224
226
  data={data.length ? data.map((tick) => ({ __x: tick })) : []}
225
227
  channels={['x']}
226
- {...options}
228
+ {...options as any}
227
229
  x="__x"
228
230
  {automatic}>
229
231
  {#if left && top && useTitle}
230
232
  <text
231
233
  style={resolveScaledStyles(
232
- null,
234
+ {} as DataRecord,
233
235
  {
234
236
  opacity: 0.8,
235
237
  ...options,
@@ -242,7 +244,7 @@
242
244
  ? 'middle'
243
245
  : 'start'
244
246
  },
245
- {},
247
+ {} as Record<ScaledChannelName, boolean>,
246
248
  plot,
247
249
  'fill'
248
250
  )}
@@ -258,12 +260,11 @@
258
260
  <BaseAxisX
259
261
  {anchor}
260
262
  class={className}
261
- {labelAnchor}
262
- options={{ ...options, ...plot.options.x }}
263
+ options={{ ...(options as any), ...plot.options.x }}
263
264
  {plot}
264
265
  {text}
265
- {tickClass}
266
- {tickFontSize}
266
+ tickClass={tickClass as ConstantAccessor<string>}
267
+ tickFontSize={tickFontSize as ConstantAccessor<number>}
267
268
  {tickPadding}
268
269
  {ticks}
269
270
  {tickSize}
@@ -271,8 +272,8 @@
271
272
  marginTop={plot.options.marginTop}
272
273
  scaleFn={plot.scales.x.fn}
273
274
  scaleType={plot.scales.x.type}
274
- tickFormat={useTickFormat}
275
- title={useTitle} />
275
+ tickFormat={useTickFormat as TickFormatFunction}
276
+ title={useTitle as string | null} />
276
277
  {/if}
277
278
  </Mark>
278
279
 
@@ -136,7 +136,7 @@ declare function $$render<Datum extends RawValue>(): {
136
136
  style: string;
137
137
  cursor: ConstantAccessor<CSS.Property.Cursor, Datum>;
138
138
  title: ConstantAccessor<string, Datum>;
139
- }>, "fillOpacity" | "paintOrder" | "title" | "href" | "target"> & {
139
+ }>, "fillOpacity" | "textAnchor" | "paintOrder" | "title" | "href" | "target"> & {
140
140
  /** custom tick values to display on the axis */
141
141
  data?: Datum[];
142
142
  /** whether this axis was automatically added by the Plot component */
@@ -10,7 +10,10 @@
10
10
  RawValue,
11
11
  FacetContext,
12
12
  ChannelName,
13
- ConstantAccessor
13
+ ConstantAccessor,
14
+ TickFormatFunction,
15
+ DataRecord,
16
+ ScaledChannelName
14
17
  } from '../types/index.js';
15
18
  import autoTimeFormat from '../helpers/autoTimeFormat.js';
16
19
  import { autoTicks } from '../helpers/autoTicks.js';
@@ -21,7 +24,7 @@
21
24
 
22
25
  interface AxisYMarkProps extends Omit<
23
26
  BaseMarkProps<Datum>,
24
- 'fillOpacity' | 'paintOrder' | 'title' | 'href' | 'target'
27
+ 'fillOpacity' | 'paintOrder' | 'title' | 'href' | 'target' | 'textAnchor'
25
28
  > {
26
29
  /** custom tick values to display on the axis */
27
30
  data?: Datum[];
@@ -69,7 +72,7 @@
69
72
 
70
73
  let markProps: AxisYMarkProps = $props();
71
74
 
72
- const DEFAULTS: Omit<AxisYMarkProps, 'data' | ChannelName> = {
75
+ const DEFAULTS = {
73
76
  tickSize: 6,
74
77
  tickPadding: 3,
75
78
  tickFontSize: 11,
@@ -83,7 +86,7 @@
83
86
  const { ticks: magicTicks } = $derived({ ...DEFAULTS, ...markProps });
84
87
 
85
88
  const {
86
- data,
89
+ data = [] as Datum[],
87
90
  automatic = false,
88
91
  title,
89
92
  anchor = 'left',
@@ -102,12 +105,12 @@
102
105
  text = true,
103
106
  ...options
104
107
  }: AxisYMarkProps = $derived({
105
- data: Array.isArray(magicTicks) ? magicTicks : [],
108
+ data: (Array.isArray(magicTicks) ? magicTicks : []) as Datum[],
106
109
  tickCount: typeof magicTicks === 'number' ? magicTicks : undefined,
107
110
  interval: typeof magicTicks === 'string' ? magicTicks : undefined,
108
111
  ...DEFAULTS,
109
112
  ...markProps
110
- });
113
+ } as AxisYMarkProps);
111
114
 
112
115
  const plot = usePlot();
113
116
 
@@ -135,15 +138,14 @@
135
138
  );
136
139
 
137
140
  const useCompactNotation = $derived.by(() => {
138
- const range =
139
- extent(plot.scales.y.domain).filter(
140
- (d): d is number => typeof d === 'number' && Number.isFinite(d)
141
- ) ?? [];
142
-
143
- if (range[0] === undefined || range[1] === undefined) return false;
144
- const crossesZero = range[0] <= 0 && range[1] >= 0;
141
+ const numericDomain = plot.scales.y.domain.filter(
142
+ (d): d is number => typeof d === 'number' && Number.isFinite(d)
143
+ );
144
+ if (numericDomain.length < 2) return false;
145
+ const [min, max] = extent(numericDomain) as [number, number];
146
+ const crossesZero = min <= 0 && max >= 0;
145
147
  if (crossesZero) return true;
146
- const magnitudes = range.map((d) =>
148
+ const magnitudes = [min, max].map((d) =>
147
149
  d === 0 ? -Infinity : Math.floor(Math.log10(Math.abs(d)))
148
150
  );
149
151
  return magnitudes[0] !== magnitudes[1];
@@ -155,7 +157,7 @@
155
157
  typeof tickFmt === 'function'
156
158
  ? tickFmt
157
159
  : plot.scales.y.type === 'band' || plot.scales.y.type === 'point'
158
- ? (d) => d
160
+ ? (d: RawValue) => String(d)
159
161
  : plot.scales.y.type === 'time'
160
162
  ? // time scale
161
163
  typeof tickFmt === 'object'
@@ -169,9 +171,9 @@
169
171
  Intl.NumberFormat(plot.options.locale, {
170
172
  // use compact notation if range covers multiple magnitudes
171
173
  ...(useCompactNotation ? { notation: 'compact' } : {}),
172
- ...DEFAULTS.numberFormat,
174
+ ...getPlotDefaults().numberFormat,
173
175
  style: plot.options.y.percent ? 'percent' : 'decimal'
174
- }).format(d)
176
+ }).format(d as number)
175
177
  );
176
178
 
177
179
  const optionsLabel = $derived(plot.options.y.label);
@@ -210,12 +212,12 @@
210
212
  type="axisY"
211
213
  data={data.length ? data.map((tick) => ({ __y: tick })) : []}
212
214
  channels={['y']}
213
- {...{ ...options, y: '__y' }}
215
+ {...{ ...options, y: '__y' } as any}
214
216
  {automatic}>
215
217
  {#if left && top && useTitle}
216
218
  <text
217
219
  style={resolveScaledStyles(
218
- null,
220
+ {} as DataRecord,
219
221
  {
220
222
  opacity: 0.8,
221
223
  ...options,
@@ -224,7 +226,7 @@
224
226
  stroke: null,
225
227
  textAnchor: anchor === 'left' ? 'start' : 'end'
226
228
  },
227
- {},
229
+ {} as Record<ScaledChannelName, boolean>,
228
230
  plot,
229
231
  'fill'
230
232
  )}
@@ -239,7 +241,7 @@
239
241
  class={className}
240
242
  {lineAnchor}
241
243
  options={{
242
- ...options,
244
+ ...(options as any),
243
245
  textAnchor:
244
246
  textAnchor == null || textAnchor === 'auto'
245
247
  ? anchor === 'left'
@@ -249,16 +251,16 @@
249
251
  }}
250
252
  {plot}
251
253
  {text}
252
- {tickClass}
253
- {tickFontSize}
254
+ tickClass={tickClass as ConstantAccessor<string>}
255
+ tickFontSize={tickFontSize as ConstantAccessor<number>}
254
256
  {tickPadding}
255
257
  {ticks}
256
258
  {tickSize}
257
259
  marginLeft={plot.options.marginLeft}
258
260
  scaleFn={plot.scales.y.fn}
259
261
  scaleType={plot.scales.y.type}
260
- tickFormat={useTickFormat}
261
- title={useTitle}
262
+ tickFormat={useTickFormat as TickFormatFunction}
263
+ title={useTitle as string | null}
262
264
  width={plot.facetWidth} />
263
265
  {/if}
264
266
  </Mark>
@@ -135,7 +135,7 @@ declare function $$render<Datum extends RawValue>(): {
135
135
  style: string;
136
136
  cursor: ConstantAccessor<import("csstype").Property.Cursor, Datum>;
137
137
  title: ConstantAccessor<string, Datum>;
138
- }>, "fillOpacity" | "paintOrder" | "title" | "href" | "target"> & {
138
+ }>, "fillOpacity" | "textAnchor" | "paintOrder" | "title" | "href" | "target"> & {
139
139
  /** custom tick values to display on the axis */
140
140
  data?: Datum[];
141
141
  /** whether this axis was automatically added by the Plot component */
@@ -73,7 +73,7 @@
73
73
  </div>
74
74
  {/each}
75
75
  {:else if scaleType === 'quantile' || scaleType === 'quantize' || scaleType === 'threshold'}
76
- {@const domain = extent(plot.scales.color.fn.domain())}
76
+ {@const domain = extent(plot.scales.color.fn.domain() as number[]) as [number, number]}
77
77
  {@const range = plot.scales.color.range}
78
78
  {@const tickLabels =
79
79
  scaleType === 'quantile'
@@ -95,28 +95,34 @@
95
95
  marginBottom={20}
96
96
  height={38}
97
97
  inset={0}
98
- x={{ domain, ticks }}>
98
+ x={{ domain: domain as [number, number], ticks }}>
99
99
  <defs>
100
100
  <linearGradient id="gradient-{randId}" x2="1">
101
- <stop offset="0%" stop-color={range[0]} />
101
+ <stop offset="0%" stop-color={range[0] as string} />
102
102
  {#each ticks as t, i (i)}
103
103
  {@const offset = (100 * (t - domain[0])) / (domain[1] - domain[0])}
104
104
  <stop
105
105
  offset="{offset - 0.001}%"
106
- stop-color={plot.scales.color.fn(tickLabels[i] - 0.1)} />
106
+ stop-color={plot.scales.color.fn(
107
+ (tickLabels[i] as number) - 0.1
108
+ )} />
107
109
  <stop
108
110
  offset="{offset}%"
109
- stop-color={plot.scales.color.fn(tickLabels[i])} />
111
+ stop-color={plot.scales.color.fn(tickLabels[i] as number)} />
110
112
  {/each}
111
- <stop offset="100%" stop-color={range.at(-1)} />
113
+ <stop offset="100%" stop-color={range.at(-1) as string} />
112
114
  </linearGradient>
113
115
  </defs>
114
- <Frame dy={-5} stroke={null} fill="url(#gradient-{randId})" />
115
- <AxisX tickSize={18} dy={-17} tickFormat={(d, i) => tickFormat(tickLabels[i])} />
116
+ <Frame dy={-5} stroke={undefined} fill="url(#gradient-{randId})" />
117
+ <AxisX
118
+ tickSize={18}
119
+ dy={-17}
120
+ tickFormat={(d, i) =>
121
+ (tickFormat as (d: number) => string)(tickLabels[i] as number)} />
116
122
  </Plot>
117
123
  {:else}
118
124
  <!--- continuous -->
119
- {@const domain = extent(plot.scales.color.domain)}
125
+ {@const domain = extent(plot.scales.color.domain as number[]) as [number, number]}
120
126
  {@const ticks = d3Range(domain[0], domain[1], (domain[1] - domain[0]) / 7).slice(1)}
121
127
 
122
128
  <Plot
@@ -128,7 +134,11 @@
128
134
  marginBottom={20}
129
135
  height={38}
130
136
  inset={0}
131
- x={{ domain, tickSpacing: 30, tickFormat }}>
137
+ x={{
138
+ domain: domain as [number, number],
139
+ tickSpacing: 30,
140
+ tickFormat: tickFormat as any
141
+ }}>
132
142
  <defs>
133
143
  <linearGradient id="gradient-{randId}" x2="1">
134
144
  {#each ticks as t (t)}
@@ -138,7 +148,7 @@
138
148
  {/each}
139
149
  </linearGradient>
140
150
  </defs>
141
- <Frame dy={-5} stroke={null} fill="url(#gradient-{randId})" />
151
+ <Frame dy={-5} stroke={undefined} fill="url(#gradient-{randId})" />
142
152
  <AxisX tickSize={18} dy={-17} />
143
153
  </Plot>
144
154
  {/if}
@@ -32,7 +32,12 @@
32
32
  insetBottom?: number;
33
33
  }
34
34
  import Mark from '../Mark.svelte';
35
- import type { BaseRectMarkProps, LinkableMarkProps, DataRecord } from '../types/index.js';
35
+ import type {
36
+ BaseRectMarkProps,
37
+ LinkableMarkProps,
38
+ DataRecord,
39
+ ScaledDataRecord
40
+ } from '../types/index.js';
36
41
  import type { BaseMarkProps } from '../types/index.js';
37
42
  import RectPath from './helpers/RectPath.svelte';
38
43
  import { resolveProp } from '../helpers/resolve';
@@ -41,13 +46,15 @@
41
46
 
42
47
  let markProps: FrameMarkProps = $props();
43
48
 
49
+ const _plotDefaults = getPlotDefaults();
50
+ const _frame = _plotDefaults.frame;
44
51
  const DEFAULTS: FrameMarkProps = {
45
52
  fill: undefined,
46
53
  class: 'frame',
47
54
  stroke: undefined,
48
55
  fillOpacity: 1,
49
56
  strokeOpacity: 1,
50
- ...getPlotDefaults().frame
57
+ ...(_frame != null && _frame !== true ? _frame : {})
51
58
  };
52
59
 
53
60
  const {
@@ -73,8 +80,16 @@
73
80
  <Mark type="frame" {automatic}>
74
81
  {#snippet children({ usedScales })}
75
82
  <RectPath
76
- class={className}
77
- datum={{ fill, stroke, fillOpacity, strokeOpacity, opacity, datum: {}, valid: true }}
83
+ class={className ?? null}
84
+ datum={{
85
+ fill,
86
+ stroke,
87
+ fillOpacity,
88
+ strokeOpacity,
89
+ opacity,
90
+ datum: {} as Datum,
91
+ valid: true
92
+ } as unknown as ScaledDataRecord<Datum>}
78
93
  x={plot.options.marginLeft + dx}
79
94
  y={plot.options.marginTop + dy}
80
95
  width={plot.facetWidth}
@@ -13,7 +13,13 @@
13
13
  y2?: ChannelAccessor<Datum>;
14
14
  }
15
15
  import Mark from '../Mark.svelte';
16
- import type { BaseMarkProps, RawValue, DataRecord, ChannelAccessor } from '../types/index.js';
16
+ import type {
17
+ BaseMarkProps,
18
+ RawValue,
19
+ DataRecord,
20
+ ChannelAccessor,
21
+ ScaledDataRecord
22
+ } from '../types/index.js';
17
23
  import { resolveChannel, resolveProp, resolveStyles } from '../helpers/resolve.js';
18
24
  import { autoTicks } from '../helpers/autoTicks.js';
19
25
  import { testFilter } from '../helpers/index.js';
@@ -25,9 +31,12 @@
25
31
 
26
32
  let markProps: GridXMarkProps = $props();
27
33
 
34
+ const _plotDefaults = getPlotDefaults();
35
+ const _grid = _plotDefaults.grid;
36
+ const _gridX = _plotDefaults.gridX;
28
37
  const DEFAULTS = {
29
- ...getPlotDefaults().grid,
30
- ...getPlotDefaults().gridX
38
+ ...(_grid != null && _grid !== true ? _grid : {}),
39
+ ...(_gridX != null && _gridX !== true ? _gridX : {})
31
40
  };
32
41
 
33
42
  const {
@@ -59,37 +68,39 @@
59
68
  autoTickCount
60
69
  )
61
70
  ).map((d, i) =>
62
- isDataRecord(d) ? { ...d, [INDEX]: i } : { [RAW_VALUE]: d, [INDEX]: i }
71
+ isDataRecord(d) ? { ...d, [INDEX]: i } : { [RAW_VALUE]: d as RawValue, [INDEX]: i }
63
72
  ) as DataRecord[]
64
73
  );
65
74
  </script>
66
75
 
67
76
  <Mark
68
77
  type="gridX"
69
- data={data.length ? data.map((tick) => ({ [RAW_VALUE]: tick })) : []}
78
+ data={data.length ? data.map((tick) => ({ [RAW_VALUE]: tick as RawValue })) : []}
70
79
  channels={['y1', 'y2', 'x', 'stroke', 'strokeOpacity']}
71
- {...{ ...options, x: RAW_VALUE }}
80
+ {...{ ...options, x: RAW_VALUE } as any}
72
81
  {automatic}>
73
82
  {#snippet children({ usedScales })}
74
83
  <g class="grid-x">
75
84
  {#each ticks as tick, t (t)}
76
- {#if testFilter(tick, options)}
85
+ {#if testFilter(tick as any, options as any)}
77
86
  {@const x =
78
87
  plot.scales.x.fn(tick[RAW_VALUE]) +
79
88
  (plot.scales.x.type === 'band' ? plot.scales.x.fn.bandwidth() * 0.5 : 0)}
80
- {@const y1_ = resolveChannel('y1', tick, options)}
81
- {@const y2_ = resolveChannel('y2', tick, options)}
82
- {@const dx = +resolveProp(options?.dx, tick, 0)}
83
- {@const dy = +resolveProp(options?.dy, tick, 0)}
89
+ {@const y1_ = resolveChannel('y1', tick as any, options as any)}
90
+ {@const y2_ = resolveChannel('y2', tick as any, options as any)}
91
+ {@const dx = resolveProp(options.dx, tick as any, 0) ?? 0}
92
+ {@const dy = resolveProp(options.dy, tick as any, 0) ?? 0}
84
93
  {@const y1 =
85
- options.y1 != null ? plot.scales.y.fn(y1_) : plot.options.marginTop}
94
+ options.y1 != null && y1_ != null
95
+ ? plot.scales.y.fn(y1_)
96
+ : plot.options.marginTop}
86
97
  {@const y2 =
87
- options.y2 != null
98
+ options.y2 != null && y2_ != null
88
99
  ? plot.scales.y.fn(y2_)
89
100
  : plot.options.marginTop + plot.facetHeight}
90
101
  {@const [style, styleClass] = resolveStyles(
91
102
  plot,
92
- { datum: tick },
103
+ { datum: tick } as ScaledDataRecord,
93
104
  options,
94
105
  'stroke',
95
106
  usedScales,
@@ -13,7 +13,13 @@
13
13
  x2?: ChannelAccessor<Datum>;
14
14
  }
15
15
  import Mark from '../Mark.svelte';
16
- import type { BaseMarkProps, RawValue, ChannelAccessor } from '../types/index.js';
16
+ import type {
17
+ BaseMarkProps,
18
+ RawValue,
19
+ DataRecord,
20
+ ChannelAccessor,
21
+ ScaledDataRecord
22
+ } from '../types/index.js';
17
23
  import { resolveChannel, resolveProp, resolveStyles } from '../helpers/resolve.js';
18
24
  import { autoTicks } from '../helpers/autoTicks.js';
19
25
  import { testFilter } from '../helpers/index.js';
@@ -23,9 +29,12 @@
23
29
 
24
30
  let markProps: GridYMarkProps = $props();
25
31
 
32
+ const _plotDefaults = getPlotDefaults();
33
+ const _grid = _plotDefaults.grid;
34
+ const _gridY = _plotDefaults.gridY;
26
35
  const DEFAULTS = {
27
- ...getPlotDefaults().grid,
28
- ...getPlotDefaults().gridY
36
+ ...(_grid != null && _grid !== true ? _grid : {}),
37
+ ...(_gridY != null && _gridY !== true ? _gridY : {})
29
38
  };
30
39
 
31
40
  const {
@@ -46,7 +55,7 @@
46
55
  const ticks: RawValue[] = $derived(
47
56
  data.length > 0
48
57
  ? // use custom tick values if user passed any as prop
49
- data
58
+ (data as RawValue[])
50
59
  : // use custom scale tick values if user passed any as plot scale option
51
60
  autoTicks(
52
61
  plot.scales.y.type,
@@ -61,31 +70,33 @@
61
70
 
62
71
  <Mark
63
72
  type="gridY"
64
- data={data.length ? data.map((tick) => ({ [RAW_VALUE]: tick })) : []}
73
+ data={data.length ? data.map((tick) => ({ [RAW_VALUE]: tick as RawValue })) : []}
65
74
  channels={['x1', 'x2', 'y', 'stroke', 'strokeOpacity']}
66
- {...{ ...options, y: RAW_VALUE }}
75
+ {...{ ...options, y: RAW_VALUE } as any}
67
76
  {automatic}>
68
77
  {#snippet children({ usedScales })}
69
78
  <g class="grid-y">
70
79
  {#each ticks as tick, t (t)}
71
- {#if testFilter(tick, options)}
80
+ {#if testFilter(tick as any, options as any)}
72
81
  {@const y =
73
82
  plot.scales.y.fn(tick) +
74
83
  (plot.scales.y.type === 'band' ? plot.scales.y.fn.bandwidth() * 0.5 : 0)}
75
- {@const x1_ = resolveChannel('x1', tick, options)}
76
- {@const x2_ = resolveChannel('x2', tick, options)}
84
+ {@const x1_ = resolveChannel('x1', tick as any, options as any)}
85
+ {@const x2_ = resolveChannel('x2', tick as any, options as any)}
77
86
  {@const x1 =
78
- options.x1 != null ? plot.scales.x.fn(x1_) : plot.options.marginLeft}
87
+ options.x1 != null && x1_ != null
88
+ ? plot.scales.x.fn(x1_)
89
+ : plot.options.marginLeft}
79
90
  {@const x2 =
80
- options.x2 != null
91
+ options.x2 != null && x2_ != null
81
92
  ? plot.scales.x.fn(x2_)
82
93
  : plot.options.marginLeft + plot.facetWidth}
83
- {@const dx = +resolveProp(options?.dx, tick, 0)}
84
- {@const dy = +resolveProp(options?.dy, tick, 0)}
94
+ {@const dx = resolveProp(options.dx, tick as any, 0) ?? 0}
95
+ {@const dy = resolveProp(options.dy, tick as any, 0) ?? 0}
85
96
  {@const [style, styleClass] = resolveStyles(
86
97
  plot,
87
- { datum: { [RAW_VALUE]: tick } },
88
- options,
98
+ { datum: { [RAW_VALUE]: tick } } as unknown as ScaledDataRecord,
99
+ options as any,
89
100
  'stroke',
90
101
  usedScales,
91
102
  true
@@ -47,13 +47,13 @@
47
47
  const firstPoint = group[0];
48
48
  if (!firstPoint || !firstPoint.valid) continue;
49
49
 
50
- let { fill, stroke, ...restStyles } = resolveScaledStyleProps(
50
+ const { fill, stroke, ...restStyles } = resolveScaledStyleProps(
51
51
  firstPoint.datum,
52
52
  mark.options,
53
53
  usedScales,
54
54
  plot,
55
55
  'fill'
56
- );
56
+ ) as { fill: string; stroke: string } & Record<string, unknown>;
57
57
 
58
58
  const opacity = maybeOpacity(restStyles['opacity']);
59
59
  const fillOpacity = maybeOpacity(restStyles['fill-opacity']);
@@ -65,23 +65,23 @@
65
65
  0
66
66
  ) as number;
67
67
 
68
- fill = resolveColor(fill || 'currentColor', canvas);
69
- stroke = resolveColor(stroke, canvas);
68
+ const fillStyle = resolveColor(fill || 'currentColor', canvas);
69
+ const strokeStyle = resolveColor(stroke, canvas);
70
70
 
71
71
  // Start drawing the area
72
72
  context.beginPath();
73
73
  areaPath(group);
74
74
 
75
75
  // Fill the area
76
- if (fill && fill !== 'none') {
77
- context.fillStyle = fill;
76
+ if (fillStyle && fillStyle !== 'none') {
77
+ context.fillStyle = fillStyle;
78
78
  context.globalAlpha = opacity * fillOpacity;
79
79
  context.fill();
80
80
  }
81
81
 
82
82
  // Stroke the area outline if strokeWidth > 0
83
- if (stroke && stroke !== 'none' && strokeWidth > 0) {
84
- context.strokeStyle = stroke;
83
+ if (strokeStyle && strokeStyle !== 'none' && strokeWidth > 0) {
84
+ context.strokeStyle = strokeStyle;
85
85
  context.lineWidth = strokeWidth;
86
86
  context.globalAlpha = opacity * strokeOpacity;
87
87
  context.stroke();
@@ -33,7 +33,7 @@
33
33
  width: 6,
34
34
  height: 6,
35
35
  orient,
36
- color: 'stroke'
36
+ color: 'stroke' as const
37
37
  });
38
38
 
39
39
  const MARKERS: Record<
@@ -5,7 +5,8 @@
5
5
  ScaledDataRecord,
6
6
  UsedScales,
7
7
  CurveName,
8
- ConstantAccessor
8
+ ConstantAccessor,
9
+ DataRecord
9
10
  } from '../../types/index.js';
10
11
  import CanvasLayer from './CanvasLayer.svelte';
11
12
  import type { Attachment } from 'svelte/attachments';
@@ -14,7 +15,7 @@
14
15
  import type { CurveFactory } from 'd3-shape';
15
16
  import { trailPath, type TrailSample } from './trail';
16
17
  import { resolveProp, resolveScaledStyleProps } from '../../helpers/resolve';
17
- import { usePlot } from '../../hooks/usePlot.svelte.js';
18
+ import { usePlot } from '../..';
18
19
 
19
20
  interface TrailCanvasProps<Datum extends object> {
20
21
  curve?: CurveName | CurveFactory;
@@ -1,4 +1,4 @@
1
- import type { ScaledDataRecord, UsedScales, CurveName, ConstantAccessor } from '../../types/index.js';
1
+ import type { ScaledDataRecord, UsedScales, CurveName, ConstantAccessor, DataRecord } from '../../types/index.js';
2
2
  import type { CurveFactory } from 'd3-shape';
3
3
  interface TrailCanvasProps<Datum extends object> {
4
4
  curve?: CurveName | CurveFactory;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelteplot",
3
- "version": "0.10.3-pr-475.2",
3
+ "version": "0.10.3-pr-477.1",
4
4
  "description": "A Svelte-native data visualization framework based on the layered grammar of graphics principles.",
5
5
  "keywords": [
6
6
  "svelte",