smithkit 0.3.0 → 0.5.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 +324 -37
- package/dist/lib/OptionsValidation.d.ts +16 -0
- package/dist/lib/OptionsValidation.js +172 -0
- package/dist/lib/Smith.d.ts +20 -5
- package/dist/lib/Smith.js +114 -15
- package/dist/lib/appearance/Theme.js +5 -0
- package/dist/lib/grid/CircleLayerControl.d.ts +1 -1
- package/dist/lib/grid/CircleLayerControl.js +10 -8
- package/dist/lib/grid/ConstQCircles.d.ts +1 -0
- package/dist/lib/grid/ConstQCircles.js +5 -0
- package/dist/lib/grid/ConstSwrCircles.d.ts +1 -0
- package/dist/lib/grid/ConstSwrCircles.js +5 -0
- package/dist/lib/grid/GridLayerControl.js +5 -4
- package/dist/lib/grid/LayerControl.d.ts +1 -2
- package/dist/lib/grid/LayerControl.js +1 -10
- package/dist/lib/index.d.ts +3 -2
- package/dist/lib/io/Touchstone.d.ts +13 -7
- package/dist/lib/io/Touchstone.js +146 -46
- package/dist/lib/io/types.d.ts +17 -0
- package/dist/lib/io/types.js +1 -0
- package/dist/lib/layers.d.ts +7 -1
- package/dist/lib/measurements.d.ts +2 -0
- package/dist/lib/options.d.ts +58 -0
- package/dist/lib/options.js +1 -0
- package/dist/lib/rendering/SvgChartRenderer.d.ts +6 -3
- package/dist/lib/rendering/SvgChartRenderer.js +58 -11
- package/dist/lib/rf/RfCalculations.d.ts +3 -1
- package/dist/lib/rf/RfCalculations.js +23 -6
- package/dist/lib/samples.d.ts +5 -1
- package/dist/lib/scales/SmithPeripheralScales.d.ts +5 -0
- package/dist/lib/scales/SmithPeripheralScales.js +20 -1
- package/dist/lib/svg/SvgExporter.d.ts +1 -1
- package/dist/lib/svg/SvgExporter.js +4 -3
- package/dist/lib/svg/export.d.ts +3 -1
- package/dist/lib/traces/SmithData.d.ts +10 -4
- package/dist/lib/traces/SmithData.js +14 -4
- package/dist/lib/traces/TraceBuffer.d.ts +19 -0
- package/dist/lib/traces/TraceBuffer.js +176 -0
- package/dist/lib/traces/TraceLineDetail.d.ts +8 -0
- package/dist/lib/traces/TraceLineDetail.js +52 -0
- package/dist/lib/traces/TraceModel.d.ts +6 -8
- package/dist/lib/traces/TraceModel.js +24 -49
- package/dist/lib/traces/TraceRenderer.d.ts +13 -3
- package/dist/lib/traces/TraceRenderer.js +83 -23
- package/package.json +4 -2
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { path, pathRound } from 'd3';
|
|
2
2
|
import { SmithGroup } from '../svg/SmithGroup.js';
|
|
3
|
+
import { TraceLineDetail } from './TraceLineDetail.js';
|
|
4
|
+
import { TraceBuffer } from './TraceBuffer.js';
|
|
3
5
|
/** Draws a trace; sample validation and marker selection belong to TraceModel. */
|
|
4
6
|
export class TraceRenderer {
|
|
5
7
|
data;
|
|
@@ -10,6 +12,8 @@ export class TraceRenderer {
|
|
|
10
12
|
viewportScale = 1;
|
|
11
13
|
visible = true;
|
|
12
14
|
group;
|
|
15
|
+
lineDetail;
|
|
16
|
+
lineIndices;
|
|
13
17
|
constructor(data, color, transform, container, scaler, style = {}) {
|
|
14
18
|
this.data = data;
|
|
15
19
|
this.color = color;
|
|
@@ -19,6 +23,7 @@ export class TraceRenderer {
|
|
|
19
23
|
mode: style.mode ?? 'points',
|
|
20
24
|
lineWidth: style.lineWidth ?? 2,
|
|
21
25
|
pointRadius: style.pointRadius ?? 2,
|
|
26
|
+
lineTolerancePx: style.lineTolerancePx ?? 0,
|
|
22
27
|
};
|
|
23
28
|
this.group = this.drawTrace(data).attr('pointer-events', 'none');
|
|
24
29
|
container.append(this.group);
|
|
@@ -32,12 +37,10 @@ export class TraceRenderer {
|
|
|
32
37
|
group.attr('data-role', 'samples');
|
|
33
38
|
group.attr('data-mode', this.style.mode);
|
|
34
39
|
if (this.style.mode !== 'points') {
|
|
35
|
-
|
|
36
|
-
.x((sample) => this.scaler.x(sample.reflectionCoefficient[0]))
|
|
37
|
-
.y((sample) => this.scaler.y(sample.reflectionCoefficient[1]));
|
|
40
|
+
this.lineIndices = this.selectLineIndices();
|
|
38
41
|
group.Element.append('path')
|
|
39
42
|
.attr('class', 'trace-line')
|
|
40
|
-
.attr('d',
|
|
43
|
+
.attr('d', this.linePath(this.lineIndices))
|
|
41
44
|
.attr('fill', 'none')
|
|
42
45
|
.attr('stroke', this.color)
|
|
43
46
|
.attr('stroke-width', this.style.lineWidth)
|
|
@@ -50,32 +53,83 @@ export class TraceRenderer {
|
|
|
50
53
|
}
|
|
51
54
|
return group;
|
|
52
55
|
}
|
|
56
|
+
selectLineIndices() {
|
|
57
|
+
if (this.style.lineTolerancePx === 0) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
this.lineDetail ??= new TraceLineDetail(this.data);
|
|
61
|
+
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
|
+
this.transform.k *
|
|
63
|
+
this.viewportScale;
|
|
64
|
+
return this.lineDetail.select(this.style.lineTolerancePx / unitsToPixels);
|
|
65
|
+
}
|
|
66
|
+
linePath(indices) {
|
|
67
|
+
// Simplified paths retain numeric precision even at high zoom. Full paths keep
|
|
68
|
+
// the existing SVG serialization; the tolerance measures additional simplification.
|
|
69
|
+
const line = indices ? path() : pathRound(3);
|
|
70
|
+
const length = indices?.length ?? this.data.length;
|
|
71
|
+
for (let position = 0; position < length; position++) {
|
|
72
|
+
const index = indices ? indices[position] : position;
|
|
73
|
+
const x = this.scaler.x(this.data.real(index));
|
|
74
|
+
const y = this.scaler.y(this.data.imaginary(index));
|
|
75
|
+
if (position === 0) {
|
|
76
|
+
line.moveTo(x, y);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
line.lineTo(x, y);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (length === 1) {
|
|
83
|
+
line.closePath();
|
|
84
|
+
}
|
|
85
|
+
return line.toString();
|
|
86
|
+
}
|
|
87
|
+
updateLine() {
|
|
88
|
+
if (this.style.mode === 'points') {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const indices = this.selectLineIndices();
|
|
92
|
+
if (indices !== this.lineIndices) {
|
|
93
|
+
this.lineIndices = indices;
|
|
94
|
+
this.group.Element.select('.trace-line').attr('d', this.linePath(indices));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** Replace geometry only in the export copy, never in the live SVG. */
|
|
98
|
+
fullExportLine() {
|
|
99
|
+
const node = this.group.Element.select('.trace-line').node();
|
|
100
|
+
if (node && this.lineIndices) {
|
|
101
|
+
return { node, path: this.linePath() };
|
|
102
|
+
}
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
53
105
|
renderPoints(group, data) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
106
|
+
const visible = [];
|
|
107
|
+
const cells = new Set();
|
|
108
|
+
const cellSize = Math.max(0.5, this.style.pointRadius) / this.viewportScale;
|
|
109
|
+
const extent = this.scaler.x(1);
|
|
110
|
+
const margin = this.style.pointRadius / this.viewportScale;
|
|
111
|
+
const firstCell = Math.floor(-margin / cellSize);
|
|
112
|
+
const columns = Math.floor((extent + margin) / cellSize) - firstCell + 1;
|
|
113
|
+
for (let i = 0; i < data.length; i++) {
|
|
114
|
+
if (data.length > 5000) {
|
|
115
|
+
const x = this.scaler.x(data.real(i)) * this.transform.k + this.transform.x;
|
|
116
|
+
const y = this.scaler.y(data.imaginary(i)) * this.transform.k + this.transform.y;
|
|
63
117
|
if (x < -margin || y < -margin || x > extent + margin || y > extent + margin) {
|
|
64
|
-
|
|
118
|
+
continue;
|
|
65
119
|
}
|
|
66
|
-
const cell =
|
|
120
|
+
const cell = (Math.floor(y / cellSize) - firstCell) * columns + Math.floor(x / cellSize) - firstCell;
|
|
67
121
|
if (cells.has(cell)) {
|
|
68
|
-
|
|
122
|
+
continue;
|
|
69
123
|
}
|
|
70
124
|
cells.add(cell);
|
|
71
|
-
|
|
72
|
-
|
|
125
|
+
}
|
|
126
|
+
visible.push(i);
|
|
73
127
|
}
|
|
74
128
|
group.Element.selectAll('circle')
|
|
75
129
|
.data(visible)
|
|
76
130
|
.join('circle')
|
|
77
|
-
.attr('cx', (
|
|
78
|
-
.attr('cy', (
|
|
131
|
+
.attr('cx', (index) => this.scaler.x(data.real(index)))
|
|
132
|
+
.attr('cy', (index) => this.scaler.y(data.imaginary(index)))
|
|
79
133
|
.attr('r', this.style.pointRadius / (this.transform.k * this.viewportScale));
|
|
80
134
|
}
|
|
81
135
|
setViewportScale(scale) {
|
|
@@ -90,6 +144,7 @@ export class TraceRenderer {
|
|
|
90
144
|
this.zoomDataPoints();
|
|
91
145
|
}
|
|
92
146
|
zoomDataPoints() {
|
|
147
|
+
this.updateLine();
|
|
93
148
|
const k = this.transform.k;
|
|
94
149
|
if (this.style.mode === 'line') {
|
|
95
150
|
return;
|
|
@@ -114,10 +169,12 @@ export class TraceRenderer {
|
|
|
114
169
|
mode: options.mode ?? this.style.mode,
|
|
115
170
|
lineWidth: options.lineWidth ?? this.style.lineWidth,
|
|
116
171
|
pointRadius: options.pointRadius ?? this.style.pointRadius,
|
|
172
|
+
lineTolerancePx: options.lineTolerancePx ?? this.style.lineTolerancePx,
|
|
117
173
|
};
|
|
118
174
|
if (next.mode === this.style.mode &&
|
|
119
175
|
next.lineWidth === this.style.lineWidth &&
|
|
120
|
-
next.pointRadius === this.style.pointRadius
|
|
176
|
+
next.pointRadius === this.style.pointRadius &&
|
|
177
|
+
next.lineTolerancePx === this.style.lineTolerancePx) {
|
|
121
178
|
return;
|
|
122
179
|
}
|
|
123
180
|
const modeChanged = next.mode !== this.style.mode;
|
|
@@ -143,10 +200,13 @@ export class TraceRenderer {
|
|
|
143
200
|
}
|
|
144
201
|
update(data) {
|
|
145
202
|
this.data = data;
|
|
203
|
+
this.lineDetail = undefined;
|
|
146
204
|
this.redraw();
|
|
147
205
|
}
|
|
148
206
|
destroy() {
|
|
149
|
-
this.
|
|
207
|
+
this.lineDetail = undefined;
|
|
208
|
+
this.lineIndices = undefined;
|
|
209
|
+
this.data = TraceBuffer.empty();
|
|
150
210
|
this.group.Element.remove();
|
|
151
211
|
}
|
|
152
212
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "smithkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Framework-independent, interactive Smith chart library for JavaScript and TypeScript",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
"format:check": "prettier . --check",
|
|
22
22
|
"check:package": "node scripts/check-package.mjs",
|
|
23
23
|
"check:example": "node scripts/check-example.mjs",
|
|
24
|
-
"prepare:release": "node scripts/prepare-release.mjs"
|
|
24
|
+
"prepare:release": "node scripts/prepare-release.mjs",
|
|
25
|
+
"benchmark:traces": "node scripts/benchmark-traces.mjs",
|
|
26
|
+
"benchmark:workloads": "node scripts/benchmark-workloads.mjs"
|
|
25
27
|
},
|
|
26
28
|
"dependencies": {
|
|
27
29
|
"@types/d3": "^7.4.3",
|