@fundar/data-chart-telling 0.0.40 → 0.0.42

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.
@@ -21,7 +21,7 @@
21
21
  validateSegments,
22
22
  buildScopedMarkerGroups
23
23
  } from '../utils/segments';
24
- import type { BasePlotProps } from '../../types/plots/props';
24
+ import type { BasePlotProps, MarginConfig } from '../../types/plots/props';
25
25
  import type { AxisValue, AxisBasedScalesConfig } from '../../types/layout/scales';
26
26
  import type { Series, SeriesProps, DataProps } from '../../types/plots/data/common';
27
27
  import type { GapsAwarePlotStylesConfig } from '../../types/layout/styles';
@@ -50,7 +50,7 @@
50
50
  segments = {},
51
51
  markers = [],
52
52
  scales = {},
53
- margins,
53
+ margins = $bindable(),
54
54
  tooltip = undefined
55
55
  }: Props = $props();
56
56
 
@@ -129,7 +129,9 @@
129
129
  buildGapMarkers<TData>({
130
130
  seriesList: resolvedSeries,
131
131
  gaps,
132
- colorFor: (seriesIndex) => paletteColor(seriesIndex, cfg.palette)
132
+ colorFor: (seriesIndex) => paletteColor(seriesIndex, cfg.palette),
133
+ disabledStrokeFor: (name) => disabledStrokeOverride(effectiveDisabledFor(name)),
134
+ disabledDotsFor: (name) => disabledDotsOverride(effectiveDisabledFor(name))
133
135
  })
134
136
  );
135
137
 
@@ -169,6 +171,26 @@
169
171
  () => margins,
170
172
  () => resolvedSeries
171
173
  );
174
+
175
+ // Writes the resolved margin back into the bindable `margins` prop once it
176
+ // settles, so a caller binding it (`bind:margins`) can capture and reuse a
177
+ // fixed margin later. `lastWritten` is a plain variable (not `$state`) so
178
+ // the effect only depends on `resolvedMargins`, never on `margins` itself.
179
+ let lastWritten: MarginConfig | undefined;
180
+ $effect(() => {
181
+ const next = labelMargin.resolvedMargins;
182
+ if (!next) return;
183
+ const changed =
184
+ !lastWritten ||
185
+ next.top !== lastWritten.top ||
186
+ next.right !== lastWritten.right ||
187
+ next.bottom !== lastWritten.bottom ||
188
+ next.left !== lastWritten.left;
189
+ if (changed) {
190
+ lastWritten = { top: next.top, right: next.right, bottom: next.bottom, left: next.left };
191
+ margins = next;
192
+ }
193
+ });
172
194
  </script>
173
195
 
174
196
  <BasePlotLayout
@@ -7,7 +7,7 @@ import type { LineMarkersConfig } from '../../types/markers/line';
7
7
  declare function $$render<TData extends Record<string, unknown>>(): {
8
8
  props: BasePlotProps<SeriesProps<TData> | DataProps<TData>, TData, GapsAwarePlotStylesConfig<LineSegmentStyle>, LineSegmentStyle, LineMarkersConfig, AxisBasedScalesConfig<TData>>;
9
9
  exports: {};
10
- bindings: "";
10
+ bindings: "margins";
11
11
  slots: {};
12
12
  events: {};
13
13
  };
@@ -15,7 +15,7 @@ declare class __sveltets_Render<TData extends Record<string, unknown>> {
15
15
  props(): ReturnType<typeof $$render<TData>>['props'];
16
16
  events(): ReturnType<typeof $$render<TData>>['events'];
17
17
  slots(): ReturnType<typeof $$render<TData>>['slots'];
18
- bindings(): "";
18
+ bindings(): "margins";
19
19
  exports(): {};
20
20
  }
21
21
  interface $$IsomorphicComponent {
@@ -2,6 +2,7 @@ import type { Series } from '../../types/plots/data/common';
2
2
  import type { GapsConfig } from '../../types/plots/gaps';
3
3
  import type { LineSegmentStyle } from '../../types/plots/segments/common';
4
4
  import type { LineMarkerConfig, DotMarkerConfig } from '../../types/markers/common';
5
+ import type { StrokeStyle, DotStyle } from '../../types/plots/styling';
5
6
  /**
6
7
  * One `'line'` (+ `'dot'`, when its zone sets `style.dots`) marker per
7
8
  * detected, configured gap run across every series — the interpolated
@@ -12,10 +13,16 @@ import type { LineMarkerConfig, DotMarkerConfig } from '../../types/markers/comm
12
13
  * muted out of the box), so a gap-fill reads as estimated rather than real
13
14
  * data unless a zone or the global configuration overrides it. Dots (when
14
15
  * requested) are drawn only at a run's two endpoints, not along every
15
- * sampled bridge point.
16
+ * sampled bridge point. `disabledStrokeFor`/`disabledDotsFor` mirror
17
+ * `buildLineMarkers`'s own params — a legend-disabled (or hover-isolated)
18
+ * series must dim its gap bridge exactly like it dims the real line it's
19
+ * bridging, so both take the same precedence: disabled override, then the
20
+ * gap zone's own style, then the shared gap default.
16
21
  */
17
22
  export declare function buildGapMarkers<TData extends Record<string, unknown>>(args: {
18
23
  seriesList: Series<TData>[];
19
24
  gaps: GapsConfig<LineSegmentStyle>;
20
25
  colorFor: (seriesIndex: number) => string;
26
+ disabledStrokeFor: (seriesName: string) => StrokeStyle | undefined;
27
+ disabledDotsFor: (seriesName: string) => DotStyle | undefined;
21
28
  }): (LineMarkerConfig | DotMarkerConfig)[];
@@ -12,10 +12,14 @@ const gy = (p) => p.y;
12
12
  * muted out of the box), so a gap-fill reads as estimated rather than real
13
13
  * data unless a zone or the global configuration overrides it. Dots (when
14
14
  * requested) are drawn only at a run's two endpoints, not along every
15
- * sampled bridge point.
15
+ * sampled bridge point. `disabledStrokeFor`/`disabledDotsFor` mirror
16
+ * `buildLineMarkers`'s own params — a legend-disabled (or hover-isolated)
17
+ * series must dim its gap bridge exactly like it dims the real line it's
18
+ * bridging, so both take the same precedence: disabled override, then the
19
+ * gap zone's own style, then the shared gap default.
16
20
  */
17
21
  export function buildGapMarkers(args) {
18
- const { seriesList, gaps, colorFor } = args;
22
+ const { seriesList, gaps, colorFor, disabledStrokeFor, disabledDotsFor } = args;
19
23
  const cfg = getConfiguration();
20
24
  const gapDefaults = cfg.line.gap;
21
25
  const markers = [];
@@ -25,6 +29,8 @@ export function buildGapMarkers(args) {
25
29
  if (runs.length === 0)
26
30
  return;
27
31
  const defaultColor = colorFor(seriesIndex);
32
+ const disabledStroke = disabledStrokeFor(series.name);
33
+ const disabledDots = disabledDotsFor(series.name);
28
34
  for (const run of runs) {
29
35
  const strokeStyle = run.zone.style?.stroke;
30
36
  const dotStyle = run.zone.style?.dots;
@@ -34,12 +40,12 @@ export function buildGapMarkers(args) {
34
40
  x: gx,
35
41
  y: gy,
36
42
  style: {
37
- stroke: strokeStyle?.stroke ?? defaultColor,
38
- strokeWidth: strokeStyle?.strokeWidth ?? gapDefaults.stroke.strokeWidth ?? cfg.line.strokeWidth,
39
- strokeOpacity: strokeStyle?.strokeOpacity ?? gapDefaults.stroke.strokeOpacity,
40
- strokeDasharray: strokeStyle?.strokeDasharray ?? gapDefaults.stroke.strokeDasharray,
41
- strokeLinejoin: strokeStyle?.strokeLinejoin ?? gapDefaults.stroke.strokeLinejoin,
42
- strokeLinecap: strokeStyle?.strokeLinecap ?? gapDefaults.stroke.strokeLinecap,
43
+ stroke: disabledStroke?.stroke ?? strokeStyle?.stroke ?? defaultColor,
44
+ strokeWidth: disabledStroke?.strokeWidth ?? strokeStyle?.strokeWidth ?? gapDefaults.stroke.strokeWidth ?? cfg.line.strokeWidth,
45
+ strokeOpacity: disabledStroke?.strokeOpacity ?? strokeStyle?.strokeOpacity ?? gapDefaults.stroke.strokeOpacity,
46
+ strokeDasharray: disabledStroke?.strokeDasharray ?? strokeStyle?.strokeDasharray ?? gapDefaults.stroke.strokeDasharray,
47
+ strokeLinejoin: disabledStroke?.strokeLinejoin ?? strokeStyle?.strokeLinejoin ?? gapDefaults.stroke.strokeLinejoin,
48
+ strokeLinecap: disabledStroke?.strokeLinecap ?? strokeStyle?.strokeLinecap ?? gapDefaults.stroke.strokeLinecap,
43
49
  },
44
50
  });
45
51
  if (!dotStyle)
@@ -52,14 +58,14 @@ export function buildGapMarkers(args) {
52
58
  x: gx,
53
59
  y: gy,
54
60
  style: {
55
- dotRadius: dotStyle.dotRadius ?? dotDefaults.dotRadius ?? cfg.line.dotRadius,
56
- dotFill: dotStyle.dotFill ?? strokeStyle?.stroke ?? dotDefaults.dotFill ?? defaultColor,
57
- dotSymbol: dotStyle.dotSymbol ?? dotDefaults.dotSymbol ?? 'circle',
58
- dotStroke: dotStyle.dotStroke ?? strokeStyle?.stroke ?? dotDefaults.dotStroke ?? defaultColor,
59
- dotStrokeWidth: dotStyle.dotStrokeWidth ?? dotDefaults.dotStrokeWidth ?? 1,
60
- dotFillOpacity: dotStyle.dotFillOpacity ?? dotDefaults.dotFillOpacity ?? 1,
61
- dotStrokeOpacity: dotStyle.dotStrokeOpacity ?? dotDefaults.dotStrokeOpacity ?? 1,
62
- dotStrokeDasharray: dotStyle.dotStrokeDasharray ?? dotDefaults.dotStrokeDasharray,
61
+ dotRadius: disabledDots?.dotRadius ?? dotStyle.dotRadius ?? dotDefaults.dotRadius ?? cfg.line.dotRadius,
62
+ dotFill: disabledDots?.dotFill ?? dotStyle.dotFill ?? strokeStyle?.stroke ?? dotDefaults.dotFill ?? defaultColor,
63
+ dotSymbol: disabledDots?.dotSymbol ?? dotStyle.dotSymbol ?? dotDefaults.dotSymbol ?? 'circle',
64
+ dotStroke: disabledDots?.dotStroke ?? dotStyle.dotStroke ?? strokeStyle?.stroke ?? dotDefaults.dotStroke ?? defaultColor,
65
+ dotStrokeWidth: disabledDots?.dotStrokeWidth ?? dotStyle.dotStrokeWidth ?? dotDefaults.dotStrokeWidth ?? 1,
66
+ dotFillOpacity: disabledDots?.dotFillOpacity ?? dotStyle.dotFillOpacity ?? dotDefaults.dotFillOpacity ?? 1,
67
+ dotStrokeOpacity: disabledDots?.dotStrokeOpacity ?? dotStyle.dotStrokeOpacity ?? dotDefaults.dotStrokeOpacity ?? 1,
68
+ dotStrokeDasharray: disabledDots?.dotStrokeDasharray ?? dotStyle.dotStrokeDasharray ?? dotDefaults.dotStrokeDasharray,
63
69
  },
64
70
  });
65
71
  }
@@ -160,15 +160,18 @@ export function createLabelMarginTracker(margins, resetKey) {
160
160
  out.bottom = AUTO_MARGIN_ESTIMATE.bottom + measured.bottom;
161
161
  return out;
162
162
  });
163
- // Bundles `resolvedMargins` with a remount key derived from `measured`,
164
- // ready to spread straight onto `<BasePlotLayout>` as its `margins`/
165
- // `marginRemountKey` props (see that prop's doc comment for *why* a
166
- // remount key is needed here at all) — keeps the caller from re-deriving
167
- // the same key by hand, and from having to know it's `measured` that key
168
- // must track.
163
+ // Bundles `resolvedMargins` with a remount key, ready to spread straight
164
+ // onto `<BasePlotLayout>` as its `margins`/`marginRemountKey` props (see
165
+ // that prop's doc comment for *why* a remount key is needed here at all)
166
+ // — keeps the caller from re-deriving the same key by hand. Tracks both
167
+ // `measured` (this tracker's own auto-grown overflow) and the caller's
168
+ // own `margins()` — a caller that changes its explicit margins prop
169
+ // after mount (e.g. locking in a previously-measured value) needs that
170
+ // picked up just as cleanly as internal growth does; keying only on
171
+ // `measured` would silently miss it.
169
172
  const plotProps = $derived.by(() => ({
170
173
  margins: resolvedMargins,
171
- marginRemountKey: JSON.stringify(measured)
174
+ marginRemountKey: JSON.stringify({ base: margins(), measured })
172
175
  }));
173
176
  return {
174
177
  report,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fundar/data-chart-telling",
3
- "version": "0.0.40",
3
+ "version": "0.0.42",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"