@fundar/data-chart-telling 0.0.7 → 0.0.9

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.
@@ -210,6 +210,7 @@
210
210
  ruleX={showRuleX ? ctrl.ruleX : null}
211
211
  ruleY={showRuleY ? ctrl.ruleY : null}
212
212
  showLabels={unscopedHoverMarker.showLabels ?? showHoverLabels}
213
+ format={unscopedHoverMarker.format}
213
214
  ruleStyle={unscopedHoverMarker.ruleStyle}
214
215
  dotStyle={unscopedHoverMarker.dotStyle}
215
216
  fontStyle={unscopedHoverMarker.fontStyle}
@@ -63,7 +63,7 @@
63
63
  const yAcc = $derived(resolveAccessor(resolvedSeries[0]?.y ?? ((d: TData) => d)));
64
64
  const flat = $derived(resolvedSeries.flatMap((s) => s.data));
65
65
  const hoverPoints = $derived(
66
- resolvedSeries.flatMap((s) => {
66
+ resolvedSeries.flatMap((s, idx) => {
67
67
  const sx = resolveAccessor(s.x);
68
68
  const sy = resolveAccessor(s.y);
69
69
  return s.data.map((d) => ({
@@ -72,6 +72,7 @@
72
72
  row: d,
73
73
  label: String(sy(d)),
74
74
  series: s.name,
75
+ color: paletteColor(idx, cfg.palette),
75
76
  }));
76
77
  }),
77
78
  );
@@ -62,7 +62,7 @@
62
62
  const yAcc = $derived(resolveAccessor(resolvedSeries[0]?.y ?? ((d: TData) => d)));
63
63
  const flat = $derived(resolvedSeries.flatMap((s) => s.data));
64
64
  const hoverPoints = $derived(
65
- resolvedSeries.flatMap((s) => {
65
+ resolvedSeries.flatMap((s, idx) => {
66
66
  const sx = resolveAccessor(s.x);
67
67
  const sy = resolveAccessor(s.y);
68
68
  return s.data.map((d) => ({
@@ -71,6 +71,7 @@
71
71
  row: d,
72
72
  label: String(sy(d)),
73
73
  series: s.name,
74
+ color: paletteColor(idx, cfg.palette),
74
75
  }));
75
76
  }),
76
77
  );
@@ -19,6 +19,7 @@
19
19
  ruleX?: AxisValue | null;
20
20
  ruleY?: AxisValue | null;
21
21
  showLabels?: boolean;
22
+ format?: (point: HoverDisplayPoint) => string;
22
23
  ruleStyle?: StrokeStyle;
23
24
  dotStyle?: DotStyle;
24
25
  fontStyle?: FontStyle;
@@ -29,6 +30,7 @@
29
30
  ruleX = null,
30
31
  ruleY = null,
31
32
  showLabels = true,
33
+ format,
32
34
  ruleStyle,
33
35
  dotStyle,
34
36
  fontStyle,
@@ -60,19 +62,32 @@
60
62
  {/if}
61
63
 
62
64
  {#if data.length > 0}
63
- <DotMarker
64
- {data}
65
- x={(d) => d.x}
66
- y={(d) => d.y}
67
- style={{ ...cfg.hover.dot, ...dotStyle }}
68
- />
69
- {#if showLabels}
70
- <TextMarker
71
- {data}
65
+ {#each data as point (point.series ?? `${point.x}_${point.y}`)}
66
+ <DotMarker
67
+ data={[point]}
72
68
  x={(d) => d.x}
73
69
  y={(d) => d.y}
74
- text={(d) => d.label ?? ''}
75
- style={{ ...cfg.hover.font, ...fontStyle }}
70
+ style={{
71
+ ...cfg.hover.dot,
72
+ ...dotStyle,
73
+ ...(dotStyle?.dotFill === 'currentColor' && point.color ? { dotFill: point.color } : {}),
74
+ ...(dotStyle?.dotStroke === 'currentColor' && point.color ? { dotStroke: point.color } : {}),
75
+ }}
76
76
  />
77
+ {/each}
78
+ {#if showLabels}
79
+ {#each data as point (point.series ?? `${point.x}_${point.y}`)}
80
+ <TextMarker
81
+ data={[point]}
82
+ x={(d) => d.x}
83
+ y={(d) => d.y}
84
+ text={(d) => format ? format(d) : (d.label ?? '')}
85
+ style={{
86
+ ...cfg.hover.font,
87
+ ...fontStyle,
88
+ ...(fontStyle?.fill === 'currentColor' && point.color ? { fill: point.color } : {}),
89
+ }}
90
+ />
91
+ {/each}
77
92
  {/if}
78
93
  {/if}
@@ -13,6 +13,7 @@ interface Props extends MarkerProps<HoverDisplayPoint> {
13
13
  ruleX?: AxisValue | null;
14
14
  ruleY?: AxisValue | null;
15
15
  showLabels?: boolean;
16
+ format?: (point: HoverDisplayPoint) => string;
16
17
  ruleStyle?: StrokeStyle;
17
18
  dotStyle?: DotStyle;
18
19
  fontStyle?: FontStyle;
@@ -118,6 +118,7 @@
118
118
  row: d,
119
119
  label: d.__label,
120
120
  series: d.__series,
121
+ color: d.__side === 'left' ? leftColor : rightColor,
121
122
  })),
122
123
  );
123
124
 
@@ -68,6 +68,27 @@ export function validateSegments(segments) {
68
68
  check(key === DEFAULT_KEY ? '(default)' : `"${key}"`, segs);
69
69
  }
70
70
  }
71
+ function isPlainObject(v) {
72
+ return v !== null && typeof v === 'object' && !Array.isArray(v);
73
+ }
74
+ /**
75
+ * Merges two style objects one level deep: for any key where both base and
76
+ * override hold plain objects (e.g. `stroke`, `dots`), their fields are
77
+ * merged — override wins on conflict. Primitive fields are overridden directly.
78
+ */
79
+ function mergeStyles(base, override) {
80
+ const result = { ...base };
81
+ for (const [key, val] of Object.entries(override)) {
82
+ const baseVal = result[key];
83
+ if (isPlainObject(val) && isPlainObject(baseVal)) {
84
+ result[key] = { ...baseVal, ...val };
85
+ }
86
+ else {
87
+ result[key] = val;
88
+ }
89
+ }
90
+ return result;
91
+ }
71
92
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
72
93
  function resolveSeriesSegments(series, segs) {
73
94
  if (!segs.length) {
@@ -143,7 +164,7 @@ function resolveSeriesSegments(series, segs) {
143
164
  // keys fill in whatever the area segment omits; the area wins on conflict.
144
165
  const isAreaSpecific = seg.areas != null && seg.areas.length > 0;
145
166
  const resolvedStyle = isAreaSpecific && catchAll?.style
146
- ? { ...catchAll.style, ...segStyle }
167
+ ? mergeStyles(catchAll.style, segStyle)
147
168
  : segStyle;
148
169
  userVisual.push({ data: run.data, style: resolvedStyle });
149
170
  // When the next run is also a user segment (no unmatched data between them),
@@ -81,6 +81,8 @@ export type HoverDisplayPoint = {
81
81
  label: string;
82
82
  /** Owning series name; undefined for plot kinds with no series concept (heatmap). */
83
83
  series?: string;
84
+ /** Resolved series color — used by HoverMarker when dotFill/fill is `'currentColor'`. */
85
+ color?: string;
84
86
  };
85
87
  /** A candidate point for hover matching/highlighting — also carries its source row. */
86
88
  export type HoverPoint<T> = HoverDisplayPoint & {
@@ -1,6 +1,6 @@
1
1
  import type { AxisValue } from './common';
2
2
  import type { DotStyle, FontStyle, StrokeStyle } from './styles';
3
- import type { HoverStrategy } from '../layout/tooltip';
3
+ import type { HoverStrategy, HoverDisplayPoint } from '../layout/tooltip';
4
4
  /**
5
5
  * Baseline props every marker component receives when mounted by a plot:
6
6
  * `data` for the points/values it draws, plus `series`/`seriesColor` when
@@ -40,6 +40,8 @@ export type HoverMarkerConfig = {
40
40
  ruleX?: boolean;
41
41
  ruleY?: boolean;
42
42
  showLabels?: boolean;
43
+ /** Custom label formatter. Receives the matched point; return the string to display. */
44
+ format?: (point: HoverDisplayPoint) => string;
43
45
  ruleStyle?: StrokeStyle;
44
46
  dotStyle?: DotStyle;
45
47
  fontStyle?: FontStyle;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fundar/data-chart-telling",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"