svelteplot 0.2.9 → 0.2.10

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.
Files changed (48) hide show
  1. package/README.md +1 -1
  2. package/dist/Mark.svelte +5 -4
  3. package/dist/Plot.svelte +1 -1
  4. package/dist/core/Plot.svelte +2 -2
  5. package/dist/helpers/scales.js +9 -1
  6. package/dist/marks/Area.svelte +18 -26
  7. package/dist/marks/AxisX.svelte +5 -1
  8. package/dist/marks/AxisX.svelte.d.ts +2 -0
  9. package/dist/marks/AxisY.svelte +4 -0
  10. package/dist/marks/AxisY.svelte.d.ts +2 -0
  11. package/dist/marks/BarX.svelte +3 -1
  12. package/dist/marks/BarX.svelte.d.ts +2 -2
  13. package/dist/marks/BarY.svelte +1 -0
  14. package/dist/marks/BarY.svelte.d.ts +2 -2
  15. package/dist/marks/BrushX.svelte +1 -1
  16. package/dist/marks/BrushY.svelte +1 -1
  17. package/dist/marks/Cell.svelte +1 -0
  18. package/dist/marks/Cell.svelte.d.ts +2 -2
  19. package/dist/marks/ColorLegend.svelte +1 -0
  20. package/dist/marks/Dot.svelte +20 -19
  21. package/dist/marks/Dot.svelte.d.ts +2 -2
  22. package/dist/marks/Frame.svelte +2 -1
  23. package/dist/marks/Frame.svelte.d.ts +2 -2
  24. package/dist/marks/Geo.svelte +27 -33
  25. package/dist/marks/Geo.svelte.d.ts +4 -2
  26. package/dist/marks/Rect.svelte +1 -0
  27. package/dist/marks/Rect.svelte.d.ts +2 -2
  28. package/dist/marks/Sphere.svelte +2 -2
  29. package/dist/marks/Sphere.svelte.d.ts +3 -58
  30. package/dist/marks/helpers/Anchor.svelte +37 -0
  31. package/dist/marks/helpers/Anchor.svelte.d.ts +15 -0
  32. package/dist/marks/helpers/BaseAxisX.svelte +59 -53
  33. package/dist/marks/helpers/BaseAxisX.svelte.d.ts +1 -0
  34. package/dist/marks/helpers/BaseAxisY.svelte +24 -18
  35. package/dist/marks/helpers/BaseAxisY.svelte.d.ts +1 -0
  36. package/dist/marks/helpers/RectPath.svelte +33 -30
  37. package/dist/marks/helpers/Regression.svelte +1 -1
  38. package/dist/transforms/bollinger.d.ts +58 -0
  39. package/dist/transforms/centroid.d.ts +58 -0
  40. package/dist/transforms/interval.d.ts +116 -0
  41. package/dist/transforms/map.d.ts +174 -0
  42. package/dist/transforms/normalize.d.ts +117 -1
  43. package/dist/transforms/select.d.ts +406 -0
  44. package/dist/transforms/sort.d.ts +228 -1
  45. package/dist/transforms/sort.js +23 -13
  46. package/dist/transforms/window.d.ts +116 -0
  47. package/dist/types.d.ts +29 -8
  48. package/package.json +121 -120
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # SveltePlot
2
2
 
3
- ![Tests](https://github.com/svelteplot/svelteplot/actions/workflows/test.yml/badge.svg)
3
+ ![License](https://img.shields.io/npm/l/svelteplot.svg) ![Tests](https://github.com/svelteplot/svelteplot/actions/workflows/test.yml/badge.svg)
4
4
 
5
5
  SveltePlot is a visualization framework based on the [layered grammar of graphics](https://vita.had.co.nz/papers/layered-grammar.html) ideas. It's API is heavily inspired by [Observable Plot](https://github.com/observablehq/plot). Created by Gregor Aisch.
6
6
 
package/dist/Mark.svelte CHANGED
@@ -56,7 +56,7 @@
56
56
 
57
57
  const channelsWithFacets: ScaledChannelName[] = $derived([...channels, 'fx', 'fy']);
58
58
 
59
- const { addMark, updateMark, updatePlotState, removeMark, getTopLevelFacet, getPlotState } =
59
+ const { addMark, removeMark, getTopLevelFacet, getPlotState } =
60
60
  getContext<PlotContext>('svelteplot');
61
61
 
62
62
  const plot = $derived(getPlotState());
@@ -258,16 +258,17 @@
258
258
  if (options?.[channel] != null && out[channel] === undefined) {
259
259
  // resolve value
260
260
  const value = row[channel];
261
-
262
261
  const scaled = usedScales[channel]
263
262
  ? scale === 'x'
264
263
  ? projectX(channel as 'x' | 'x1' | 'x2', plot.scales, value)
265
264
  : scale === 'y'
266
265
  ? projectY(channel as 'y' | 'y1' | 'y1', plot.scales, value)
267
- : plot.scales[scale].fn(value)
266
+ : scale === 'color' && !isValid(value)
267
+ ? plot.options.color.unknown
268
+ : plot.scales[scale].fn(value)
268
269
  : value;
269
270
 
270
- out.valid = out.valid && isValid(value);
271
+ out.valid = out.valid && (scale === 'color' || isValid(value));
271
272
 
272
273
  // apply dx/dy transform
273
274
  out[channel] =
package/dist/Plot.svelte CHANGED
@@ -117,7 +117,7 @@
117
117
  scales,
118
118
  ...restProps
119
119
  })}
120
- <svelte:boundary onerror={(err) => console.warn(err)}>
120
+ <svelte:boundary onerror={(err) => console.error(err)}>
121
121
  <!-- implicit axes -->
122
122
  {#if !hasProjection && !hasExplicitAxisX}
123
123
  {#if options.axes && (options.x.axis === 'top' || options.x.axis === 'both')}
@@ -62,7 +62,7 @@
62
62
  initialWidth: 500,
63
63
  inset: 0,
64
64
  colorScheme: 'turbo',
65
- unknown: '#cccccc',
65
+ unknown: '#cccccc99',
66
66
  dotRadius: 3,
67
67
  frame: false,
68
68
  axes: true,
@@ -450,7 +450,7 @@
450
450
  padding: 0,
451
451
  align: 0
452
452
  },
453
- color: { type: 'auto' },
453
+ color: { type: 'auto', unknown: DEFAULTS.unknown },
454
454
  length: { type: 'linear' },
455
455
  symbol: { type: 'ordinal' },
456
456
  fx: { type: 'band', axis: 'top' },
@@ -6,6 +6,7 @@ import { resolveProp, toChannelOption } from './resolve.js';
6
6
  import isDataRecord from './isDataRecord.js';
7
7
  import { createProjection } from './projection.js';
8
8
  import { maybeInterval } from './autoTicks.js';
9
+ import { IS_SORTED } from '../transforms/sort.js';
9
10
  /**
10
11
  * compute the plot scales
11
12
  */
@@ -54,8 +55,9 @@ export function createScale(name, scaleOptions, marks, plotOptions, plotWidth, p
54
55
  // we're deliberately checking for !== undefined and not for != null
55
56
  // since the explicit sort transforms like shuffle will set the
56
57
  // sort channel to null to we know that there's an explicit order
57
- if (mark.channels.sort !== undefined)
58
+ if ((name === 'x' || name === 'y') && mark.options[IS_SORTED] != undefined) {
58
59
  sortOrdinalDomain = false;
60
+ }
59
61
  for (const channel of mark.channels) {
60
62
  // channelOptions can be passed as prop, but most often users will just
61
63
  // pass the channel accessor or constant value, so we may need to wrap
@@ -135,6 +137,12 @@ export function createScale(name, scaleOptions, marks, plotOptions, plotWidth, p
135
137
  }
136
138
  }
137
139
  }
140
+ if ((name === 'x' || name === 'y') && scaleOptions.sort) {
141
+ sortOrdinalDomain = true;
142
+ }
143
+ if ((name === 'x' || name === 'y') && scaleOptions.sort === false) {
144
+ sortOrdinalDomain = false;
145
+ }
138
146
  // construct domain from data values
139
147
  const valueArr = [...dataValues.values(), ...(scaleOptions.domain || [])].filter((d) => d != null);
140
148
  const type = scaleOptions.type === 'auto'
@@ -29,6 +29,7 @@
29
29
  import { maybeCurve } from '../helpers/curves.js';
30
30
  import { isValid } from '../helpers/index.js';
31
31
  import AreaCanvas from './helpers/AreaCanvas.svelte';
32
+ import Anchor from './helpers/Anchor.svelte';
32
33
 
33
34
  import type {
34
35
  CurveName,
@@ -37,7 +38,6 @@
37
38
  BaseMarkProps,
38
39
  ConstantAccessor,
39
40
  ChannelAccessor,
40
- FacetContext,
41
41
  ScaledDataRecord,
42
42
  LinkableMarkProps
43
43
  } from '../types.js';
@@ -113,32 +113,24 @@
113
113
  {:else}
114
114
  <GroupMultiple length={grouped.length}>
115
115
  {#each grouped as areaData, i (i)}
116
- {#snippet el(datum: ScaledDataRecord)}
117
- {@const title = resolveProp(options.title, datum.datum, '')}
118
- {@const [style, styleClass] = resolveStyles(
119
- plot,
120
- datum,
121
- options,
122
- 'fill',
123
- usedScales
124
- )}
125
- <path
126
- class={['svelteplot-area', className, styleClass]}
127
- clip-path={options.clipPath}
128
- d={areaPath(areaData)}
129
- {style}
130
- >{#if title}<title>{title}</title>{/if}</path>
131
- {/snippet}
116
+ {@const datum = areaData[0]}
132
117
  {#if areaData.length > 0}
133
- {#if options.href}
134
- <a
135
- href={resolveProp(options.href, areaData[0].datum, '')}
136
- target={resolveProp(options.target, areaData[0].datum, '_self')}>
137
- {@render el(areaData[0])}
138
- </a>
139
- {:else}
140
- {@render el(areaData[0])}
141
- {/if}
118
+ <Anchor {options} {datum}>
119
+ {@const title = resolveProp(options.title, datum.datum, '')}
120
+ {@const [style, styleClass] = resolveStyles(
121
+ plot,
122
+ datum,
123
+ options,
124
+ 'fill',
125
+ usedScales
126
+ )}
127
+ <path
128
+ class={['svelteplot-area', className, styleClass]}
129
+ clip-path={options.clipPath}
130
+ d={areaPath(areaData)}
131
+ {style}
132
+ >{#if title}<title>{title}</title>{/if}</path>
133
+ </Anchor>
142
134
  {/if}
143
135
  {/each}
144
136
  </GroupMultiple>
@@ -25,6 +25,8 @@
25
25
  tickClass?: ConstantAccessor<string>;
26
26
  /** ticks is a shorthand for defining data, tickCount or interval */
27
27
  ticks?: number | string | RawValue[];
28
+ /** set to false or null to disable tick labels */
29
+ text: boolean | null;
28
30
  } & XOR<
29
31
  {
30
32
  /** approximate number of ticks to be generated */
@@ -79,6 +81,7 @@
79
81
  class: className,
80
82
  tickCount = typeof magicTicks === 'number' ? magicTicks : undefined,
81
83
  tickSpacing,
84
+ text = true,
82
85
  ...options
83
86
  }: AxisXMarkProps = $props();
84
87
 
@@ -96,7 +99,7 @@
96
99
  const ticks: RawValue[] = $derived(
97
100
  data.length > 0
98
101
  ? // use custom tick values if user passed any as prop
99
- data
102
+ Array.from(new Set(data))
100
103
  : // use custom scale tick values if user passed any as plot scale option
101
104
  autoTicks(
102
105
  plot.scales.x.type,
@@ -220,6 +223,7 @@
220
223
  {tickPadding}
221
224
  {tickFontSize}
222
225
  {tickClass}
226
+ {text}
223
227
  {options}
224
228
  title={useTitle}
225
229
  {plot} />
@@ -14,6 +14,8 @@ export type AxisXMarkProps = Omit<BaseMarkProps, 'fill' | 'fillOpacity' | 'paint
14
14
  tickClass?: ConstantAccessor<string>;
15
15
  /** ticks is a shorthand for defining data, tickCount or interval */
16
16
  ticks?: number | string | RawValue[];
17
+ /** set to false or null to disable tick labels */
18
+ text: boolean | null;
17
19
  } & XOR<{
18
20
  /** approximate number of ticks to be generated */
19
21
  tickCount?: number;
@@ -26,6 +26,8 @@
26
26
  tickClass?: ConstantAccessor<string>;
27
27
  /** ticks is a shorthand for defining data, tickCount or interval */
28
28
  ticks?: number | string | RawValue[];
29
+ /** set to false or null to disable tick labels */
30
+ text: boolean | null;
29
31
  } & XOR<
30
32
  {
31
33
  /** approximate number of ticks to be generated */
@@ -78,6 +80,7 @@
78
80
  tickClass,
79
81
  tickCount = typeof magicTicks === 'number' ? magicTicks : undefined,
80
82
  tickSpacing,
83
+ text = true,
81
84
  ...options
82
85
  }: AxisYMarkProps = $props();
83
86
 
@@ -200,6 +203,7 @@
200
203
  {tickFontSize}
201
204
  {tickClass}
202
205
  {options}
206
+ {text}
203
207
  title={useTitle}
204
208
  {plot} />
205
209
  {/if}
@@ -15,6 +15,8 @@ export type AxisYMarkProps = Omit<BaseMarkProps, 'fill' | 'fillOpacity' | 'paint
15
15
  tickClass?: ConstantAccessor<string>;
16
16
  /** ticks is a shorthand for defining data, tickCount or interval */
17
17
  ticks?: number | string | RawValue[];
18
+ /** set to false or null to disable tick labels */
19
+ text: boolean | null;
18
20
  } & XOR<{
19
21
  /** approximate number of ticks to be generated */
20
22
  tickCount?: number;
@@ -7,10 +7,12 @@
7
7
  PlotContext,
8
8
  BaseMarkProps,
9
9
  BaseRectMarkProps,
10
- ChannelAccessor
10
+ ChannelAccessor,
11
+ LinkableMarkProps
11
12
  } from '../types.js';
12
13
 
13
14
  export type BarXMarkProps = BaseMarkProps &
15
+ LinkableMarkProps &
14
16
  BaseRectMarkProps & {
15
17
  data: DataRow[];
16
18
  x?: ChannelAccessor;
@@ -1,5 +1,5 @@
1
- import type { BaseMarkProps, BaseRectMarkProps, ChannelAccessor } from '../types.js';
2
- export type BarXMarkProps = BaseMarkProps & BaseRectMarkProps & {
1
+ import type { BaseMarkProps, BaseRectMarkProps, ChannelAccessor, LinkableMarkProps } from '../types.js';
2
+ export type BarXMarkProps = BaseMarkProps & LinkableMarkProps & BaseRectMarkProps & {
3
3
  data: DataRow[];
4
4
  x?: ChannelAccessor;
5
5
  x1?: ChannelAccessor;
@@ -12,6 +12,7 @@
12
12
  } from '../types.js';
13
13
 
14
14
  export type BarYMarkProps = BaseMarkProps &
15
+ LinkableMarkProps &
15
16
  BaseRectMarkProps & {
16
17
  data: DataRow[];
17
18
  x?: ChannelAccessor;
@@ -1,5 +1,5 @@
1
1
  import type { BaseMarkProps, BaseRectMarkProps, ChannelAccessor, DataRow } from '../types.js';
2
- export type BarYMarkProps = BaseMarkProps & BaseRectMarkProps & {
2
+ export type BarYMarkProps = BaseMarkProps & LinkableMarkProps & BaseRectMarkProps & {
3
3
  data: DataRow[];
4
4
  x?: ChannelAccessor;
5
5
  y?: ChannelAccessor;
@@ -14,6 +14,6 @@ export type BarYMarkProps = BaseMarkProps & BaseRectMarkProps & {
14
14
  };
15
15
  import type { StackOptions } from '../transforms/stack.js';
16
16
  /** For vertical column charts using a band scale as x axis */
17
- declare const BarY: import("svelte").Component<BarYMarkProps, {}, "">;
17
+ declare const BarY: import("svelte").Component<any, {}, "">;
18
18
  type BarY = ReturnType<typeof BarY>;
19
19
  export default BarY;
@@ -1,4 +1,4 @@
1
- <script module type="ts">
1
+ <script module lang="ts">
2
2
  export type BrushXMarkProps = Omit<BrushMarkProps, 'limitDimension'>;
3
3
  </script>
4
4
 
@@ -1,4 +1,4 @@
1
- <script module type="ts">
1
+ <script module lang="ts">
2
2
  export type BrushYMarkProps = Omit<BrushMarkProps, 'limitDimension'>;
3
3
  </script>
4
4
 
@@ -12,6 +12,7 @@
12
12
  } from '../types.js';
13
13
 
14
14
  export type CellMarkProps = BaseMarkProps &
15
+ LinkableMarkProps &
15
16
  BaseRectMarkProps & {
16
17
  data: DataRecord[];
17
18
  x?: ChannelAccessor;
@@ -1,10 +1,10 @@
1
1
  import type { DataRecord, BaseMarkProps, BaseRectMarkProps, ChannelAccessor } from '../types.js';
2
- export type CellMarkProps = BaseMarkProps & BaseRectMarkProps & {
2
+ export type CellMarkProps = BaseMarkProps & LinkableMarkProps & BaseRectMarkProps & {
3
3
  data: DataRecord[];
4
4
  x?: ChannelAccessor;
5
5
  y?: ChannelAccessor;
6
6
  };
7
7
  /** For arbitrary rectangles, requires band x and y scales */
8
- declare const Cell: import("svelte").Component<CellMarkProps, {}, "">;
8
+ declare const Cell: import("svelte").Component<any, {}, "">;
9
9
  type Cell = ReturnType<typeof Cell>;
10
10
  export default Cell;
@@ -167,6 +167,7 @@
167
167
  .swatch {
168
168
  display: inline-flex;
169
169
  align-items: center;
170
+ column-gap: 0.3rem;
170
171
  }
171
172
  .item-label {
172
173
  vertical-align: super;
@@ -10,7 +10,7 @@
10
10
  symbol?: ChannelAccessor | Snippet<[number, string]>;
11
11
  canvas?: boolean;
12
12
  dotClass?: ConstantAccessor<string>;
13
- };
13
+ } & LinkableMarkProps;
14
14
  </script>
15
15
 
16
16
  <script lang="ts">
@@ -21,8 +21,8 @@
21
21
  BaseMarkProps,
22
22
  ConstantAccessor,
23
23
  ChannelAccessor,
24
- FacetContext,
25
- PlotDefaults
24
+ PlotDefaults,
25
+ LinkableMarkProps
26
26
  } from '../types.js';
27
27
  import { resolveProp, resolveStyles } from '../helpers/resolve.js';
28
28
  import { maybeSymbol } from '../helpers/symbols.js';
@@ -33,6 +33,7 @@
33
33
  import { maybeData, isValid } from '../helpers/index.js';
34
34
  import { recordizeXY } from '../transforms/recordize.js';
35
35
  import { addEventHandlers } from './helpers/events.js';
36
+ import Anchor from './helpers/Anchor.svelte';
36
37
 
37
38
  let {
38
39
  data = [{}],
@@ -49,9 +50,7 @@
49
50
  return d3Symbol(maybeSymbol(symbolType), size)();
50
51
  }
51
52
 
52
- const { getTestFacet } = getContext<FacetContext>('svelteplot/facet');
53
53
  const { dotRadius } = getContext<PlotDefaults>('svelteplot/_defaults');
54
- let testFacet = $derived(getTestFacet());
55
54
 
56
55
  const args = $derived(
57
56
  // todo: move sorting to Mark
@@ -84,7 +83,7 @@
84
83
  defaults={{ r: dotRadius, symbol: 'circle' }}
85
84
  {...args}>
86
85
  {#snippet children({ mark, usedScales, scaledData })}
87
- <g class="dots {className || ''}">
86
+ <g class="dot {className || ''}">
88
87
  {#if canvas}
89
88
  <DotCanvas data={scaledData} {mark} />
90
89
  {:else}
@@ -97,19 +96,21 @@
97
96
  'stroke',
98
97
  usedScales
99
98
  )}
100
- <path
101
- transform="translate({d.x}, {d.y})"
102
- d={getSymbolPath(d.symbol, d.r ** 2 * Math.PI)}
103
- class={[
104
- dotClass ? resolveProp(dotClass, d.datum, null) : null,
105
- styleClass
106
- ]}
107
- {style}
108
- use:addEventHandlers={{
109
- getPlotState,
110
- options: args,
111
- datum: d.datum
112
- }} />
99
+ <Anchor {options} datum={d.datum}>
100
+ <path
101
+ transform="translate({d.x}, {d.y})"
102
+ d={getSymbolPath(d.symbol, d.r ** 2 * Math.PI)}
103
+ class={[
104
+ dotClass ? resolveProp(dotClass, d.datum, null) : null,
105
+ styleClass
106
+ ]}
107
+ {style}
108
+ use:addEventHandlers={{
109
+ getPlotState,
110
+ options: args,
111
+ datum: d.datum
112
+ }} />
113
+ </Anchor>
113
114
  {/if}
114
115
  {/each}
115
116
  {/if}
@@ -6,9 +6,9 @@ export type DotMarkProps = BaseMarkProps & {
6
6
  symbol?: ChannelAccessor | Snippet<[number, string]>;
7
7
  canvas?: boolean;
8
8
  dotClass?: ConstantAccessor<string>;
9
- };
9
+ } & LinkableMarkProps;
10
10
  import { type Snippet } from 'svelte';
11
- import type { DataRecord, BaseMarkProps, ConstantAccessor, ChannelAccessor } from '../types.js';
11
+ import type { DataRecord, BaseMarkProps, ConstantAccessor, ChannelAccessor, LinkableMarkProps } from '../types.js';
12
12
  /** Creates dots or symbols at specified positions with customizable size and appearance */
13
13
  declare const Dot: import("svelte").Component<DotMarkProps, {}, "">;
14
14
  type Dot = ReturnType<typeof Dot>;
@@ -7,6 +7,7 @@
7
7
  BaseMarkProps,
8
8
  'fill' | 'stroke' | 'fillOpacity' | 'strokeOpacity'
9
9
  > &
10
+ LinkableMarkProps &
10
11
  Omit<
11
12
  BaseRectMarkProps,
12
13
  'inset' | 'insetLeft' | 'insetRight' | 'insetTop' | 'insetBottom'
@@ -27,7 +28,7 @@
27
28
  <script lang="ts">
28
29
  import Mark from '../Mark.svelte';
29
30
  import { getContext } from 'svelte';
30
- import type { PlotContext, BaseRectMarkProps } from '../types.js';
31
+ import type { PlotContext, BaseRectMarkProps, LinkableMarkProps } from '../types.js';
31
32
  import type { BaseMarkProps } from '../types.js';
32
33
  import RectPath from './helpers/RectPath.svelte';
33
34
 
@@ -1,4 +1,4 @@
1
- export type FrameMarkProps = Omit<BaseMarkProps, 'fill' | 'stroke' | 'fillOpacity' | 'strokeOpacity'> & Omit<BaseRectMarkProps, 'inset' | 'insetLeft' | 'insetRight' | 'insetTop' | 'insetBottom'> & {
1
+ export type FrameMarkProps = Omit<BaseMarkProps, 'fill' | 'stroke' | 'fillOpacity' | 'strokeOpacity'> & LinkableMarkProps & Omit<BaseRectMarkProps, 'inset' | 'insetLeft' | 'insetRight' | 'insetTop' | 'insetBottom'> & {
2
2
  fill: string;
3
3
  stroke: string;
4
4
  fillOpacity: number;
@@ -10,7 +10,7 @@ export type FrameMarkProps = Omit<BaseMarkProps, 'fill' | 'stroke' | 'fillOpacit
10
10
  insetTop?: number;
11
11
  insetBottom?: number;
12
12
  };
13
- import type { BaseRectMarkProps } from '../types.js';
13
+ import type { BaseRectMarkProps, LinkableMarkProps } from '../types.js';
14
14
  import type { BaseMarkProps } from '../types.js';
15
15
  /** Renders a simple frame around the entire plot domain */
16
16
  declare const Frame: import("svelte").Component<FrameMarkProps, {}, "">;
@@ -7,8 +7,10 @@
7
7
  geoType?: 'sphere' | 'graticule';
8
8
  dragRotate: boolean;
9
9
  canvas: boolean;
10
- href: ConstantAccessor<string>;
11
- target: ConstantAccessor<string>;
10
+ /**
11
+ * simple browser tooltip to be displayed on mouseover
12
+ */
13
+ title: ConstantAccessor<string>;
12
14
  } & BaseMarkProps &
13
15
  LinkableMarkProps;
14
16
  </script>
@@ -31,6 +33,7 @@
31
33
  import GeoCanvas from './helpers/GeoCanvas.svelte';
32
34
  import { recordize } from '../transforms/recordize.js';
33
35
  import { GEOJSON_PREFER_STROKE } from '../helpers/index.js';
36
+ import Anchor from './helpers/Anchor.svelte';
34
37
 
35
38
  const { getPlotState } = getContext<PlotContext>('svelteplot');
36
39
  const plot = $derived(getPlotState());
@@ -68,28 +71,6 @@
68
71
  channels={['fill', 'stroke', 'opacity', 'fillOpacity', 'strokeOpacity', 'r']}
69
72
  {...args}>
70
73
  {#snippet children({ mark, scaledData, usedScales })}
71
- {#snippet el(d)}
72
- {@const title = resolveProp(args.title, d.datum, '')}
73
- {@const geometry = resolveProp(args.geometry, d.datum, d.datum)}
74
- {@const [style, styleClass] = resolveStyles(
75
- plot,
76
- d,
77
- args,
78
- GEOJSON_PREFER_STROKE.has(geometry.type) ? 'stroke' : 'fill',
79
- usedScales
80
- )}
81
- <path
82
- d={path(geometry)}
83
- {style}
84
- class={[styleClass]}
85
- use:addEventHandlers={{
86
- getPlotState,
87
- options: args,
88
- datum: d.datum
89
- }}>
90
- {#if title}<title>{title}</title>{/if}
91
- </path>
92
- {/snippet}
93
74
  <g
94
75
  aria-label="geo"
95
76
  class={['geo', geoType && `geo-${geoType}`, className]}
@@ -99,15 +80,28 @@
99
80
  {:else}
100
81
  {#each scaledData as d, i (i)}
101
82
  {#if d.valid}
102
- {#if options.href}
103
- <a
104
- href={resolveProp(args.href, d.datum, '')}
105
- target={resolveProp(args.target, d.datum, '_self')}>
106
- {@render el(d)}
107
- </a>
108
- {:else}
109
- {@render el(d)}
110
- {/if}
83
+ <Anchor {options} datum={d.datum}>
84
+ {@const title = resolveProp(args.title, d.datum, '')}
85
+ {@const geometry = resolveProp(args.geometry, d.datum, d.datum)}
86
+ {@const [style, styleClass] = resolveStyles(
87
+ plot,
88
+ d,
89
+ args,
90
+ GEOJSON_PREFER_STROKE.has(geometry.type) ? 'stroke' : 'fill',
91
+ usedScales
92
+ )}
93
+ <path
94
+ d={path(geometry)}
95
+ {style}
96
+ class={[styleClass]}
97
+ use:addEventHandlers={{
98
+ getPlotState,
99
+ options: args,
100
+ datum: d.datum
101
+ }}>
102
+ {#if title}<title>{title}</title>{/if}
103
+ </path>
104
+ </Anchor>
111
105
  {/if}
112
106
  {/each}
113
107
  {/if}
@@ -3,8 +3,10 @@ export type GeoMarkProps = {
3
3
  geoType?: 'sphere' | 'graticule';
4
4
  dragRotate: boolean;
5
5
  canvas: boolean;
6
- href: ConstantAccessor<string>;
7
- target: ConstantAccessor<string>;
6
+ /**
7
+ * simple browser tooltip to be displayed on mouseover
8
+ */
9
+ title: ConstantAccessor<string>;
8
10
  } & BaseMarkProps & LinkableMarkProps;
9
11
  import type { DataRecord, BaseMarkProps, ConstantAccessor, LinkableMarkProps } from '../types.js';
10
12
  /** Renders geographical data using projections and GeoJSON geometries */
@@ -13,6 +13,7 @@
13
13
  y2?: ChannelAccessor;
14
14
  interval?: number | string;
15
15
  } & BaseMarkProps &
16
+ LinkableMarkProps &
16
17
  BaseRectMarkProps;
17
18
  </script>
18
19
 
@@ -7,9 +7,9 @@ export type RectMarkProps = {
7
7
  y1?: ChannelAccessor;
8
8
  y2?: ChannelAccessor;
9
9
  interval?: number | string;
10
- } & BaseMarkProps & BaseRectMarkProps;
10
+ } & BaseMarkProps & LinkableMarkProps & BaseRectMarkProps;
11
11
  import type { DataRecord, BaseMarkProps, BaseRectMarkProps, ChannelAccessor } from '../types.js';
12
12
  /** For arbitrary rectangles, requires quantitative x and y scales */
13
- declare const Rect: import("svelte").Component<RectMarkProps, {}, "">;
13
+ declare const Rect: import("svelte").Component<any, {}, "">;
14
14
  type Rect = ReturnType<typeof Rect>;
15
15
  export default Rect;
@@ -2,8 +2,8 @@
2
2
  Geo mark with Sphere geometry object -->
3
3
 
4
4
  <script module lang="ts">
5
- import { type BaseMarkProps } from '../types.js';
6
- export type SphereMarkProps = BaseMarkProps;
5
+ import { type BaseMarkProps, type LinkableMarkProps } from '../types.js';
6
+ export type SphereMarkProps = BaseMarkProps & LinkableMarkProps;
7
7
  </script>
8
8
 
9
9
  <script lang="ts">