smithkit 0.1.1 → 0.3.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 (146) hide show
  1. package/README.md +291 -42
  2. package/dist/lib/MarkerMeasurements.d.ts +6 -0
  3. package/dist/lib/MarkerMeasurements.js +22 -0
  4. package/dist/lib/Smith.d.ts +18 -35
  5. package/dist/lib/Smith.js +107 -275
  6. package/dist/lib/SmithFormatter.d.ts +10 -0
  7. package/dist/lib/SmithFormatter.js +19 -0
  8. package/dist/lib/appearance/SvgTheme.d.ts +6 -0
  9. package/dist/lib/appearance/SvgTheme.js +21 -0
  10. package/dist/lib/appearance/Theme.d.ts +8 -0
  11. package/dist/lib/appearance/Theme.js +120 -0
  12. package/dist/lib/appearance/types.d.ts +55 -0
  13. package/dist/lib/grid/CircleLayerControl.d.ts +15 -0
  14. package/dist/lib/grid/CircleLayerControl.js +40 -0
  15. package/dist/lib/{draw → grid}/ConstCircles.d.ts +4 -9
  16. package/dist/lib/{draw → grid}/ConstCircles.js +8 -22
  17. package/dist/lib/{draw → grid}/ConstQCircles.d.ts +2 -2
  18. package/dist/lib/{draw → grid}/ConstQCircles.js +4 -4
  19. package/dist/lib/{draw → grid}/ConstSwrCircles.d.ts +2 -2
  20. package/dist/lib/{draw → grid}/ConstSwrCircles.js +4 -4
  21. package/dist/lib/grid/GridDefinitions.d.ts +18 -0
  22. package/dist/lib/grid/GridDefinitions.js +167 -0
  23. package/dist/lib/grid/GridGeometry.d.ts +26 -0
  24. package/dist/lib/grid/GridGeometry.js +58 -0
  25. package/dist/lib/grid/GridLabels.d.ts +8 -0
  26. package/dist/lib/grid/GridLabels.js +45 -0
  27. package/dist/lib/grid/GridLayerControl.d.ts +13 -0
  28. package/dist/lib/grid/GridLayerControl.js +48 -0
  29. package/dist/lib/grid/LayerControl.d.ts +6 -0
  30. package/dist/lib/grid/LayerControl.js +16 -0
  31. package/dist/lib/grid/SmithGridLayer.d.ts +26 -0
  32. package/dist/lib/grid/SmithGridLayer.js +95 -0
  33. package/dist/lib/grid/types.d.ts +1 -1
  34. package/dist/lib/index.d.ts +11 -11
  35. package/dist/lib/index.js +5 -7
  36. package/dist/lib/{draw → interaction}/SmithCursor.d.ts +3 -20
  37. package/dist/lib/{draw → interaction}/SmithCursor.js +12 -20
  38. package/dist/lib/io/Touchstone.d.ts +10 -0
  39. package/dist/lib/io/Touchstone.js +75 -0
  40. package/dist/lib/layers.d.ts +7 -9
  41. package/dist/lib/layers.js +1 -73
  42. package/dist/lib/{complex → math}/Complex.d.ts +1 -0
  43. package/dist/lib/{complex → math}/Complex.js +1 -1
  44. package/dist/lib/math/geometry.d.ts +14 -0
  45. package/dist/lib/measurements.d.ts +2 -4
  46. package/dist/lib/measurements.js +1 -19
  47. package/dist/lib/rendering/SvgChartRenderer.d.ts +66 -0
  48. package/dist/lib/rendering/SvgChartRenderer.js +342 -0
  49. package/dist/lib/rf/RfCalculations.d.ts +65 -0
  50. package/dist/lib/rf/RfCalculations.js +161 -0
  51. package/dist/lib/{SmithConstantCircle.d.ts → rf/SmithConstantCircle.d.ts} +2 -3
  52. package/dist/lib/{SmithConstantCircle.js → rf/SmithConstantCircle.js} +3 -4
  53. package/dist/lib/scales/PeripheralScaleDefinitions.d.ts +16 -0
  54. package/dist/lib/scales/PeripheralScaleDefinitions.js +54 -0
  55. package/dist/lib/scales/RadialScaleDefinitions.d.ts +15 -0
  56. package/dist/lib/scales/RadialScaleDefinitions.js +112 -0
  57. package/dist/lib/scales/SmithPeripheralScales.d.ts +4 -2
  58. package/dist/lib/scales/SmithPeripheralScales.js +55 -35
  59. package/dist/lib/scales/SmithScales.d.ts +11 -2
  60. package/dist/lib/scales/SmithScales.js +78 -38
  61. package/dist/lib/svg/ImageExporter.d.ts +18 -0
  62. package/dist/lib/svg/ImageExporter.js +211 -0
  63. package/dist/lib/svg/LabelLayout.d.ts +17 -0
  64. package/dist/lib/svg/LabelLayout.js +145 -0
  65. package/dist/lib/svg/MarkerLegend.d.ts +12 -0
  66. package/dist/lib/svg/MarkerLegend.js +63 -0
  67. package/dist/lib/{draw → svg}/SmithArc.d.ts +1 -1
  68. package/dist/lib/{draw → svg}/SmithCircle.d.ts +1 -1
  69. package/dist/lib/{draw → svg}/SmithLine.d.ts +1 -1
  70. package/dist/lib/{draw → svg}/SmithScaler.d.ts +1 -4
  71. package/dist/lib/{draw → svg}/SmithText.d.ts +1 -1
  72. package/dist/lib/svg/SvgExporter.d.ts +19 -0
  73. package/dist/lib/svg/SvgExporter.js +182 -0
  74. package/dist/lib/svg/export.d.ts +36 -0
  75. package/dist/lib/{draw → traces}/SmithData.d.ts +24 -35
  76. package/dist/lib/traces/SmithData.js +195 -0
  77. package/dist/lib/{draw → traces}/SmithMarker.d.ts +14 -3
  78. package/dist/lib/traces/SmithMarker.js +240 -0
  79. package/dist/lib/traces/TraceModel.d.ts +31 -0
  80. package/dist/lib/traces/TraceModel.js +123 -0
  81. package/dist/lib/traces/TraceRenderer.d.ts +33 -0
  82. package/dist/lib/traces/TraceRenderer.js +152 -0
  83. package/package.json +4 -1
  84. package/dist/lib/SmithArcsDefs.d.ts +0 -10
  85. package/dist/lib/SmithArcsDefs.js +0 -10
  86. package/dist/lib/components.d.ts +0 -14
  87. package/dist/lib/components.js +0 -26
  88. package/dist/lib/draw/SmithData.js +0 -366
  89. package/dist/lib/draw/SmithGridLayer.d.ts +0 -19
  90. package/dist/lib/draw/SmithGridLayer.js +0 -48
  91. package/dist/lib/draw/SmithMarker.js +0 -122
  92. package/dist/lib/formatting.d.ts +0 -7
  93. package/dist/lib/formatting.js +0 -16
  94. package/dist/lib/grid/definitions.d.ts +0 -3
  95. package/dist/lib/grid/definitions.js +0 -123
  96. package/dist/lib/grid/geometry.d.ts +0 -20
  97. package/dist/lib/grid/geometry.js +0 -55
  98. package/dist/lib/grid/labels.d.ts +0 -3
  99. package/dist/lib/grid/labels.js +0 -41
  100. package/dist/lib/io/touchstone.d.ts +0 -7
  101. package/dist/lib/io/touchstone.js +0 -72
  102. package/dist/lib/math/complexRatio.d.ts +0 -3
  103. package/dist/lib/math/complexRatio.js +0 -30
  104. package/dist/lib/renormalization.d.ts +0 -10
  105. package/dist/lib/renormalization.js +0 -62
  106. package/dist/lib/rf.d.ts +0 -35
  107. package/dist/lib/rf.js +0 -74
  108. package/dist/lib/scales/peripheralScales.d.ts +0 -12
  109. package/dist/lib/scales/peripheralScales.js +0 -49
  110. package/dist/lib/scales/radialScales.d.ts +0 -12
  111. package/dist/lib/scales/radialScales.js +0 -109
  112. package/dist/lib/shapes/Arc.d.ts +0 -6
  113. package/dist/lib/shapes/Circle.d.ts +0 -5
  114. package/dist/lib/shapes/Line.d.ts +0 -5
  115. package/dist/lib/shapes/Point.d.ts +0 -1
  116. package/dist/lib/shapes/Point.js +0 -1
  117. /package/dist/lib/{draw/SmithDrawOptions.js → appearance/types.js} +0 -0
  118. /package/dist/lib/{draw → grid}/ConstConductance.d.ts +0 -0
  119. /package/dist/lib/{draw → grid}/ConstConductance.js +0 -0
  120. /package/dist/lib/{draw → grid}/ConstReactance.d.ts +0 -0
  121. /package/dist/lib/{draw → grid}/ConstReactance.js +0 -0
  122. /package/dist/lib/{draw → grid}/ConstResistance.d.ts +0 -0
  123. /package/dist/lib/{draw → grid}/ConstResistance.js +0 -0
  124. /package/dist/lib/{draw → grid}/ConstSusceptance.d.ts +0 -0
  125. /package/dist/lib/{draw → grid}/ConstSusceptance.js +0 -0
  126. /package/dist/lib/{arcs → grid}/Tick.d.ts +0 -0
  127. /package/dist/lib/{arcs → grid}/Tick.js +0 -0
  128. /package/dist/lib/{draw → interaction}/MouseGesture.d.ts +0 -0
  129. /package/dist/lib/{draw → interaction}/MouseGesture.js +0 -0
  130. /package/dist/lib/{shapes/Arc.js → math/geometry.js} +0 -0
  131. /package/dist/lib/{draw → svg}/SmithArc.js +0 -0
  132. /package/dist/lib/{draw → svg}/SmithCircle.js +0 -0
  133. /package/dist/lib/{draw → svg}/SmithDrawOptions.d.ts +0 -0
  134. /package/dist/lib/{shapes/Circle.js → svg/SmithDrawOptions.js} +0 -0
  135. /package/dist/lib/{draw → svg}/SmithGroup.d.ts +0 -0
  136. /package/dist/lib/{draw → svg}/SmithGroup.js +0 -0
  137. /package/dist/lib/{draw → svg}/SmithLine.js +0 -0
  138. /package/dist/lib/{draw → svg}/SmithPath.d.ts +0 -0
  139. /package/dist/lib/{draw → svg}/SmithPath.js +0 -0
  140. /package/dist/lib/{draw → svg}/SmithScaler.js +0 -0
  141. /package/dist/lib/{draw → svg}/SmithShape.d.ts +0 -0
  142. /package/dist/lib/{draw → svg}/SmithShape.js +0 -0
  143. /package/dist/lib/{draw → svg}/SmithSvg.d.ts +0 -0
  144. /package/dist/lib/{draw → svg}/SmithSvg.js +0 -0
  145. /package/dist/lib/{draw → svg}/SmithText.js +0 -0
  146. /package/dist/lib/{shapes/Line.js → svg/export.js} +0 -0
@@ -0,0 +1,120 @@
1
+ import { color } from 'd3';
2
+ /** Resolve and validate a detached theme before touching any chart state or DOM. */
3
+ export class Theme {
4
+ constructor() { }
5
+ static resolve(appearance = {}) {
6
+ if (!appearance || typeof appearance !== 'object' || Array.isArray(appearance)) {
7
+ throw new TypeError('Appearance must be an object.');
8
+ }
9
+ const name = appearance.theme === undefined ? 'light' : appearance.theme;
10
+ if (name !== 'light' && name !== 'dark') {
11
+ throw new TypeError('Theme must be light or dark.');
12
+ }
13
+ const dark = name === 'dark';
14
+ const theme = {
15
+ background: dark ? '#0f172a' : 'transparent',
16
+ fontFamily: 'Verdana, sans-serif',
17
+ grid: {
18
+ stroke: dark ? '#94a3b8' : '#64748b',
19
+ textColor: dark ? '#e2e8f0' : '#111827',
20
+ majorWidth: 1,
21
+ minorWidth: 0.6,
22
+ fontSize: 7,
23
+ },
24
+ boundary: { stroke: dark ? '#cbd5e1' : '#334155', width: 1 },
25
+ circles: { q: dark ? '#93c5fd' : 'blue', vswr: dark ? '#fbbf24' : 'orange', width: 1 },
26
+ scales: {
27
+ stroke: dark ? '#94a3b8' : '#64748b',
28
+ boundaryColor: dark ? '#cbd5e1' : '#334155',
29
+ textColor: dark ? '#e2e8f0' : '#334155',
30
+ valueColor: dark ? '#fca5a5' : '#b42318',
31
+ indicatorColor: dark ? '#f87171' : '#dc2626',
32
+ indicatorOutline: dark ? '#0f172a' : 'white',
33
+ fontSize: 10,
34
+ titleFontSize: 12,
35
+ valueFontSize: 11,
36
+ peripheralFontSize: 10.5,
37
+ },
38
+ cursor: {
39
+ pointColor: dark ? '#fca5a5' : 'red',
40
+ impedanceColor: dark ? '#fca5a5' : 'red',
41
+ admittanceColor: dark ? '#86efac' : 'green',
42
+ pointSize: 5,
43
+ lineWidth: 1,
44
+ },
45
+ marker: {
46
+ outlineColor: dark ? '#e2e8f0' : 'gray',
47
+ textColor: 'white',
48
+ focusColor: dark ? '#93c5fd' : '#1d4ed8',
49
+ focusHaloColor: dark ? '#0f172a' : 'white',
50
+ },
51
+ traceColors: dark
52
+ ? [
53
+ '#fb923c',
54
+ '#4ade80',
55
+ '#f87171',
56
+ '#c084fc',
57
+ '#d6a681',
58
+ '#f472b6',
59
+ '#cbd5e1',
60
+ '#d4d45c',
61
+ '#22d3ee',
62
+ '#60a5fa',
63
+ ]
64
+ : [
65
+ '#ff7f0e',
66
+ '#2ca02c',
67
+ '#d62728',
68
+ '#9467bd',
69
+ '#8c564b',
70
+ '#e377c2',
71
+ '#7f7f7f',
72
+ '#bcbd22',
73
+ '#17becf',
74
+ '#1f77b4',
75
+ ],
76
+ };
77
+ if (appearance.overrides !== undefined) {
78
+ Theme.merge(theme, appearance.overrides);
79
+ }
80
+ return theme;
81
+ }
82
+ static merge(target, source, path = 'appearance') {
83
+ if (!source || typeof source !== 'object' || Array.isArray(source)) {
84
+ throw new TypeError(`${path} overrides must be an object.`);
85
+ }
86
+ for (const [key, value] of Object.entries(source)) {
87
+ if (!Object.hasOwn(target, key)) {
88
+ throw new TypeError(`Unknown appearance setting: ${path}.${key}.`);
89
+ }
90
+ if (value === undefined) {
91
+ continue;
92
+ }
93
+ const previous = target[key];
94
+ if (Array.isArray(previous)) {
95
+ if (!Array.isArray(value) || value.length === 0 || !value.every(Theme.isColor)) {
96
+ throw new TypeError('Trace colors must be a non-empty array of solid CSS colors.');
97
+ }
98
+ target[key] = [...value];
99
+ }
100
+ else if (typeof previous === 'object') {
101
+ Theme.merge(previous, value, `${path}.${key}`);
102
+ }
103
+ else if (typeof previous === 'number') {
104
+ if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) {
105
+ throw new RangeError(`${path}.${key} must be positive and finite.`);
106
+ }
107
+ target[key] = value;
108
+ }
109
+ else {
110
+ if (key === 'fontFamily' ? typeof value !== 'string' || !value.trim() : !Theme.isColor(value)) {
111
+ throw new TypeError(`${path}.${key} must be ${key === 'fontFamily' ? 'a non-empty font family' : 'a solid CSS color'}.`);
112
+ }
113
+ target[key] = value;
114
+ }
115
+ }
116
+ }
117
+ static isColor(value) {
118
+ return typeof value === 'string' && color(value) !== null;
119
+ }
120
+ }
@@ -0,0 +1,55 @@
1
+ /** Resolved appearance shared by charts and independent scales. Lengths are positive. */
2
+ export interface SmithTheme {
3
+ background: string;
4
+ fontFamily: string;
5
+ grid: {
6
+ stroke: string;
7
+ textColor: string;
8
+ majorWidth: number;
9
+ minorWidth: number;
10
+ fontSize: number;
11
+ };
12
+ boundary: {
13
+ stroke: string;
14
+ width: number;
15
+ };
16
+ circles: {
17
+ q: string;
18
+ vswr: string;
19
+ width: number;
20
+ };
21
+ 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;
32
+ };
33
+ cursor: {
34
+ pointColor: string;
35
+ impedanceColor: string;
36
+ admittanceColor: string;
37
+ pointSize: number;
38
+ lineWidth: number;
39
+ };
40
+ marker: {
41
+ outlineColor: string;
42
+ textColor: string;
43
+ focusColor: string;
44
+ focusHaloColor: string;
45
+ };
46
+ traceColors: readonly string[];
47
+ }
48
+ export type SmithThemeOverrides = {
49
+ [K in keyof SmithTheme]?: SmithTheme[K] extends readonly string[] ? readonly string[] : SmithTheme[K] extends object ? Partial<SmithTheme[K]> : SmithTheme[K];
50
+ };
51
+ /** Each application replaces the previous appearance, starting from the named preset. */
52
+ export interface SmithAppearance {
53
+ theme?: 'light' | 'dark';
54
+ overrides?: SmithThemeOverrides;
55
+ }
@@ -0,0 +1,15 @@
1
+ import type { ConstQCircles } from './ConstQCircles.js';
2
+ import type { ConstSwrCircles } from './ConstSwrCircles.js';
3
+ import type { CircleLayer, CircleStyle } from '../layers.js';
4
+ import { LayerControl } from './LayerControl.js';
5
+ /** Exposes Q/VSWR circle controls without exposing the SVG renderer. */
6
+ export declare class CircleLayerControl extends LayerControl implements CircleLayer {
7
+ private readonly layer;
8
+ private readonly minimum;
9
+ constructor(layer: ConstQCircles | ConstSwrCircles, minimum: number, assertAlive: () => void);
10
+ setVisible(visible: boolean): void;
11
+ setStyle(style: Partial<CircleStyle>): void;
12
+ addValue(value: number): void;
13
+ removeValue(value: number): void;
14
+ private validateValue;
15
+ }
@@ -0,0 +1,40 @@
1
+ import { LayerControl } from './LayerControl.js';
2
+ /** Exposes Q/VSWR circle controls without exposing the SVG renderer. */
3
+ export class CircleLayerControl extends LayerControl {
4
+ layer;
5
+ minimum;
6
+ constructor(layer, minimum, assertAlive) {
7
+ super(assertAlive);
8
+ this.layer = layer;
9
+ this.minimum = minimum;
10
+ }
11
+ setVisible(visible) {
12
+ this.assertAlive();
13
+ this.layer.visibility(visible);
14
+ }
15
+ setStyle(style) {
16
+ this.assertAlive();
17
+ this.validateLengths(style, ['strokeWidth']);
18
+ if (style.stroke !== undefined) {
19
+ this.layer.Stroke = style.stroke;
20
+ }
21
+ if (style.strokeWidth !== undefined) {
22
+ this.layer.StrokeWidth = String(style.strokeWidth);
23
+ }
24
+ }
25
+ addValue(value) {
26
+ this.assertAlive();
27
+ this.validateValue(value);
28
+ this.layer.append(value);
29
+ }
30
+ removeValue(value) {
31
+ this.assertAlive();
32
+ this.validateValue(value);
33
+ this.layer.remove(value);
34
+ }
35
+ validateValue(value) {
36
+ if (!Number.isFinite(value) || value < this.minimum || value <= 0) {
37
+ throw new RangeError(`Circle value must be finite, positive, and at least ${this.minimum}.`);
38
+ }
39
+ }
40
+ }
@@ -1,10 +1,8 @@
1
1
  import type * as d3 from 'd3';
2
- import { SmithGroup } from './SmithGroup.js';
3
- import { SmithScaler } from './SmithScaler.js';
4
- import { Line } from '../shapes/Line.js';
5
- import { Circle } from '../shapes/Circle.js';
6
- import { Point } from '../shapes/Point.js';
7
- import { SmithConstantCircle } from '../SmithConstantCircle.js';
2
+ import { SmithGroup } from '../svg/SmithGroup.js';
3
+ import { SmithScaler } from '../svg/SmithScaler.js';
4
+ import type { Line, Circle, Point } from '../math/geometry.js';
5
+ import { SmithConstantCircle } from '../rf/SmithConstantCircle.js';
8
6
  export interface ArcData {
9
7
  p1: Point;
10
8
  p2: Point;
@@ -37,9 +35,6 @@ export declare abstract class ConstCircles {
37
35
  visibility(visible: boolean): void;
38
36
  show(): void;
39
37
  hide(): void;
40
- displayMinor(display: boolean): void;
41
- showMinor(): void;
42
- hideMinor(): void;
43
38
  protected build(): SmithGroup;
44
39
  /** Mount labels separately so every grid line is painted before any label. */
45
40
  get labels(): SmithGroup;
@@ -1,5 +1,5 @@
1
- import { SmithGroup } from './SmithGroup.js';
2
- import { SmithConstantCircle } from '../SmithConstantCircle.js';
1
+ import { SmithGroup } from '../svg/SmithGroup.js';
2
+ import { SmithConstantCircle } from '../rf/SmithConstantCircle.js';
3
3
  export class ConstCircles {
4
4
  scaler;
5
5
  calcs = new SmithConstantCircle();
@@ -26,20 +26,6 @@ export class ConstCircles {
26
26
  this.container.hide();
27
27
  this.texts.hide();
28
28
  }
29
- displayMinor(display) {
30
- if (display) {
31
- this.minor.show();
32
- }
33
- else {
34
- this.minor.hide();
35
- }
36
- }
37
- showMinor() {
38
- this.minor.show();
39
- }
40
- hideMinor() {
41
- this.minor.hide();
42
- }
43
29
  build() {
44
30
  this.texts.hide();
45
31
  return this.container.append(this.minor).append(this.major).hide();
@@ -108,12 +94,12 @@ export class ConstCircles {
108
94
  defaultDrawingOptions() {
109
95
  return {
110
96
  // Keep curved grid strokes visible at normal browser zoom and low pixel density.
111
- stroke: '#64748b',
112
- majorWidth: '1',
113
- minorWidth: '0.6',
114
- textColor: 'black',
115
- textFontFamily: 'Verdana',
116
- textFontSize: '1',
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)',
117
103
  };
118
104
  }
119
105
  scaleArc(scaler, d) {
@@ -1,5 +1,5 @@
1
- import { SmithGroup } from './SmithGroup.js';
2
- import { SmithScaler } from './SmithScaler.js';
1
+ import { SmithGroup } from '../svg/SmithGroup.js';
2
+ import { SmithScaler } from '../svg/SmithScaler.js';
3
3
  interface ConstQDrawOptions {
4
4
  stroke: string;
5
5
  strokeWidth: string;
@@ -1,6 +1,6 @@
1
- import { SmithGroup } from './SmithGroup.js';
2
- import { SmithArc } from './SmithArc.js';
3
- import { SmithConstantCircle } from '../SmithConstantCircle.js';
1
+ import { SmithGroup } from '../svg/SmithGroup.js';
2
+ import { SmithArc } from '../svg/SmithArc.js';
3
+ import { SmithConstantCircle } from '../rf/SmithConstantCircle.js';
4
4
  export class ConstQCircles {
5
5
  scaler;
6
6
  calcs = new SmithConstantCircle();
@@ -28,7 +28,7 @@ export class ConstQCircles {
28
28
  this.container.append(a2);
29
29
  }
30
30
  getDefaultDrawOptions() {
31
- return { stroke: 'blue', strokeWidth: '1' };
31
+ return { stroke: 'var(--smithkit-circles-q)', strokeWidth: 'var(--smithkit-circles-width)' };
32
32
  }
33
33
  setDrawOptions(opts) {
34
34
  this.opts = opts;
@@ -1,5 +1,5 @@
1
- import { SmithGroup } from './SmithGroup.js';
2
- import { SmithScaler } from './SmithScaler.js';
1
+ import { SmithGroup } from '../svg/SmithGroup.js';
2
+ import { SmithScaler } from '../svg/SmithScaler.js';
3
3
  interface ConstSwrDrawOptions {
4
4
  stroke: string;
5
5
  strokeWidth: string;
@@ -1,6 +1,6 @@
1
- import { SmithGroup } from './SmithGroup.js';
2
- import { SmithCircle } from './SmithCircle.js';
3
- import { SmithConstantCircle } from '../SmithConstantCircle.js';
1
+ import { SmithGroup } from '../svg/SmithGroup.js';
2
+ import { SmithCircle } from '../svg/SmithCircle.js';
3
+ import { SmithConstantCircle } from '../rf/SmithConstantCircle.js';
4
4
  export class ConstSwrCircles {
5
5
  scaler;
6
6
  calcs = new SmithConstantCircle();
@@ -27,7 +27,7 @@ export class ConstSwrCircles {
27
27
  this.container.append(circle);
28
28
  }
29
29
  getDefaultDrawOptions() {
30
- return { stroke: 'orange', strokeWidth: '1' };
30
+ return { stroke: 'var(--smithkit-circles-vswr)', strokeWidth: 'var(--smithkit-circles-width)' };
31
31
  }
32
32
  setDrawOptions(opts) {
33
33
  this.opts = opts;
@@ -0,0 +1,18 @@
1
+ import type { SmithTicksData, SmithTicksShapes } from './types.js';
2
+ export declare class GridDefinitions {
3
+ private constructor();
4
+ static readonly basicValues: readonly number[];
5
+ /** Complete principal circles and boundary-to-axis arcs for a sparse grid. */
6
+ static basic(): {
7
+ resistance: SmithTicksShapes;
8
+ reactance: SmithTicksShapes;
9
+ };
10
+ private static readonly resistanceMajor;
11
+ private static readonly resistanceMinor;
12
+ private static readonly reactanceMajor;
13
+ private static readonly reactanceMinor;
14
+ private static resistanceArcs;
15
+ private static reactanceArcs;
16
+ /** Build fresh definitions so callers cannot mutate another chart's grid. */
17
+ static create(): SmithTicksData;
18
+ }
@@ -0,0 +1,167 @@
1
+ export class GridDefinitions {
2
+ constructor() { }
3
+ static basicValues = Object.freeze([0.2, 0.5, 1, 2, 5]);
4
+ /** Complete principal circles and boundary-to-axis arcs for a sparse grid. */
5
+ static basic() {
6
+ return {
7
+ resistance: { lines: [], circles: [...GridDefinitions.basicValues], arcs: [] },
8
+ reactance: {
9
+ lines: [{ p1: [-1, 0], p2: [1, 0] }],
10
+ circles: [],
11
+ arcs: GridDefinitions.basicValues.flatMap((value) => [
12
+ [
13
+ value,
14
+ [
15
+ [0, 0],
16
+ [0, 1],
17
+ ],
18
+ [false, false],
19
+ ],
20
+ [
21
+ -value,
22
+ [
23
+ [0, 1],
24
+ [0, 0],
25
+ ],
26
+ [false, true],
27
+ ],
28
+ ]),
29
+ },
30
+ };
31
+ }
32
+ static resistanceMajor = [
33
+ [[0.05, 0.15], 0.2, -0.2, false],
34
+ [[0.1, 0.3, 0.5, 0.7, 0.9], 2, -2, true],
35
+ [[0.2, 0.4, 0.6, 0.8, 1.2, 1.4, 1.6, 1.8], 5, -5, true],
36
+ [[1, 3, 5], 10, -10, true],
37
+ [[2, 4], 20, -20, true],
38
+ [[20], 50, -50, true],
39
+ ];
40
+ static resistanceMinor = [
41
+ [[0.02, 0.04, 0.06, 0.08, 0.12, 0.14, 0.16, 0.18], 0.2, 0.5, false],
42
+ [[0.02, 0.04, 0.06, 0.08, 0.12, 0.14, 0.16, 0.18], -0.2, -0.5, false],
43
+ [[0.05, 0.15, 0.25, 0.35, 0.45], 0.5, 1, false],
44
+ [[0.05, 0.15, 0.25, 0.35, 0.45], -0.5, -1, false],
45
+ [
46
+ [
47
+ 0.01, 0.02, 0.03, 0.04, 0.06, 0.07, 0.08, 0.09, 0.11, 0.12, 0.13, 0.14, 0.16, 0.17, 0.18,
48
+ 0.19,
49
+ ],
50
+ 0.2,
51
+ -0.2,
52
+ false,
53
+ ],
54
+ [[0.22, 0.24, 0.26, 0.28, 0.32, 0.34, 0.36, 0.38, 0.42, 0.44, 0.46, 0.48], 0.5, -0.5, false],
55
+ [[0.55, 0.65, 0.75, 0.85, 0.95], 2, -2, true],
56
+ [[1.1, 1.3, 1.5, 1.7, 1.9], 2, -2, false],
57
+ [[2.2, 2.4, 2.6, 2.8, 3.2, 3.4, 3.6, 3.8], 5, -5, true],
58
+ [[4.2, 4.4, 4.6, 4.8], 5, -5, false],
59
+ [[6, 8, 12, 14, 16, 18], 20, -20, true],
60
+ [[7, 9], 10, -10, true],
61
+ [[30, 40], 50, -50, true],
62
+ ];
63
+ static reactanceMajor = [
64
+ [[0.05, 0.15], 0.2, 0],
65
+ [[0.1, 0.3, 0.5, 0.7, 0.9], 2, 0],
66
+ [[0.2, 0.4, 0.6, 0.8, 1.2, 1.4, 1.6, 1.8], 5, 0],
67
+ [[1, 3, 5], 10, 0],
68
+ [[2, 4, 10], 20, 0],
69
+ [[20], 50, 0],
70
+ ];
71
+ static reactanceMinor = [
72
+ [
73
+ [
74
+ 0.01, 0.02, 0.03, 0.04, 0.06, 0.07, 0.08, 0.09, 0.11, 0.12, 0.13, 0.14, 0.16, 0.17, 0.18,
75
+ 0.19,
76
+ ],
77
+ 0.2,
78
+ 0,
79
+ ],
80
+ [[0.02, 0.04, 0.06, 0.08, 0.12, 0.14, 0.16, 0.18], 0.5, 0.2],
81
+ [[0.22, 0.24, 0.26, 0.28, 0.32, 0.34, 0.36, 0.38, 0.42, 0.44, 0.46, 0.48], 0.5, 0],
82
+ [[0.05, 0.15, 0.25, 0.35, 0.45], 1, 0.5],
83
+ [[0.55, 0.65, 0.75, 0.85, 0.95], 1, 0],
84
+ [[1.1, 1.3, 1.5, 1.7, 1.9], 2, 0],
85
+ [[2.2, 2.4, 2.6, 2.8, 3.2, 3.4, 3.6, 3.8, 4.2, 4.4, 4.6, 4.8], 5, 0],
86
+ [[6, 8, 14, 16, 18], 20, 0],
87
+ [[7, 9], 10, 0],
88
+ [[12, 30, 40], 50, 0],
89
+ ];
90
+ static resistanceArcs(bands) {
91
+ return bands.flatMap(([values, from, to, largeArc]) => values.map((value) => [
92
+ value,
93
+ [
94
+ [from, from < 0 ? 1 : 0],
95
+ [to, to < 0 ? 1 : 0],
96
+ ],
97
+ [largeArc, from > to],
98
+ ]));
99
+ }
100
+ static reactanceArcs(bands) {
101
+ return bands.flatMap(([values, outer, inner]) => values.flatMap((value) => [
102
+ [
103
+ value,
104
+ [
105
+ [outer, 1],
106
+ [inner, 1],
107
+ ],
108
+ [false, false],
109
+ ],
110
+ [
111
+ -value,
112
+ [
113
+ [outer, 0],
114
+ [inner, 0],
115
+ ],
116
+ [false, true],
117
+ ],
118
+ ]));
119
+ }
120
+ /** Build fresh definitions so callers cannot mutate another chart's grid. */
121
+ static create() {
122
+ return {
123
+ resistance: {
124
+ major: {
125
+ lines: [],
126
+ circles: [10, 50],
127
+ arcs: GridDefinitions.resistanceArcs(GridDefinitions.resistanceMajor),
128
+ },
129
+ minor: {
130
+ lines: [],
131
+ circles: [],
132
+ arcs: GridDefinitions.resistanceArcs(GridDefinitions.resistanceMinor),
133
+ },
134
+ },
135
+ reactance: {
136
+ major: {
137
+ lines: [{ p1: [-1, 0], p2: [1, 0] }],
138
+ circles: [],
139
+ arcs: [
140
+ ...GridDefinitions.reactanceArcs(GridDefinitions.reactanceMajor),
141
+ [
142
+ 50,
143
+ [
144
+ [0, 0],
145
+ [0, 1],
146
+ ],
147
+ [false, false],
148
+ ],
149
+ [
150
+ -50,
151
+ [
152
+ [0, 1],
153
+ [0, 0],
154
+ ],
155
+ [false, true],
156
+ ],
157
+ ],
158
+ },
159
+ minor: {
160
+ lines: [],
161
+ circles: [],
162
+ arcs: GridDefinitions.reactanceArcs(GridDefinitions.reactanceMinor),
163
+ },
164
+ },
165
+ };
166
+ }
167
+ }
@@ -0,0 +1,26 @@
1
+ import type { TickDefRequired } from './Tick.js';
2
+ import type { SmithTicksShapes } from './types.js';
3
+ import type { Point } from '../math/geometry.js';
4
+ export type GridKind = 'resistance' | 'reactance' | 'conductance' | 'susceptance';
5
+ export type GridArc = [Point, Point, number, boolean, boolean];
6
+ export declare class GridGeometry {
7
+ private constructor();
8
+ private static readonly calcs;
9
+ private static readonly circles;
10
+ private static readonly clipping;
11
+ /** Normalized geometry only: no DOM, D3, or pixel coordinates. */
12
+ static shapes(kind: GridKind, data: SmithTicksShapes): {
13
+ lines: import("../math/geometry.js").Line[];
14
+ circles: import("../math/geometry.js").Circle[];
15
+ arcs: GridArc[];
16
+ };
17
+ static label(kind: GridKind, definition: TickDefRequired): {
18
+ point: [number, number];
19
+ text: string;
20
+ rotate: number;
21
+ dx: number;
22
+ dy: number;
23
+ textAnchor: string;
24
+ dominantBaseline: string;
25
+ };
26
+ }
@@ -0,0 +1,58 @@
1
+ import { SmithConstantCircle } from '../rf/SmithConstantCircle.js';
2
+ import { Complex } from '../math/Complex.js';
3
+ export class GridGeometry {
4
+ constructor() { }
5
+ static calcs = new SmithConstantCircle();
6
+ static circles = {
7
+ resistance: (value) => GridGeometry.calcs.resistanceCircle(value),
8
+ reactance: (value) => GridGeometry.calcs.reactanceCircle(value),
9
+ conductance: (value) => GridGeometry.calcs.conductanceCircle(value),
10
+ susceptance: (value) => GridGeometry.calcs.susceptanceCircle(value),
11
+ };
12
+ static clipping = {
13
+ resistance: 'reactance',
14
+ reactance: 'resistance',
15
+ conductance: 'susceptance',
16
+ susceptance: 'conductance',
17
+ };
18
+ /** Normalized geometry only: no DOM, D3, or pixel coordinates. */
19
+ static shapes(kind, data) {
20
+ const circle = GridGeometry.circles[kind];
21
+ const clip = GridGeometry.circles[GridGeometry.clipping[kind]];
22
+ return {
23
+ lines: data.lines,
24
+ circles: data.circles.map(circle),
25
+ arcs: data.arcs.map(([value, limits, options]) => {
26
+ const c = circle(value);
27
+ const [a, b] = limits.map(([limit, index]) => GridGeometry.calcs.circleCircleIntersection(c, clip(limit))[index]);
28
+ return [a, b, c.r, options[0], options[1]];
29
+ }),
30
+ };
31
+ }
32
+ static label(kind, definition) {
33
+ const { point, transform, dp, textAnchor, dominantBaseline } = definition;
34
+ const admittance = kind === 'conductance' || kind === 'susceptance';
35
+ const real = kind === 'resistance' || kind === 'conductance';
36
+ const rc = admittance
37
+ ? GridGeometry.calcs.admittanceToRflCoeff(Complex.from(point.r, point.i))
38
+ : GridGeometry.calcs.impedanceToRflCoeff(Complex.from(point.r, point.i));
39
+ if (!rc) {
40
+ throw new Error('Invalid grid label coordinates.');
41
+ }
42
+ const value = real ? point.r : point.i;
43
+ const circle = GridGeometry.circles[kind](value);
44
+ let rotate = -GridGeometry.calcs.tangentToCircleAngle(circle, rc.toVector()) + transform.rotate;
45
+ if (admittance && rotate !== 90) {
46
+ rotate += 180;
47
+ }
48
+ return {
49
+ point: rc.toVector(),
50
+ text: value.toFixed(dp),
51
+ rotate,
52
+ dx: transform.dx,
53
+ dy: transform.dy,
54
+ textAnchor,
55
+ dominantBaseline,
56
+ };
57
+ }
58
+ }
@@ -0,0 +1,8 @@
1
+ import { Tick } from './Tick.js';
2
+ export declare class GridLabels {
3
+ private constructor();
4
+ private static readonly values;
5
+ private static readonly interiorValues;
6
+ static resistance(): Tick[];
7
+ static reactance(): Tick[];
8
+ }