smithkit 0.5.0 → 0.7.0

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 (37) hide show
  1. package/README.md +47 -938
  2. package/dist/lib/OptionsValidation.d.ts +3 -3
  3. package/dist/lib/OptionsValidation.js +17 -13
  4. package/dist/lib/Smith.d.ts +3 -0
  5. package/dist/lib/Smith.js +42 -14
  6. package/dist/lib/appearance/SvgTheme.d.ts +1 -0
  7. package/dist/lib/appearance/SvgTheme.js +8 -7
  8. package/dist/lib/appearance/Theme.js +49 -52
  9. package/dist/lib/appearance/types.d.ts +75 -31
  10. package/dist/lib/grid/CircleLayerControl.d.ts +2 -2
  11. package/dist/lib/grid/CircleLayerControl.js +4 -4
  12. package/dist/lib/grid/ConstCircles.js +6 -6
  13. package/dist/lib/grid/ConstQCircles.js +4 -1
  14. package/dist/lib/grid/ConstSwrCircles.js +4 -1
  15. package/dist/lib/grid/GridLayerControl.d.ts +2 -2
  16. package/dist/lib/grid/GridLayerControl.js +10 -11
  17. package/dist/lib/grid/SmithGridLayer.js +3 -1
  18. package/dist/lib/index.d.ts +2 -2
  19. package/dist/lib/interaction/SmithCursor.js +6 -6
  20. package/dist/lib/layers.d.ts +28 -14
  21. package/dist/lib/math/Complex.d.ts +1 -1
  22. package/dist/lib/math/Complex.js +2 -2
  23. package/dist/lib/measurements.d.ts +20 -8
  24. package/dist/lib/options.d.ts +4 -4
  25. package/dist/lib/rendering/ChartHost.d.ts +5 -0
  26. package/dist/lib/rendering/ChartHost.js +14 -0
  27. package/dist/lib/rendering/SvgChartRenderer.d.ts +2 -2
  28. package/dist/lib/rendering/SvgChartRenderer.js +2 -2
  29. package/dist/lib/scales/SmithPeripheralScales.js +11 -11
  30. package/dist/lib/scales/SmithScales.d.ts +3 -0
  31. package/dist/lib/scales/SmithScales.js +39 -18
  32. package/dist/lib/svg/LabelLayout.js +9 -2
  33. package/dist/lib/traces/SmithData.d.ts +3 -3
  34. package/dist/lib/traces/SmithMarker.js +6 -5
  35. package/dist/lib/traces/TraceRenderer.d.ts +3 -3
  36. package/dist/lib/traces/TraceRenderer.js +19 -18
  37. package/package.json +24 -6
@@ -1,5 +1,5 @@
1
1
  import type { SmithOptions } from './options.js';
2
- import type { CircleStyle, GridDetail, GridStyle } from './layers.js';
2
+ import type { CircleStyleOptions, GridDetail, GridStyleOptions } from './layers.js';
3
3
  /** Shared validation for initial configuration, patches, and individual controls. */
4
4
  export declare class OptionsValidation {
5
5
  private constructor();
@@ -8,8 +8,8 @@ export declare class OptionsValidation {
8
8
  static detail(value: GridDetail): void;
9
9
  private static lengths;
10
10
  private static strings;
11
- static gridStyle(style: Partial<GridStyle>): void;
12
- static circleStyle(style: Partial<CircleStyle>): void;
11
+ static gridStyle(style: GridStyleOptions): void;
12
+ static circleStyle(style: CircleStyleOptions): void;
13
13
  static circleValue(value: number, minimum: number): void;
14
14
  static circleValues(values: readonly number[], minimum: number): void;
15
15
  static chart(options: SmithOptions): void;
@@ -41,21 +41,25 @@ export class OptionsValidation {
41
41
  }
42
42
  }
43
43
  static gridStyle(style) {
44
- OptionsValidation.object(style, 'Grid style', [
45
- 'stroke',
46
- 'majorWidth',
47
- 'minorWidth',
48
- 'textColor',
49
- 'textFontFamily',
50
- 'textFontSize',
51
- ]);
52
- OptionsValidation.lengths(style, ['majorWidth', 'minorWidth', 'textFontSize']);
53
- OptionsValidation.strings(style, ['stroke', 'textColor', 'textFontFamily']);
44
+ OptionsValidation.object(style, 'Grid style', ['line', 'text']);
45
+ if (style.line !== undefined) {
46
+ OptionsValidation.object(style.line, 'Grid line', ['color', 'majorWidth', 'minorWidth']);
47
+ OptionsValidation.lengths(style.line, ['majorWidth', 'minorWidth']);
48
+ OptionsValidation.strings(style.line, ['color']);
49
+ }
50
+ if (style.text !== undefined) {
51
+ OptionsValidation.object(style.text, 'Grid text', ['color', 'fontFamily', 'fontSize']);
52
+ OptionsValidation.lengths(style.text, ['fontSize']);
53
+ OptionsValidation.strings(style.text, ['color', 'fontFamily']);
54
+ }
54
55
  }
55
56
  static circleStyle(style) {
56
- OptionsValidation.object(style, 'Circle style', ['stroke', 'strokeWidth']);
57
- OptionsValidation.lengths(style, ['strokeWidth']);
58
- OptionsValidation.strings(style, ['stroke']);
57
+ OptionsValidation.object(style, 'Circle style', ['line']);
58
+ if (style.line !== undefined) {
59
+ OptionsValidation.object(style.line, 'Circle line', ['color', 'width']);
60
+ OptionsValidation.lengths(style.line, ['width']);
61
+ OptionsValidation.strings(style.line, ['color']);
62
+ }
59
63
  }
60
64
  static circleValue(value, minimum) {
61
65
  if (!Number.isFinite(value) || value < minimum || value <= 0) {
@@ -34,7 +34,10 @@ export declare class Smith {
34
34
  private listeners;
35
35
  readonly layers: ChartLayers;
36
36
  readonly peripheralScales: PeripheralScales;
37
+ /** Configure a chart for later mounting with draw(). */
37
38
  constructor(options?: SmithOptions);
39
+ /** Configure and mount immediately. String targets are CSS selectors, as in draw(). */
40
+ constructor(target: string | HTMLElement, options?: SmithOptions);
38
41
  /** Apply a validated patch. Omitted fields retain their current settings. */
39
42
  setOptions(options: SmithOptions): void;
40
43
  private applyOptions;
package/dist/lib/Smith.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { OptionsValidation } from './OptionsValidation.js';
2
+ import { ChartHost } from './rendering/ChartHost.js';
2
3
  import { MarkerLegend } from './svg/MarkerLegend.js';
3
4
  import { ImageExporter } from './svg/ImageExporter.js';
4
5
  import { Theme } from './appearance/Theme.js';
@@ -30,7 +31,18 @@ export class Smith {
30
31
  listeners = new Set();
31
32
  layers;
32
33
  peripheralScales;
33
- constructor(options = {}) {
34
+ constructor(targetOrOptions = {}, configuration) {
35
+ const target = typeof targetOrOptions === 'string' || ChartHost.isElement(targetOrOptions)
36
+ ? targetOrOptions
37
+ : undefined;
38
+ if (target === undefined && configuration !== undefined) {
39
+ throw new TypeError('A container is required before the second options argument.');
40
+ }
41
+ const options = target === undefined
42
+ ? targetOrOptions
43
+ : configuration === undefined
44
+ ? {}
45
+ : configuration;
34
46
  OptionsValidation.chart(options);
35
47
  this.referenceOhms =
36
48
  options.referenceImpedanceOhms === undefined ? 50 : options.referenceImpedanceOhms;
@@ -49,6 +61,9 @@ export class Smith {
49
61
  this.peripheralScales = this.renderer.peripheralScales;
50
62
  try {
51
63
  this.applyOptions(options);
64
+ if (target !== undefined) {
65
+ this.draw(target);
66
+ }
52
67
  }
53
68
  catch (error) {
54
69
  // Invalid constructor options must not retain observers or event handlers.
@@ -133,7 +148,7 @@ export class Smith {
133
148
  for (const data of this.data) {
134
149
  const index = this.traceMetadata.get(data).colorIndex;
135
150
  if (index !== undefined) {
136
- data.setColor(theme.traceColors[index % theme.traceColors.length]);
151
+ data.setColor(theme.traces.colors[index % theme.traces.colors.length]);
137
152
  }
138
153
  }
139
154
  }
@@ -149,13 +164,10 @@ export class Smith {
149
164
  }
150
165
  }
151
166
  /** Export the current mounted view as standalone SVG with its configured background. */
152
- toSvg(options) {
167
+ toSvg(options = {}) {
153
168
  this.assertAlive();
154
169
  this.validateExportOptions(options);
155
- const source = this.renderer.toSvg(options?.lineDetail ?? 'full');
156
- if (options === undefined) {
157
- return source;
158
- }
170
+ const source = this.renderer.toSvg(options.lineDetail ?? 'full');
159
171
  const sources = [source];
160
172
  if (options.scales) {
161
173
  sources.push(options.scales.toSvg({ readout: options.scaleReadout }));
@@ -179,8 +191,8 @@ export class Smith {
179
191
  ? MarkerLegend.entries(traces, (id) => this.getMarker(id), options.markerLegend)
180
192
  : []),
181
193
  ],
182
- textColor: this.theme.grid.textColor,
183
- fontFamily: this.theme.fontFamily,
194
+ textColor: this.theme.grid.text.color,
195
+ fontFamily: this.theme.text.fontFamily,
184
196
  };
185
197
  }
186
198
  /** Export the mounted view as PNG, optionally with radial scales and a trace legend. */
@@ -290,15 +302,31 @@ export class Smith {
290
302
  return;
291
303
  }
292
304
  validateTraceOptions(options) {
305
+ OptionsValidation.object(options, 'Trace', [
306
+ 'mode',
307
+ 'line',
308
+ 'point',
309
+ 'name',
310
+ 'color',
311
+ 'visible',
312
+ ]);
313
+ if (options.line !== undefined) {
314
+ OptionsValidation.object(options.line, 'Trace line', ['width', 'tolerancePx']);
315
+ }
316
+ if (options.point !== undefined) {
317
+ OptionsValidation.object(options.point, 'Trace point', ['radius']);
318
+ }
293
319
  if (options.mode !== undefined && !['points', 'line', 'both'].includes(options.mode)) {
294
320
  throw new TypeError('Trace mode must be points, line, or both.');
295
321
  }
296
- if (options.lineTolerancePx !== undefined &&
297
- (!Number.isFinite(options.lineTolerancePx) || options.lineTolerancePx < 0)) {
322
+ if (options.line?.tolerancePx !== undefined &&
323
+ (!Number.isFinite(options.line.tolerancePx) || options.line.tolerancePx < 0)) {
298
324
  throw new RangeError('Line tolerance must be finite and non-negative.');
299
325
  }
300
- for (const key of ['lineWidth', 'pointRadius']) {
301
- const value = options[key];
326
+ for (const [key, value] of [
327
+ ['line.width', options.line?.width],
328
+ ['point.radius', options.point?.radius],
329
+ ]) {
302
330
  if (value !== undefined && (!Number.isFinite(value) || value <= 0)) {
303
331
  throw new RangeError(`${key} must be positive and finite.`);
304
332
  }
@@ -442,7 +470,7 @@ export class Smith {
442
470
  this.data = [];
443
471
  }
444
472
  createSmithData(values, dataset, options) {
445
- const color = this.theme.traceColors[dataset % this.theme.traceColors.length];
473
+ const color = this.theme.traces.colors[dataset % this.theme.traces.colors.length];
446
474
  const data = this.renderer.createTrace(values, color, options, (marker, dragging) => {
447
475
  this.markerDragChanged(marker, dragging);
448
476
  const snapshot = this.getMarker(this.markerId(marker));
@@ -3,4 +3,5 @@ import type { SmithTheme } from './types.js';
3
3
  export declare class SvgTheme {
4
4
  private constructor();
5
5
  static apply(element: HTMLElement | SVGElement, theme: SmithTheme): void;
6
+ private static tokens;
6
7
  }
@@ -2,20 +2,21 @@
2
2
  export class SvgTheme {
3
3
  constructor() { }
4
4
  static apply(element, theme) {
5
- for (const [section, value] of Object.entries(theme)) {
5
+ SvgTheme.tokens(element, theme, '--smithkit');
6
+ element.style.backgroundColor = theme.background;
7
+ }
8
+ static tokens(element, values, prefix) {
9
+ for (const [key, value] of Object.entries(values)) {
6
10
  if (Array.isArray(value)) {
7
11
  continue;
8
12
  }
9
13
  if (typeof value === 'object') {
10
- for (const [key, entry] of Object.entries(value)) {
11
- const suffix = key.toLowerCase().endsWith('fontsize') ? 'px' : '';
12
- element.style.setProperty(`--smithkit-${section}-${key}`, String(entry) + suffix);
13
- }
14
+ SvgTheme.tokens(element, value, `${prefix}-${key}`);
14
15
  }
15
16
  else {
16
- element.style.setProperty(`--smithkit-${section}`, value);
17
+ const suffix = key === 'fontSize' ? 'px' : '';
18
+ element.style.setProperty(`${prefix}-${key}`, String(value) + suffix);
17
19
  }
18
20
  }
19
- element.style.backgroundColor = theme.background;
20
21
  }
21
22
  }
@@ -18,66 +18,63 @@ export class Theme {
18
18
  const dark = name === 'dark';
19
19
  const theme = {
20
20
  background: dark ? '#0f172a' : 'transparent',
21
- fontFamily: 'Verdana, sans-serif',
21
+ text: { fontFamily: 'Verdana, sans-serif' },
22
22
  grid: {
23
- stroke: dark ? '#94a3b8' : '#64748b',
24
- textColor: dark ? '#e2e8f0' : '#111827',
25
- majorWidth: 1,
26
- minorWidth: 0.6,
27
- fontSize: 7,
23
+ line: { color: dark ? '#94a3b8' : '#64748b', majorWidth: 1, minorWidth: 0.6 },
24
+ text: { color: dark ? '#e2e8f0' : '#111827', fontSize: 7 },
25
+ },
26
+ boundary: { color: dark ? '#cbd5e1' : '#334155', width: 1 },
27
+ circles: {
28
+ q: { color: dark ? '#93c5fd' : 'blue', width: 1 },
29
+ vswr: { color: dark ? '#fbbf24' : 'orange', width: 1 },
28
30
  },
29
- boundary: { stroke: dark ? '#cbd5e1' : '#334155', width: 1 },
30
- circles: { q: dark ? '#93c5fd' : 'blue', vswr: dark ? '#fbbf24' : 'orange', width: 1 },
31
31
  scales: {
32
- stroke: dark ? '#94a3b8' : '#64748b',
33
- boundaryColor: dark ? '#cbd5e1' : '#334155',
34
- textColor: dark ? '#e2e8f0' : '#334155',
35
- valueColor: dark ? '#fca5a5' : '#b42318',
36
- indicatorColor: dark ? '#f87171' : '#dc2626',
37
- indicatorOutline: dark ? '#0f172a' : 'white',
38
- fontSize: 10,
39
- titleFontSize: 12,
40
- valueFontSize: 11,
41
- peripheralFontSize: 10.5,
32
+ line: { color: dark ? '#94a3b8' : '#64748b' },
33
+ boundary: { color: dark ? '#cbd5e1' : '#334155' },
34
+ text: { color: dark ? '#e2e8f0' : '#334155', fontSize: 10 },
35
+ value: { color: dark ? '#fca5a5' : '#b42318', fontSize: 11 },
36
+ indicator: { color: dark ? '#f87171' : '#dc2626', outline: dark ? '#0f172a' : 'white' },
37
+ title: { fontSize: 12 },
38
+ peripheral: { fontSize: 10.5 },
42
39
  },
43
40
  cursor: {
44
- pointColor: dark ? '#fca5a5' : 'red',
45
- impedanceColor: dark ? '#fca5a5' : 'red',
46
- admittanceColor: dark ? '#86efac' : 'green',
47
- pointSize: 5,
48
- lineWidth: 1,
41
+ point: { color: dark ? '#fca5a5' : 'red', size: 5 },
42
+ impedance: { color: dark ? '#fca5a5' : 'red' },
43
+ admittance: { color: dark ? '#86efac' : 'green' },
44
+ line: { width: 1 },
49
45
  },
50
46
  marker: {
51
- outlineColor: dark ? '#e2e8f0' : 'gray',
52
- textColor: 'white',
53
- focusColor: dark ? '#93c5fd' : '#1d4ed8',
54
- focusHaloColor: dark ? '#0f172a' : 'white',
47
+ outline: { color: dark ? '#e2e8f0' : 'gray' },
48
+ text: { color: 'white' },
49
+ focus: { color: dark ? '#93c5fd' : '#1d4ed8', halo: dark ? '#0f172a' : 'white' },
50
+ },
51
+ traces: {
52
+ colors: dark
53
+ ? [
54
+ '#fb923c',
55
+ '#4ade80',
56
+ '#f87171',
57
+ '#c084fc',
58
+ '#d6a681',
59
+ '#f472b6',
60
+ '#cbd5e1',
61
+ '#d4d45c',
62
+ '#22d3ee',
63
+ '#60a5fa',
64
+ ]
65
+ : [
66
+ '#ff7f0e',
67
+ '#2ca02c',
68
+ '#d62728',
69
+ '#9467bd',
70
+ '#8c564b',
71
+ '#e377c2',
72
+ '#7f7f7f',
73
+ '#bcbd22',
74
+ '#17becf',
75
+ '#1f77b4',
76
+ ],
55
77
  },
56
- traceColors: dark
57
- ? [
58
- '#fb923c',
59
- '#4ade80',
60
- '#f87171',
61
- '#c084fc',
62
- '#d6a681',
63
- '#f472b6',
64
- '#cbd5e1',
65
- '#d4d45c',
66
- '#22d3ee',
67
- '#60a5fa',
68
- ]
69
- : [
70
- '#ff7f0e',
71
- '#2ca02c',
72
- '#d62728',
73
- '#9467bd',
74
- '#8c564b',
75
- '#e377c2',
76
- '#7f7f7f',
77
- '#bcbd22',
78
- '#17becf',
79
- '#1f77b4',
80
- ],
81
78
  };
82
79
  if (appearance.overrides !== undefined) {
83
80
  Theme.merge(theme, appearance.overrides);
@@ -1,52 +1,96 @@
1
1
  /** Resolved appearance shared by charts and independent scales. Lengths are positive. */
2
2
  export interface SmithTheme {
3
3
  background: string;
4
- fontFamily: string;
4
+ text: {
5
+ fontFamily: string;
6
+ };
5
7
  grid: {
6
- stroke: string;
7
- textColor: string;
8
- majorWidth: number;
9
- minorWidth: number;
10
- fontSize: number;
8
+ line: {
9
+ color: string;
10
+ majorWidth: number;
11
+ minorWidth: number;
12
+ };
13
+ text: {
14
+ color: string;
15
+ fontSize: number;
16
+ };
11
17
  };
12
18
  boundary: {
13
- stroke: string;
19
+ color: string;
14
20
  width: number;
15
21
  };
16
22
  circles: {
17
- q: string;
18
- vswr: string;
19
- width: number;
23
+ q: {
24
+ color: string;
25
+ width: number;
26
+ };
27
+ vswr: {
28
+ color: string;
29
+ width: number;
30
+ };
20
31
  };
21
32
  scales: {
22
- stroke: string;
23
- boundaryColor: string;
24
- textColor: string;
25
- valueColor: string;
26
- indicatorColor: string;
27
- indicatorOutline: string;
28
- fontSize: number;
29
- titleFontSize: number;
30
- valueFontSize: number;
31
- peripheralFontSize: number;
33
+ line: {
34
+ color: string;
35
+ };
36
+ boundary: {
37
+ color: string;
38
+ };
39
+ text: {
40
+ color: string;
41
+ fontSize: number;
42
+ };
43
+ title: {
44
+ fontSize: number;
45
+ };
46
+ value: {
47
+ color: string;
48
+ fontSize: number;
49
+ };
50
+ indicator: {
51
+ color: string;
52
+ outline: string;
53
+ };
54
+ peripheral: {
55
+ fontSize: number;
56
+ };
32
57
  };
33
58
  cursor: {
34
- pointColor: string;
35
- impedanceColor: string;
36
- admittanceColor: string;
37
- pointSize: number;
38
- lineWidth: number;
59
+ point: {
60
+ color: string;
61
+ size: number;
62
+ };
63
+ impedance: {
64
+ color: string;
65
+ };
66
+ admittance: {
67
+ color: string;
68
+ };
69
+ line: {
70
+ width: number;
71
+ };
39
72
  };
40
73
  marker: {
41
- outlineColor: string;
42
- textColor: string;
43
- focusColor: string;
44
- focusHaloColor: string;
74
+ outline: {
75
+ color: string;
76
+ };
77
+ text: {
78
+ color: string;
79
+ };
80
+ focus: {
81
+ color: string;
82
+ halo: string;
83
+ };
84
+ };
85
+ traces: {
86
+ colors: readonly string[];
45
87
  };
46
- traceColors: readonly string[];
47
88
  }
89
+ /** Each visual group can be overridden independently, down to individual properties. */
48
90
  export type SmithThemeOverrides = {
49
- [K in keyof SmithTheme]?: SmithTheme[K] extends readonly string[] ? readonly string[] : SmithTheme[K] extends object ? Partial<SmithTheme[K]> : SmithTheme[K];
91
+ [K in keyof SmithTheme]?: SmithTheme[K] extends string ? string : {
92
+ [P in keyof SmithTheme[K]]?: SmithTheme[K][P] extends readonly string[] ? readonly string[] : SmithTheme[K][P] extends object ? Partial<SmithTheme[K][P]> : SmithTheme[K][P];
93
+ };
50
94
  };
51
95
  /** Each application replaces the previous appearance, starting from the named preset. */
52
96
  export interface SmithAppearance {
@@ -1,6 +1,6 @@
1
1
  import type { ConstQCircles } from './ConstQCircles.js';
2
2
  import type { ConstSwrCircles } from './ConstSwrCircles.js';
3
- import type { CircleLayer, CircleStyle } from '../layers.js';
3
+ import type { CircleLayer, CircleStyleOptions } from '../layers.js';
4
4
  import { LayerControl } from './LayerControl.js';
5
5
  /** Exposes Q/VSWR circle controls without exposing the SVG renderer. */
6
6
  export declare class CircleLayerControl extends LayerControl implements CircleLayer {
@@ -8,7 +8,7 @@ export declare class CircleLayerControl extends LayerControl implements CircleLa
8
8
  private readonly minimum;
9
9
  constructor(layer: ConstQCircles | ConstSwrCircles, minimum: number, assertAlive: () => void);
10
10
  setVisible(visible: boolean): void;
11
- setStyle(style: Partial<CircleStyle>): void;
11
+ setStyle(style: CircleStyleOptions): void;
12
12
  setValues(values: readonly number[]): void;
13
13
  addValue(value: number): void;
14
14
  removeValue(value: number): void;
@@ -17,11 +17,11 @@ export class CircleLayerControl extends LayerControl {
17
17
  setStyle(style) {
18
18
  this.assertAlive();
19
19
  OptionsValidation.circleStyle(style);
20
- if (style.stroke !== undefined) {
21
- this.layer.Stroke = style.stroke;
20
+ if (style.line?.color !== undefined) {
21
+ this.layer.Stroke = style.line.color;
22
22
  }
23
- if (style.strokeWidth !== undefined) {
24
- this.layer.StrokeWidth = String(style.strokeWidth);
23
+ if (style.line?.width !== undefined) {
24
+ this.layer.StrokeWidth = String(style.line.width);
25
25
  }
26
26
  }
27
27
  setValues(values) {
@@ -94,12 +94,12 @@ export class ConstCircles {
94
94
  defaultDrawingOptions() {
95
95
  return {
96
96
  // Keep curved grid strokes visible at normal browser zoom and low pixel density.
97
- stroke: 'var(--smithkit-grid-stroke)',
98
- majorWidth: 'var(--smithkit-grid-majorWidth)',
99
- minorWidth: 'var(--smithkit-grid-minorWidth)',
100
- textColor: 'var(--smithkit-grid-textColor)',
101
- textFontFamily: 'var(--smithkit-fontFamily)',
102
- textFontSize: 'var(--smithkit-grid-fontSize)',
97
+ stroke: 'var(--smithkit-grid-line-color)',
98
+ majorWidth: 'var(--smithkit-grid-line-majorWidth)',
99
+ minorWidth: 'var(--smithkit-grid-line-minorWidth)',
100
+ textColor: 'var(--smithkit-grid-text-color)',
101
+ textFontFamily: 'var(--smithkit-text-fontFamily)',
102
+ textFontSize: 'var(--smithkit-grid-text-fontSize)',
103
103
  };
104
104
  }
105
105
  scaleArc(scaler, d) {
@@ -28,7 +28,10 @@ export class ConstQCircles {
28
28
  this.container.append(a2);
29
29
  }
30
30
  getDefaultDrawOptions() {
31
- return { stroke: 'var(--smithkit-circles-q)', strokeWidth: 'var(--smithkit-circles-width)' };
31
+ return {
32
+ stroke: 'var(--smithkit-circles-q-color)',
33
+ strokeWidth: 'var(--smithkit-circles-q-width)',
34
+ };
32
35
  }
33
36
  setDrawOptions(opts) {
34
37
  this.opts = opts;
@@ -27,7 +27,10 @@ export class ConstSwrCircles {
27
27
  this.container.append(circle);
28
28
  }
29
29
  getDefaultDrawOptions() {
30
- return { stroke: 'var(--smithkit-circles-vswr)', strokeWidth: 'var(--smithkit-circles-width)' };
30
+ return {
31
+ stroke: 'var(--smithkit-circles-vswr-color)',
32
+ strokeWidth: 'var(--smithkit-circles-vswr-width)',
33
+ };
31
34
  }
32
35
  setDrawOptions(opts) {
33
36
  this.opts = opts;
@@ -1,5 +1,5 @@
1
1
  import type { SmithGridLayer } from './SmithGridLayer.js';
2
- import type { GridDetail, GridLayer, GridStyle } from '../layers.js';
2
+ import type { GridDetail, GridLayer, GridStyleOptions } from '../layers.js';
3
3
  import { LayerControl } from './LayerControl.js';
4
4
  /** Exposes grid controls without exposing the SVG renderer. */
5
5
  export declare class GridLayerControl extends LayerControl implements GridLayer {
@@ -9,5 +9,5 @@ export declare class GridLayerControl extends LayerControl implements GridLayer
9
9
  setVisible(visible: boolean): void;
10
10
  setLabelsVisible(visible: boolean): void;
11
11
  setDetail(detail: GridDetail): void;
12
- setStyle(style: Partial<GridStyle>): void;
12
+ setStyle(style: GridStyleOptions): void;
13
13
  }
@@ -30,18 +30,17 @@ export class GridLayerControl extends LayerControl {
30
30
  setStyle(style) {
31
31
  this.assertAlive();
32
32
  OptionsValidation.gridStyle(style);
33
- const properties = {
34
- stroke: 'Stroke',
35
- majorWidth: 'MajorWidth',
36
- minorWidth: 'MinorWidth',
37
- textColor: 'TextColor',
38
- textFontFamily: 'TextFontFamily',
39
- textFontSize: 'TextFontSize',
40
- };
41
- for (const key of Object.keys(properties)) {
42
- const value = style[key];
33
+ const properties = [
34
+ ['Stroke', style.line?.color],
35
+ ['MajorWidth', style.line?.majorWidth],
36
+ ['MinorWidth', style.line?.minorWidth],
37
+ ['TextColor', style.text?.color],
38
+ ['TextFontFamily', style.text?.fontFamily],
39
+ ['TextFontSize', style.text?.fontSize],
40
+ ];
41
+ for (const [property, value] of properties) {
43
42
  if (value !== undefined) {
44
- this.layer[properties[key]] = String(value);
43
+ this.layer[property] = String(value);
45
44
  }
46
45
  }
47
46
  this.changed();
@@ -31,7 +31,9 @@ export class SmithGridLayer extends ConstCircles {
31
31
  const label = GridGeometry.label(kind, tick.definition);
32
32
  const text = new SmithText(this.scaler.point(label.point), label.text, {
33
33
  rotate: label.rotate,
34
- dx: this.scaler.r(label.dx).toString(),
34
+ // Keep the zero clear of the opposite grid's high-value labels even
35
+ // when minimum font sizing or browser font metrics enlarge it.
36
+ dx: real && tick.definition.point.r === 0 ? '0.9em' : this.scaler.r(label.dx).toString(),
35
37
  dy: this.scaler.r(label.dy).toString(),
36
38
  textAnchor: label.textAnchor,
37
39
  dominantBaseline: label.dominantBaseline,
@@ -6,10 +6,10 @@ export { Touchstone } from './io/Touchstone.js';
6
6
  export type { TouchstoneData, TouchstoneParseOptions, TouchstoneWriteOptions } from './io/types.js';
7
7
  export { SmithScales } from './scales/SmithScales.js';
8
8
  export { MarkerMeasurements } from './MarkerMeasurements.js';
9
- export type { TraceOptions, TraceUpdateOptions, MarkerSelectionStrategy, TraceStyle, TraceRenderMode, TraceInfo, MarkerInfo, MarkerSnapshot, MarkerComparison, } from './measurements.js';
9
+ export type { TraceOptions, TraceUpdateOptions, MarkerSelectionStrategy, TraceStyle, TraceStyleOptions, TraceRenderMode, TraceInfo, MarkerInfo, MarkerSnapshot, MarkerComparison, } from './measurements.js';
10
10
  export { RfCalculations } from './rf/RfCalculations.js';
11
11
  export type { SmithReading } from './rf/RfCalculations.js';
12
- export type { GridStyle, CircleStyle, GridLayer, GridDetail, CircleLayer, ChartLayers, PeripheralScales, } from './layers.js';
12
+ export type { GridStyle, GridStyleOptions, CircleStyle, CircleStyleOptions, GridLayer, GridDetail, CircleLayer, ChartLayers, PeripheralScales, } from './layers.js';
13
13
  export { SmithFormatter } from './SmithFormatter.js';
14
14
  export type { ReactiveComponent } from './rf/RfCalculations.js';
15
15
  export type { SmithAppearance, SmithTheme, SmithThemeOverrides } from './appearance/types.js';