smithkit 0.6.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.
- package/README.md +2 -2
- package/dist/lib/OptionsValidation.d.ts +3 -3
- package/dist/lib/OptionsValidation.js +17 -13
- package/dist/lib/Smith.d.ts +3 -0
- package/dist/lib/Smith.js +40 -9
- package/dist/lib/appearance/SvgTheme.d.ts +1 -0
- package/dist/lib/appearance/SvgTheme.js +8 -7
- package/dist/lib/appearance/Theme.js +49 -52
- package/dist/lib/appearance/types.d.ts +75 -31
- package/dist/lib/grid/CircleLayerControl.d.ts +2 -2
- package/dist/lib/grid/CircleLayerControl.js +4 -4
- package/dist/lib/grid/ConstCircles.js +6 -6
- package/dist/lib/grid/ConstQCircles.js +4 -1
- package/dist/lib/grid/ConstSwrCircles.js +4 -1
- package/dist/lib/grid/GridLayerControl.d.ts +2 -2
- package/dist/lib/grid/GridLayerControl.js +10 -11
- package/dist/lib/index.d.ts +2 -2
- package/dist/lib/interaction/SmithCursor.js +6 -6
- package/dist/lib/layers.d.ts +28 -14
- package/dist/lib/measurements.d.ts +20 -8
- package/dist/lib/options.d.ts +4 -4
- package/dist/lib/rendering/ChartHost.d.ts +5 -0
- package/dist/lib/rendering/ChartHost.js +14 -0
- package/dist/lib/rendering/SvgChartRenderer.d.ts +2 -2
- package/dist/lib/rendering/SvgChartRenderer.js +1 -1
- package/dist/lib/scales/SmithPeripheralScales.js +11 -11
- package/dist/lib/scales/SmithScales.d.ts +3 -0
- package/dist/lib/scales/SmithScales.js +37 -16
- package/dist/lib/traces/SmithData.d.ts +3 -3
- package/dist/lib/traces/SmithMarker.js +5 -5
- package/dist/lib/traces/TraceRenderer.d.ts +3 -3
- package/dist/lib/traces/TraceRenderer.js +19 -18
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -60,8 +60,7 @@ Mount a container with a non-zero size:
|
|
|
60
60
|
```ts
|
|
61
61
|
import { Smith } from 'smithkit';
|
|
62
62
|
|
|
63
|
-
const chart = new Smith({ referenceImpedanceOhms: 50 });
|
|
64
|
-
chart.draw('#smith');
|
|
63
|
+
const chart = new Smith('#smith', { referenceImpedanceOhms: 50 });
|
|
65
64
|
const traceId = chart.addTrace(
|
|
66
65
|
[
|
|
67
66
|
[1e9, 0.5, -0.5],
|
|
@@ -84,6 +83,7 @@ packed `Float64Array` triples are also supported. Inputs are validated and copie
|
|
|
84
83
|
By default, the chart shows a labeled standard impedance grid with zoom, cursor
|
|
85
84
|
tracking, and peripheral scales disabled. No markers are added automatically.
|
|
86
85
|
The constructor and `setOptions()` share the same grouped configuration schema.
|
|
86
|
+
To mount later, use `new Smith(options)` and then `chart.draw(elementOrSelector)`.
|
|
87
87
|
|
|
88
88
|
Create charts in the browser after mounting the host; call `destroy()` on unmount.
|
|
89
89
|
Calculation, formatting, and Touchstone classes also work without a DOM.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SmithOptions } from './options.js';
|
|
2
|
-
import type {
|
|
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:
|
|
12
|
-
static circleStyle(style:
|
|
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
|
-
|
|
46
|
-
'majorWidth',
|
|
47
|
-
'minorWidth'
|
|
48
|
-
'
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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', ['
|
|
57
|
-
|
|
58
|
-
|
|
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) {
|
package/dist/lib/Smith.d.ts
CHANGED
|
@@ -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(
|
|
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.
|
|
151
|
+
data.setColor(theme.traces.colors[index % theme.traces.colors.length]);
|
|
137
152
|
}
|
|
138
153
|
}
|
|
139
154
|
}
|
|
@@ -176,8 +191,8 @@ export class Smith {
|
|
|
176
191
|
? MarkerLegend.entries(traces, (id) => this.getMarker(id), options.markerLegend)
|
|
177
192
|
: []),
|
|
178
193
|
],
|
|
179
|
-
textColor: this.theme.grid.
|
|
180
|
-
fontFamily: this.theme.fontFamily,
|
|
194
|
+
textColor: this.theme.grid.text.color,
|
|
195
|
+
fontFamily: this.theme.text.fontFamily,
|
|
181
196
|
};
|
|
182
197
|
}
|
|
183
198
|
/** Export the mounted view as PNG, optionally with radial scales and a trace legend. */
|
|
@@ -287,15 +302,31 @@ export class Smith {
|
|
|
287
302
|
return;
|
|
288
303
|
}
|
|
289
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
|
+
}
|
|
290
319
|
if (options.mode !== undefined && !['points', 'line', 'both'].includes(options.mode)) {
|
|
291
320
|
throw new TypeError('Trace mode must be points, line, or both.');
|
|
292
321
|
}
|
|
293
|
-
if (options.
|
|
294
|
-
(!Number.isFinite(options.
|
|
322
|
+
if (options.line?.tolerancePx !== undefined &&
|
|
323
|
+
(!Number.isFinite(options.line.tolerancePx) || options.line.tolerancePx < 0)) {
|
|
295
324
|
throw new RangeError('Line tolerance must be finite and non-negative.');
|
|
296
325
|
}
|
|
297
|
-
for (const key of [
|
|
298
|
-
|
|
326
|
+
for (const [key, value] of [
|
|
327
|
+
['line.width', options.line?.width],
|
|
328
|
+
['point.radius', options.point?.radius],
|
|
329
|
+
]) {
|
|
299
330
|
if (value !== undefined && (!Number.isFinite(value) || value <= 0)) {
|
|
300
331
|
throw new RangeError(`${key} must be positive and finite.`);
|
|
301
332
|
}
|
|
@@ -439,7 +470,7 @@ export class Smith {
|
|
|
439
470
|
this.data = [];
|
|
440
471
|
}
|
|
441
472
|
createSmithData(values, dataset, options) {
|
|
442
|
-
const color = this.theme.
|
|
473
|
+
const color = this.theme.traces.colors[dataset % this.theme.traces.colors.length];
|
|
443
474
|
const data = this.renderer.createTrace(values, color, options, (marker, dragging) => {
|
|
444
475
|
this.markerDragChanged(marker, dragging);
|
|
445
476
|
const snapshot = this.getMarker(this.markerId(marker));
|
|
@@ -2,20 +2,21 @@
|
|
|
2
2
|
export class SvgTheme {
|
|
3
3
|
constructor() { }
|
|
4
4
|
static apply(element, theme) {
|
|
5
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
4
|
+
text: {
|
|
5
|
+
fontFamily: string;
|
|
6
|
+
};
|
|
5
7
|
grid: {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
19
|
+
color: string;
|
|
14
20
|
width: number;
|
|
15
21
|
};
|
|
16
22
|
circles: {
|
|
17
|
-
q:
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
q: {
|
|
24
|
+
color: string;
|
|
25
|
+
width: number;
|
|
26
|
+
};
|
|
27
|
+
vswr: {
|
|
28
|
+
color: string;
|
|
29
|
+
width: number;
|
|
30
|
+
};
|
|
20
31
|
};
|
|
21
32
|
scales: {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
|
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,
|
|
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:
|
|
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.
|
|
21
|
-
this.layer.Stroke = style.
|
|
20
|
+
if (style.line?.color !== undefined) {
|
|
21
|
+
this.layer.Stroke = style.line.color;
|
|
22
22
|
}
|
|
23
|
-
if (style.
|
|
24
|
-
this.layer.StrokeWidth = String(style.
|
|
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-
|
|
98
|
-
majorWidth: 'var(--smithkit-grid-majorWidth)',
|
|
99
|
-
minorWidth: 'var(--smithkit-grid-minorWidth)',
|
|
100
|
-
textColor: 'var(--smithkit-grid-
|
|
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 {
|
|
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 {
|
|
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,
|
|
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:
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
for (const
|
|
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[
|
|
43
|
+
this.layer[property] = String(value);
|
|
45
44
|
}
|
|
46
45
|
}
|
|
47
46
|
this.changed();
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -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';
|
|
@@ -22,8 +22,8 @@ export class SmithCursor {
|
|
|
22
22
|
this.group = new SmithGroup().attr('pointer-events', 'none');
|
|
23
23
|
this.impedance = {
|
|
24
24
|
group: new SmithGroup({
|
|
25
|
-
stroke: 'var(--smithkit-cursor-
|
|
26
|
-
strokeWidth: 'var(--smithkit-cursor-
|
|
25
|
+
stroke: 'var(--smithkit-cursor-impedance-color)',
|
|
26
|
+
strokeWidth: 'var(--smithkit-cursor-line-width)',
|
|
27
27
|
fill: 'none',
|
|
28
28
|
}),
|
|
29
29
|
resistance: { circle: new SmithCircle({ p: [0, 0], r: 1 }) },
|
|
@@ -37,8 +37,8 @@ export class SmithCursor {
|
|
|
37
37
|
this.impedance.reactance.line.nonScalingStroke();
|
|
38
38
|
this.admittance = {
|
|
39
39
|
group: new SmithGroup({
|
|
40
|
-
stroke: 'var(--smithkit-cursor-
|
|
41
|
-
strokeWidth: 'var(--smithkit-cursor-
|
|
40
|
+
stroke: 'var(--smithkit-cursor-admittance-color)',
|
|
41
|
+
strokeWidth: 'var(--smithkit-cursor-line-width)',
|
|
42
42
|
fill: 'none',
|
|
43
43
|
}),
|
|
44
44
|
conductance: { circle: new SmithCircle({ p: [0, 0], r: 1 }) },
|
|
@@ -51,8 +51,8 @@ export class SmithCursor {
|
|
|
51
51
|
this.admittance.susceptance.arc.nonScalingStroke();
|
|
52
52
|
this.admittance.susceptance.line.nonScalingStroke();
|
|
53
53
|
this.point = new SmithLine([0, 0], [0, 0], {
|
|
54
|
-
stroke: 'var(--smithkit-cursor-
|
|
55
|
-
strokeWidth: 'var(--smithkit-cursor-
|
|
54
|
+
stroke: 'var(--smithkit-cursor-point-color)',
|
|
55
|
+
strokeWidth: 'var(--smithkit-cursor-point-size)',
|
|
56
56
|
fill: 'none',
|
|
57
57
|
});
|
|
58
58
|
this.point.nonScalingStroke();
|
package/dist/lib/layers.d.ts
CHANGED
|
@@ -1,19 +1,33 @@
|
|
|
1
1
|
import type { Complex } from './math/Complex.js';
|
|
2
2
|
export interface GridStyle {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
line: {
|
|
4
|
+
color: string;
|
|
5
|
+
/** Non-scaling stroke width in CSS pixels. */
|
|
6
|
+
majorWidth: number;
|
|
7
|
+
/** Non-scaling stroke width in CSS pixels. */
|
|
8
|
+
minorWidth: number;
|
|
9
|
+
};
|
|
10
|
+
text: {
|
|
11
|
+
color: string;
|
|
12
|
+
fontFamily: string;
|
|
13
|
+
/** Base font size in chart units; adaptive layout enforces a 9 CSS px minimum in the default view. */
|
|
14
|
+
fontSize: number;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/** A grid style patch. Omitted nested properties retain their existing values. */
|
|
18
|
+
export interface GridStyleOptions {
|
|
19
|
+
line?: Partial<GridStyle['line']>;
|
|
20
|
+
text?: Partial<GridStyle['text']>;
|
|
12
21
|
}
|
|
13
22
|
export interface CircleStyle {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
23
|
+
line: {
|
|
24
|
+
color: string;
|
|
25
|
+
/** Non-scaling stroke width in CSS pixels. */
|
|
26
|
+
width: number;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export interface CircleStyleOptions {
|
|
30
|
+
line?: Partial<CircleStyle['line']>;
|
|
17
31
|
}
|
|
18
32
|
export type GridDetail = 'basic' | 'standard' | 'detailed';
|
|
19
33
|
/** Grid styling uses SVG user units, except non-scaling stroke widths in screen pixels. */
|
|
@@ -23,11 +37,11 @@ export interface GridLayer {
|
|
|
23
37
|
setLabelsVisible(visible: boolean): void;
|
|
24
38
|
/** Default: standard. Basic shows only the principal normalized values. */
|
|
25
39
|
setDetail(detail: GridDetail): void;
|
|
26
|
-
setStyle(style:
|
|
40
|
+
setStyle(style: GridStyleOptions): void;
|
|
27
41
|
}
|
|
28
42
|
export interface CircleLayer {
|
|
29
43
|
setVisible(visible: boolean): void;
|
|
30
|
-
setStyle(style:
|
|
44
|
+
setStyle(style: CircleStyleOptions): void;
|
|
31
45
|
/** Replace the complete set after validation; duplicates are ignored and empty clears it. */
|
|
32
46
|
setValues(values: readonly number[]): void;
|
|
33
47
|
addValue(value: number): void;
|
|
@@ -3,14 +3,24 @@ import type { SmithReading } from './rf/RfCalculations.js';
|
|
|
3
3
|
export type TraceRenderMode = 'points' | 'line' | 'both';
|
|
4
4
|
export interface TraceStyle {
|
|
5
5
|
mode: TraceRenderMode;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
line: {
|
|
7
|
+
/** Non-scaling SVG stroke width in CSS pixels. Default: 2. */
|
|
8
|
+
width: number;
|
|
9
|
+
/** Maximum additional line simplification error in CSS pixels. Zero disables it (default). */
|
|
10
|
+
tolerancePx: number;
|
|
11
|
+
};
|
|
12
|
+
point: {
|
|
13
|
+
/** Radius in CSS pixels; constant under chart zoom and container resize. Default: 2. */
|
|
14
|
+
radius: number;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/** A partial style patch; omitted nested properties retain their current values. */
|
|
18
|
+
export interface TraceStyleOptions {
|
|
19
|
+
mode?: TraceRenderMode;
|
|
20
|
+
line?: Partial<TraceStyle['line']>;
|
|
21
|
+
point?: Partial<TraceStyle['point']>;
|
|
22
|
+
}
|
|
23
|
+
export interface TraceOptions extends TraceStyleOptions {
|
|
14
24
|
name?: string;
|
|
15
25
|
/** A solid CSS color, such as '#2563eb' or 'orange'. */
|
|
16
26
|
color?: string;
|
|
@@ -29,6 +39,8 @@ export interface MarkerInfo {
|
|
|
29
39
|
readonly sampleIndex: number;
|
|
30
40
|
}
|
|
31
41
|
export interface TraceInfo extends Readonly<TraceStyle> {
|
|
42
|
+
readonly line: Readonly<TraceStyle['line']>;
|
|
43
|
+
readonly point: Readonly<TraceStyle['point']>;
|
|
32
44
|
readonly id: string;
|
|
33
45
|
readonly name: string;
|
|
34
46
|
readonly color: string;
|
package/dist/lib/options.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { SmithAppearance } from './appearance/types.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { CircleStyleOptions, GridDetail, GridStyleOptions } from './layers.js';
|
|
3
3
|
/** Settings for an individual impedance/admittance grid layer. */
|
|
4
4
|
export interface GridLayerOptions {
|
|
5
5
|
visible?: boolean;
|
|
6
6
|
detail?: GridDetail;
|
|
7
7
|
labelsVisible?: boolean;
|
|
8
|
-
style?:
|
|
8
|
+
style?: GridStyleOptions;
|
|
9
9
|
}
|
|
10
10
|
/** Shared settings for all four grids, followed by per-layer overrides. */
|
|
11
11
|
export interface GridOptions {
|
|
@@ -13,7 +13,7 @@ export interface GridOptions {
|
|
|
13
13
|
detail?: GridDetail;
|
|
14
14
|
/** Default: true. */
|
|
15
15
|
labelsVisible?: boolean;
|
|
16
|
-
style?:
|
|
16
|
+
style?: GridStyleOptions;
|
|
17
17
|
layers?: {
|
|
18
18
|
resistance?: GridLayerOptions;
|
|
19
19
|
reactance?: GridLayerOptions;
|
|
@@ -24,7 +24,7 @@ export interface GridOptions {
|
|
|
24
24
|
export interface CircleLayerOptions {
|
|
25
25
|
/** Default: false. */
|
|
26
26
|
visible?: boolean;
|
|
27
|
-
style?:
|
|
27
|
+
style?: CircleStyleOptions;
|
|
28
28
|
/** Replace the default values. Empty hides all circles; duplicate values are ignored. */
|
|
29
29
|
values?: readonly number[];
|
|
30
30
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Recognize HTML hosts across windows without accessing browser globals at import time. */
|
|
2
|
+
export class ChartHost {
|
|
3
|
+
constructor() { }
|
|
4
|
+
static isElement(value) {
|
|
5
|
+
if (!value || typeof value !== 'object') {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
if (typeof HTMLElement !== 'undefined' && value instanceof HTMLElement) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
const elementType = value.ownerDocument?.defaultView?.HTMLElement;
|
|
12
|
+
return elementType !== undefined && value instanceof elementType;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -4,7 +4,7 @@ import type { SmithMarker } from '../traces/SmithMarker.js';
|
|
|
4
4
|
import { TraceInput } from '../samples.js';
|
|
5
5
|
import { Complex } from '../math/Complex.js';
|
|
6
6
|
import type { ChartLayers, PeripheralScales } from '../layers.js';
|
|
7
|
-
import type {
|
|
7
|
+
import type { TraceStyleOptions } from '../measurements.js';
|
|
8
8
|
/** Internal SVG backend. Owns chart elements, view transforms, and SVG gestures. */
|
|
9
9
|
export declare class SvgChartRenderer {
|
|
10
10
|
private onCursorChange;
|
|
@@ -64,6 +64,6 @@ export declare class SvgChartRenderer {
|
|
|
64
64
|
private cursorContainer;
|
|
65
65
|
private drawReactanceAxis;
|
|
66
66
|
/** Construct trace rendering without exposing chart containers or scalers to Smith. */
|
|
67
|
-
createTrace(values: TraceInput, color: string, style:
|
|
67
|
+
createTrace(values: TraceInput, color: string, style: TraceStyleOptions, onMarkerDrag: (marker: SmithMarker, dragging: boolean) => void): SmithData;
|
|
68
68
|
removeTrace(trace: SmithData): void;
|
|
69
69
|
}
|
|
@@ -93,7 +93,7 @@ export class SvgChartRenderer {
|
|
|
93
93
|
this.cursor = this.initCursor();
|
|
94
94
|
const cursorContainer = this.cursorContainer();
|
|
95
95
|
this.reactanceAxis = this.drawReactanceAxis({
|
|
96
|
-
stroke: 'var(--smithkit-boundary-
|
|
96
|
+
stroke: 'var(--smithkit-boundary-color)',
|
|
97
97
|
strokeWidth: 'var(--smithkit-boundary-width)',
|
|
98
98
|
fill: 'none',
|
|
99
99
|
});
|
|
@@ -44,7 +44,7 @@ export class SmithPeripheralScales extends SmithGroup {
|
|
|
44
44
|
.attr('cy', 250)
|
|
45
45
|
.attr('r', (radius) => radius)
|
|
46
46
|
.attr('fill', 'none')
|
|
47
|
-
.attr('stroke', 'var(--smithkit-scales-
|
|
47
|
+
.attr('stroke', 'var(--smithkit-scales-boundary-color)')
|
|
48
48
|
.attr('stroke-width', 1.1)
|
|
49
49
|
.attr('vector-effect', 'non-scaling-stroke');
|
|
50
50
|
this.axes.each(function (scale, index) {
|
|
@@ -62,7 +62,7 @@ export class SmithPeripheralScales extends SmithGroup {
|
|
|
62
62
|
.attr('cy', 250)
|
|
63
63
|
.attr('r', radius)
|
|
64
64
|
.attr('fill', 'none')
|
|
65
|
-
.attr('stroke', 'var(--smithkit-scales-
|
|
65
|
+
.attr('stroke', 'var(--smithkit-scales-line-color)')
|
|
66
66
|
.attr('stroke-width', 0.6)
|
|
67
67
|
.attr('vector-effect', 'non-scaling-stroke');
|
|
68
68
|
}
|
|
@@ -77,7 +77,7 @@ export class SmithPeripheralScales extends SmithGroup {
|
|
|
77
77
|
.attr('y1', y1)
|
|
78
78
|
.attr('x2', x2)
|
|
79
79
|
.attr('y2', y2)
|
|
80
|
-
.attr('stroke', 'var(--smithkit-scales-
|
|
80
|
+
.attr('stroke', 'var(--smithkit-scales-line-color)')
|
|
81
81
|
.attr('stroke-width', major ? 0.8 : 0.5)
|
|
82
82
|
.attr('vector-effect', 'non-scaling-stroke');
|
|
83
83
|
const captionDistance = Math.abs(((angle - captionAngle + 540) % 360) - 180);
|
|
@@ -93,9 +93,9 @@ export class SmithPeripheralScales extends SmithGroup {
|
|
|
93
93
|
.attr('transform', `rotate(${rotation},${x},${y})`)
|
|
94
94
|
.attr('text-anchor', 'middle')
|
|
95
95
|
.attr('dominant-baseline', 'central')
|
|
96
|
-
.attr('font-family', 'var(--smithkit-fontFamily)')
|
|
97
|
-
.attr('font-size', 'var(--smithkit-scales-
|
|
98
|
-
.attr('fill', 'var(--smithkit-scales-
|
|
96
|
+
.attr('font-family', 'var(--smithkit-text-fontFamily)')
|
|
97
|
+
.attr('font-size', 'var(--smithkit-scales-peripheral-fontSize)')
|
|
98
|
+
.attr('fill', 'var(--smithkit-scales-text-color)')
|
|
99
99
|
.text(scale.unit === 'λ' ? value.toFixed(2) : String(value));
|
|
100
100
|
}
|
|
101
101
|
}
|
|
@@ -118,11 +118,11 @@ export class SmithPeripheralScales extends SmithGroup {
|
|
|
118
118
|
.append('text')
|
|
119
119
|
.attr('class', 'peripheral-caption')
|
|
120
120
|
.attr('text-anchor', 'middle')
|
|
121
|
-
.attr('font-family', 'var(--smithkit-fontFamily)')
|
|
122
|
-
.attr('font-size', 'var(--smithkit-scales-
|
|
121
|
+
.attr('font-family', 'var(--smithkit-text-fontFamily)')
|
|
122
|
+
.attr('font-size', 'var(--smithkit-scales-peripheral-fontSize)')
|
|
123
123
|
.attr('font-weight', 500)
|
|
124
124
|
.attr('letter-spacing', 0.3)
|
|
125
|
-
.attr('fill', 'var(--smithkit-scales-
|
|
125
|
+
.attr('fill', 'var(--smithkit-scales-text-color)')
|
|
126
126
|
.append('textPath')
|
|
127
127
|
.attr('href', `#${pathId}`)
|
|
128
128
|
.attr('startOffset', '50%')
|
|
@@ -132,8 +132,8 @@ export class SmithPeripheralScales extends SmithGroup {
|
|
|
132
132
|
.attr('class', 'peripheral-indicator')
|
|
133
133
|
.attr('r', 3)
|
|
134
134
|
.attr('visibility', 'hidden')
|
|
135
|
-
.attr('fill', 'var(--smithkit-scales-
|
|
136
|
-
.attr('stroke', 'var(--smithkit-scales-
|
|
135
|
+
.attr('fill', 'var(--smithkit-scales-indicator-color)')
|
|
136
|
+
.attr('stroke', 'var(--smithkit-scales-indicator-outline)')
|
|
137
137
|
.attr('stroke-width', 1);
|
|
138
138
|
});
|
|
139
139
|
this.updateLabelVisibility();
|
|
@@ -9,7 +9,10 @@ export declare class SmithScales {
|
|
|
9
9
|
private readonly start;
|
|
10
10
|
private readonly length;
|
|
11
11
|
private readonly axes;
|
|
12
|
+
/** Configure independent scales for later mounting with draw(). */
|
|
12
13
|
constructor(appearance?: SmithAppearance);
|
|
14
|
+
/** Configure and mount immediately. String targets are CSS selectors, as in draw(). */
|
|
15
|
+
constructor(target: string | HTMLElement, appearance?: SmithAppearance);
|
|
13
16
|
/** Replace the preset and overrides without changing readings or layout. */
|
|
14
17
|
setAppearance(appearance: SmithAppearance): void;
|
|
15
18
|
draw(target: string | HTMLElement): void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ImageExporter } from '../svg/ImageExporter.js';
|
|
2
|
+
import { ChartHost } from '../rendering/ChartHost.js';
|
|
2
3
|
import { Theme } from '../appearance/Theme.js';
|
|
3
4
|
import { SvgTheme } from '../appearance/SvgTheme.js';
|
|
4
5
|
import { select, format } from 'd3';
|
|
@@ -27,16 +28,27 @@ export class SmithScales {
|
|
|
27
28
|
.style('display', 'block')
|
|
28
29
|
.style('width', '100%')
|
|
29
30
|
.style('height', 'auto');
|
|
30
|
-
constructor(
|
|
31
|
+
constructor(targetOrAppearance = {}, configuration) {
|
|
32
|
+
const target = typeof targetOrAppearance === 'string' || ChartHost.isElement(targetOrAppearance)
|
|
33
|
+
? targetOrAppearance
|
|
34
|
+
: undefined;
|
|
35
|
+
if (target === undefined && configuration !== undefined) {
|
|
36
|
+
throw new TypeError('A container is required before the second appearance argument.');
|
|
37
|
+
}
|
|
38
|
+
const appearance = target === undefined
|
|
39
|
+
? targetOrAppearance
|
|
40
|
+
: configuration === undefined
|
|
41
|
+
? {}
|
|
42
|
+
: configuration;
|
|
31
43
|
this.setAppearance(appearance);
|
|
32
44
|
const labels = this.axes.append('g').attr('data-role', 'labels').attr('pointer-events', 'none');
|
|
33
45
|
labels
|
|
34
46
|
.append('text')
|
|
35
47
|
.attr('x', this.start)
|
|
36
48
|
.attr('y', 12)
|
|
37
|
-
.attr('font-family', 'var(--smithkit-fontFamily)')
|
|
38
|
-
.attr('font-size', 'var(--smithkit-scales-
|
|
39
|
-
.attr('fill', 'var(--smithkit-scales-
|
|
49
|
+
.attr('font-family', 'var(--smithkit-text-fontFamily)')
|
|
50
|
+
.attr('font-size', 'var(--smithkit-scales-title-fontSize)')
|
|
51
|
+
.attr('fill', 'var(--smithkit-scales-text-color)')
|
|
40
52
|
.text((scale) => scale.title);
|
|
41
53
|
labels
|
|
42
54
|
.append('text')
|
|
@@ -44,10 +56,10 @@ export class SmithScales {
|
|
|
44
56
|
.attr('data-role', 'scale-value')
|
|
45
57
|
.attr('x', this.start)
|
|
46
58
|
.attr('y', 25)
|
|
47
|
-
.attr('font-family', 'var(--smithkit-fontFamily)')
|
|
48
|
-
.attr('font-size', 'var(--smithkit-scales-
|
|
59
|
+
.attr('font-family', 'var(--smithkit-text-fontFamily)')
|
|
60
|
+
.attr('font-size', 'var(--smithkit-scales-value-fontSize)')
|
|
49
61
|
.attr('font-weight', 600)
|
|
50
|
-
.attr('fill', 'var(--smithkit-scales-
|
|
62
|
+
.attr('fill', 'var(--smithkit-scales-value-color)')
|
|
51
63
|
.text('—');
|
|
52
64
|
this.axes
|
|
53
65
|
.append('line')
|
|
@@ -56,7 +68,7 @@ export class SmithScales {
|
|
|
56
68
|
.attr('x2', this.start + this.length)
|
|
57
69
|
.attr('y1', 36)
|
|
58
70
|
.attr('y2', 36)
|
|
59
|
-
.attr('stroke', 'var(--smithkit-scales-
|
|
71
|
+
.attr('stroke', 'var(--smithkit-scales-line-color)')
|
|
60
72
|
.attr('stroke-width', 1);
|
|
61
73
|
const start = this.start;
|
|
62
74
|
const length = this.length;
|
|
@@ -70,7 +82,7 @@ export class SmithScales {
|
|
|
70
82
|
ticks
|
|
71
83
|
.append('line')
|
|
72
84
|
.attr('y2', 5)
|
|
73
|
-
.attr('stroke', 'var(--smithkit-scales-
|
|
85
|
+
.attr('stroke', 'var(--smithkit-scales-line-color)')
|
|
74
86
|
.attr('stroke-width', 1);
|
|
75
87
|
select(this)
|
|
76
88
|
.select('[data-role=labels]')
|
|
@@ -80,9 +92,9 @@ export class SmithScales {
|
|
|
80
92
|
.attr('transform', (value) => `translate(${start + length * scale.position(value)},36)`)
|
|
81
93
|
.append('text')
|
|
82
94
|
.attr('y', 17)
|
|
83
|
-
.attr('font-size', 'var(--smithkit-scales-fontSize)')
|
|
84
|
-
.attr('font-family', 'var(--smithkit-fontFamily)')
|
|
85
|
-
.attr('fill', 'var(--smithkit-scales-
|
|
95
|
+
.attr('font-size', 'var(--smithkit-scales-text-fontSize)')
|
|
96
|
+
.attr('font-family', 'var(--smithkit-text-fontFamily)')
|
|
97
|
+
.attr('fill', 'var(--smithkit-scales-text-color)')
|
|
86
98
|
.attr('text-anchor', (_, i) => i === 0 ? 'start' : i === scale.values.length - 1 ? 'end' : 'middle')
|
|
87
99
|
.text((value) => (value === Infinity ? '∞' : String(value)));
|
|
88
100
|
});
|
|
@@ -93,11 +105,20 @@ export class SmithScales {
|
|
|
93
105
|
.attr('cx', this.start)
|
|
94
106
|
.attr('cy', 36)
|
|
95
107
|
.attr('r', 4)
|
|
96
|
-
.attr('fill', 'var(--smithkit-scales-
|
|
97
|
-
.attr('stroke', 'var(--smithkit-scales-
|
|
108
|
+
.attr('fill', 'var(--smithkit-scales-indicator-color)')
|
|
109
|
+
.attr('stroke', 'var(--smithkit-scales-indicator-outline)')
|
|
98
110
|
.attr('stroke-width', 1);
|
|
99
111
|
labels.raise();
|
|
100
112
|
this.axes.append('title').text((scale) => scale.description ?? scale.title);
|
|
113
|
+
if (target !== undefined) {
|
|
114
|
+
try {
|
|
115
|
+
this.draw(target);
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
this.destroy();
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
101
122
|
}
|
|
102
123
|
/** Replace the preset and overrides without changing readings or layout. */
|
|
103
124
|
setAppearance(appearance) {
|
|
@@ -157,8 +178,8 @@ export class SmithScales {
|
|
|
157
178
|
: undefined, readout?.label
|
|
158
179
|
? {
|
|
159
180
|
text: readout.label,
|
|
160
|
-
color: style.getPropertyValue('--smithkit-scales-
|
|
161
|
-
fontFamily: style.getPropertyValue('--smithkit-fontFamily').trim(),
|
|
181
|
+
color: style.getPropertyValue('--smithkit-scales-text-color').trim(),
|
|
182
|
+
fontFamily: style.getPropertyValue('--smithkit-text-fontFamily').trim(),
|
|
162
183
|
}
|
|
163
184
|
: undefined);
|
|
164
185
|
return ImageExporter.svg([source], options);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SmithGroup } from '../svg/SmithGroup.js';
|
|
2
|
-
import type { TraceStyle, MarkerSelectionStrategy } from '../measurements.js';
|
|
2
|
+
import type { TraceStyle, TraceStyleOptions, MarkerSelectionStrategy } from '../measurements.js';
|
|
3
3
|
import { SmithMarker } from './SmithMarker.js';
|
|
4
4
|
import { SmithScaler } from '../svg/SmithScaler.js';
|
|
5
5
|
import type { TraceInput, TraceSample } from '../samples.js';
|
|
@@ -22,7 +22,7 @@ export declare class SmithData {
|
|
|
22
22
|
private selectHandler;
|
|
23
23
|
private visible;
|
|
24
24
|
private handler;
|
|
25
|
-
constructor(data: TraceInput, color: string, transform: TraceTransform, container: SmithGroup, scaler: SmithScaler, markerDragHandler?: ((marker: SmithMarker, dragging: boolean) => void) | undefined, markerContainer?: SmithGroup, style?:
|
|
25
|
+
constructor(data: TraceInput, color: string, transform: TraceTransform, container: SmithGroup, scaler: SmithScaler, markerDragHandler?: ((marker: SmithMarker, dragging: boolean) => void) | undefined, markerContainer?: SmithGroup, style?: TraceStyleOptions);
|
|
26
26
|
setViewportScale(scale: number): void;
|
|
27
27
|
zoom(transform: TraceTransform): void;
|
|
28
28
|
addMarker(sampleIndex?: number): number;
|
|
@@ -40,7 +40,7 @@ export declare class SmithData {
|
|
|
40
40
|
path: string;
|
|
41
41
|
} | undefined;
|
|
42
42
|
get Style(): TraceStyle;
|
|
43
|
-
setStyle(options:
|
|
43
|
+
setStyle(options: TraceStyleOptions): void;
|
|
44
44
|
setVisible(visible: boolean): void;
|
|
45
45
|
private moveMarker;
|
|
46
46
|
private updateReading;
|
|
@@ -54,8 +54,8 @@ export class SmithMarker extends SmithShape {
|
|
|
54
54
|
.attr('pointer-events', 'none')
|
|
55
55
|
.attr('aria-hidden', 'true');
|
|
56
56
|
for (const [stroke, width] of [
|
|
57
|
-
['var(--smithkit-marker-
|
|
58
|
-
['var(--smithkit-marker-
|
|
57
|
+
['var(--smithkit-marker-focus-halo)', 5],
|
|
58
|
+
['var(--smithkit-marker-focus-color)', 2.5],
|
|
59
59
|
]) {
|
|
60
60
|
this.focusRing
|
|
61
61
|
.append('circle')
|
|
@@ -67,17 +67,17 @@ export class SmithMarker extends SmithShape {
|
|
|
67
67
|
this.triangle = g
|
|
68
68
|
.append('polygon')
|
|
69
69
|
.attr('stroke', 'none')
|
|
70
|
-
.attr('fill', 'var(--smithkit-marker-
|
|
70
|
+
.attr('fill', 'var(--smithkit-marker-outline-color)');
|
|
71
71
|
this.inner = g.append('polygon').attr('stroke', 'none').attr('fill', color);
|
|
72
72
|
this.text = g
|
|
73
73
|
.append('text')
|
|
74
74
|
.attr('pointer-events', 'none')
|
|
75
75
|
.attr('aria-hidden', 'true')
|
|
76
|
-
.attr('font-family', 'var(--smithkit-fontFamily)')
|
|
76
|
+
.attr('font-family', 'var(--smithkit-text-fontFamily)')
|
|
77
77
|
.attr('font-weight', 'normal')
|
|
78
78
|
.attr('text-anchor', 'middle')
|
|
79
79
|
.attr('dominant-baseline', 'middle')
|
|
80
|
-
.attr('fill', 'var(--smithkit-marker-
|
|
80
|
+
.attr('fill', 'var(--smithkit-marker-text-color)')
|
|
81
81
|
.text(marker.toString());
|
|
82
82
|
this.zoom(1);
|
|
83
83
|
const drag = d3
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SmithGroup } from '../svg/SmithGroup.js';
|
|
2
2
|
import { SmithScaler } from '../svg/SmithScaler.js';
|
|
3
|
-
import type { TraceStyle } from '../measurements.js';
|
|
3
|
+
import type { TraceStyle, TraceStyleOptions } from '../measurements.js';
|
|
4
4
|
import { TraceBuffer } from './TraceBuffer.js';
|
|
5
5
|
export interface TraceTransform {
|
|
6
6
|
x: number;
|
|
@@ -19,7 +19,7 @@ export declare class TraceRenderer {
|
|
|
19
19
|
private group;
|
|
20
20
|
private lineDetail;
|
|
21
21
|
private lineIndices;
|
|
22
|
-
constructor(data: TraceBuffer, color: string, transform: TraceTransform, container: SmithGroup, scaler: SmithScaler, style?:
|
|
22
|
+
constructor(data: TraceBuffer, color: string, transform: TraceTransform, container: SmithGroup, scaler: SmithScaler, style?: TraceStyleOptions);
|
|
23
23
|
private drawTrace;
|
|
24
24
|
private selectLineIndices;
|
|
25
25
|
private linePath;
|
|
@@ -35,7 +35,7 @@ export declare class TraceRenderer {
|
|
|
35
35
|
private zoomDataPoints;
|
|
36
36
|
setColor(color: string): void;
|
|
37
37
|
get Style(): TraceStyle;
|
|
38
|
-
setStyle(options:
|
|
38
|
+
setStyle(options: TraceStyleOptions): void;
|
|
39
39
|
private redraw;
|
|
40
40
|
setVisible(visible: boolean): void;
|
|
41
41
|
update(data: TraceBuffer): void;
|
|
@@ -21,9 +21,8 @@ export class TraceRenderer {
|
|
|
21
21
|
this.scaler = scaler;
|
|
22
22
|
this.style = {
|
|
23
23
|
mode: style.mode ?? 'points',
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
lineTolerancePx: style.lineTolerancePx ?? 0,
|
|
24
|
+
line: { width: style.line?.width ?? 2, tolerancePx: style.line?.tolerancePx ?? 0 },
|
|
25
|
+
point: { radius: style.point?.radius ?? 2 },
|
|
27
26
|
};
|
|
28
27
|
this.group = this.drawTrace(data).attr('pointer-events', 'none');
|
|
29
28
|
container.append(this.group);
|
|
@@ -43,7 +42,7 @@ export class TraceRenderer {
|
|
|
43
42
|
.attr('d', this.linePath(this.lineIndices))
|
|
44
43
|
.attr('fill', 'none')
|
|
45
44
|
.attr('stroke', this.color)
|
|
46
|
-
.attr('stroke-width', this.style.
|
|
45
|
+
.attr('stroke-width', this.style.line.width)
|
|
47
46
|
.attr('vector-effect', 'non-scaling-stroke')
|
|
48
47
|
.attr('stroke-linejoin', 'round')
|
|
49
48
|
.attr('stroke-linecap', 'round');
|
|
@@ -54,14 +53,14 @@ export class TraceRenderer {
|
|
|
54
53
|
return group;
|
|
55
54
|
}
|
|
56
55
|
selectLineIndices() {
|
|
57
|
-
if (this.style.
|
|
56
|
+
if (this.style.line.tolerancePx === 0) {
|
|
58
57
|
return;
|
|
59
58
|
}
|
|
60
59
|
this.lineDetail ??= new TraceLineDetail(this.data);
|
|
61
60
|
const unitsToPixels = Math.max(Math.abs(this.scaler.x(1) - this.scaler.x(0)), Math.abs(this.scaler.y(1) - this.scaler.y(0))) *
|
|
62
61
|
this.transform.k *
|
|
63
62
|
this.viewportScale;
|
|
64
|
-
return this.lineDetail.select(this.style.
|
|
63
|
+
return this.lineDetail.select(this.style.line.tolerancePx / unitsToPixels);
|
|
65
64
|
}
|
|
66
65
|
linePath(indices) {
|
|
67
66
|
// Simplified paths retain numeric precision even at high zoom. Full paths keep
|
|
@@ -105,9 +104,9 @@ export class TraceRenderer {
|
|
|
105
104
|
renderPoints(group, data) {
|
|
106
105
|
const visible = [];
|
|
107
106
|
const cells = new Set();
|
|
108
|
-
const cellSize = Math.max(0.5, this.style.
|
|
107
|
+
const cellSize = Math.max(0.5, this.style.point.radius) / this.viewportScale;
|
|
109
108
|
const extent = this.scaler.x(1);
|
|
110
|
-
const margin = this.style.
|
|
109
|
+
const margin = this.style.point.radius / this.viewportScale;
|
|
111
110
|
const firstCell = Math.floor(-margin / cellSize);
|
|
112
111
|
const columns = Math.floor((extent + margin) / cellSize) - firstCell + 1;
|
|
113
112
|
for (let i = 0; i < data.length; i++) {
|
|
@@ -130,7 +129,7 @@ export class TraceRenderer {
|
|
|
130
129
|
.join('circle')
|
|
131
130
|
.attr('cx', (index) => this.scaler.x(data.real(index)))
|
|
132
131
|
.attr('cy', (index) => this.scaler.y(data.imaginary(index)))
|
|
133
|
-
.attr('r', this.style.
|
|
132
|
+
.attr('r', this.style.point.radius / (this.transform.k * this.viewportScale));
|
|
134
133
|
}
|
|
135
134
|
setViewportScale(scale) {
|
|
136
135
|
if (scale === this.viewportScale || !Number.isFinite(scale) || scale <= 0) {
|
|
@@ -153,7 +152,7 @@ export class TraceRenderer {
|
|
|
153
152
|
this.renderPoints(this.group, this.data);
|
|
154
153
|
}
|
|
155
154
|
else {
|
|
156
|
-
this.group.Element.selectAll('circle').attr('r', this.style.
|
|
155
|
+
this.group.Element.selectAll('circle').attr('r', this.style.point.radius / (k * this.viewportScale));
|
|
157
156
|
}
|
|
158
157
|
}
|
|
159
158
|
setColor(color) {
|
|
@@ -162,19 +161,21 @@ export class TraceRenderer {
|
|
|
162
161
|
this.group.Element.select('.trace-line').attr('stroke', color);
|
|
163
162
|
}
|
|
164
163
|
get Style() {
|
|
165
|
-
return { ...this.style };
|
|
164
|
+
return { ...this.style, line: { ...this.style.line }, point: { ...this.style.point } };
|
|
166
165
|
}
|
|
167
166
|
setStyle(options) {
|
|
168
167
|
const next = {
|
|
169
168
|
mode: options.mode ?? this.style.mode,
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
169
|
+
line: {
|
|
170
|
+
width: options.line?.width ?? this.style.line.width,
|
|
171
|
+
tolerancePx: options.line?.tolerancePx ?? this.style.line.tolerancePx,
|
|
172
|
+
},
|
|
173
|
+
point: { radius: options.point?.radius ?? this.style.point.radius },
|
|
173
174
|
};
|
|
174
175
|
if (next.mode === this.style.mode &&
|
|
175
|
-
next.
|
|
176
|
-
next.
|
|
177
|
-
next.
|
|
176
|
+
next.line.width === this.style.line.width &&
|
|
177
|
+
next.point.radius === this.style.point.radius &&
|
|
178
|
+
next.line.tolerancePx === this.style.line.tolerancePx) {
|
|
178
179
|
return;
|
|
179
180
|
}
|
|
180
181
|
const modeChanged = next.mode !== this.style.mode;
|
|
@@ -183,7 +184,7 @@ export class TraceRenderer {
|
|
|
183
184
|
this.redraw();
|
|
184
185
|
}
|
|
185
186
|
else {
|
|
186
|
-
this.group.Element.select('.trace-line').attr('stroke-width', next.
|
|
187
|
+
this.group.Element.select('.trace-line').attr('stroke-width', next.line.width);
|
|
187
188
|
this.zoomDataPoints();
|
|
188
189
|
}
|
|
189
190
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "smithkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Framework-independent, interactive Smith chart library for JavaScript and TypeScript",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
"react": "19.3.0",
|
|
58
58
|
"react-dom": "19.3.0",
|
|
59
59
|
"rxjs": "7.8.2",
|
|
60
|
+
"shiki": "4.5.0",
|
|
60
61
|
"typedoc": "0.28.20",
|
|
61
62
|
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
62
63
|
"typescript-eslint": "^8.71.0",
|