smithkit 0.4.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 +179 -15
- package/dist/lib/OptionsValidation.js +7 -3
- package/dist/lib/Smith.d.ts +7 -1
- package/dist/lib/Smith.js +16 -5
- package/dist/lib/index.d.ts +2 -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 +4 -0
- package/dist/lib/measurements.d.ts +2 -0
- package/dist/lib/options.d.ts +4 -0
- package/dist/lib/rendering/SvgChartRenderer.d.ts +3 -3
- package/dist/lib/rendering/SvgChartRenderer.js +27 -2
- 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 +2 -0
- 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
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** Nested radial-distance levels with a conservative accumulated error in Γ units. */
|
|
2
|
+
export class TraceLineDetail {
|
|
3
|
+
levels = [];
|
|
4
|
+
constructor(data) {
|
|
5
|
+
if (data.length < 3) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
// Reuse one scratch buffer; retained levels must shrink by at least 20%.
|
|
9
|
+
// This bounds cached index storage by a geometric series instead of levels × samples.
|
|
10
|
+
const scratch = new Uint32Array(data.length);
|
|
11
|
+
let previous;
|
|
12
|
+
let previousError = 0;
|
|
13
|
+
for (let exponent = -20; exponent <= 0; exponent++) {
|
|
14
|
+
const error = 2 ** exponent;
|
|
15
|
+
const allowance = error - previousError;
|
|
16
|
+
const squared = allowance * allowance;
|
|
17
|
+
const length = previous?.length ?? data.length;
|
|
18
|
+
let count = 1;
|
|
19
|
+
let last = 0;
|
|
20
|
+
scratch[0] = 0;
|
|
21
|
+
for (let position = 1; position < length - 1; position++) {
|
|
22
|
+
const index = previous ? previous[position] : position;
|
|
23
|
+
const dx = data.real(index) - data.real(last);
|
|
24
|
+
const dy = data.imaginary(index) - data.imaginary(last);
|
|
25
|
+
if (dx * dx + dy * dy > squared) {
|
|
26
|
+
scratch[count++] = index;
|
|
27
|
+
last = index;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
scratch[count++] = data.length - 1;
|
|
31
|
+
if (count <= length * 0.8) {
|
|
32
|
+
previous = scratch.slice(0, count);
|
|
33
|
+
previousError = error;
|
|
34
|
+
this.levels.push({ error, indices: previous });
|
|
35
|
+
}
|
|
36
|
+
if (count === 2) {
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Undefined means use every sample. No data scan or allocation during view selection. */
|
|
42
|
+
select(tolerance) {
|
|
43
|
+
let indices;
|
|
44
|
+
for (const level of this.levels) {
|
|
45
|
+
if (level.error > tolerance) {
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
indices = level.indices;
|
|
49
|
+
}
|
|
50
|
+
return indices;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import type { MarkerSelectionStrategy } from '../measurements.js';
|
|
2
2
|
import type { Point } from '../math/geometry.js';
|
|
3
|
-
import type {
|
|
3
|
+
import type { TraceInput } from '../samples.js';
|
|
4
|
+
import { TraceBuffer } from './TraceBuffer.js';
|
|
4
5
|
export interface TraceMarker {
|
|
5
6
|
readonly number: number;
|
|
6
|
-
|
|
7
|
+
sampleIndex: number;
|
|
7
8
|
}
|
|
8
9
|
/** Owns validated samples and marker selections without depending on SVG or D3. */
|
|
9
10
|
export declare class TraceModel {
|
|
10
11
|
private samples;
|
|
11
12
|
private markers;
|
|
12
13
|
private markerCount;
|
|
13
|
-
constructor(samples:
|
|
14
|
-
get Samples():
|
|
14
|
+
constructor(samples: TraceInput);
|
|
15
|
+
get Samples(): TraceBuffer;
|
|
15
16
|
get Markers(): readonly TraceMarker[];
|
|
16
17
|
addMarker(sampleIndex: number): TraceMarker;
|
|
17
18
|
removeMarker(index: number): TraceMarker | undefined;
|
|
@@ -22,10 +23,7 @@ export declare class TraceModel {
|
|
|
22
23
|
setMarkerFrequency(index: number, frequencyHz: number): TraceMarker | undefined;
|
|
23
24
|
/** Returns false when dragging still selects the same sample. */
|
|
24
25
|
selectNearestPoint(marker: TraceMarker, point: Readonly<Point>): boolean;
|
|
25
|
-
update(values:
|
|
26
|
+
update(values: TraceInput | TraceBuffer, strategy: MarkerSelectionStrategy): void;
|
|
26
27
|
clear(): void;
|
|
27
|
-
private nearestFrequencyIndex;
|
|
28
|
-
private nearestPoint;
|
|
29
28
|
private validateSampleIndex;
|
|
30
|
-
private copySamples;
|
|
31
29
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { TraceBuffer } from './TraceBuffer.js';
|
|
1
2
|
/** Owns validated samples and marker selections without depending on SVG or D3. */
|
|
2
3
|
export class TraceModel {
|
|
3
4
|
samples;
|
|
4
5
|
markers = [];
|
|
5
6
|
markerCount = 0;
|
|
6
7
|
constructor(samples) {
|
|
7
|
-
this.samples =
|
|
8
|
+
this.samples = TraceBuffer.from(samples);
|
|
8
9
|
}
|
|
9
10
|
get Samples() {
|
|
10
11
|
return this.samples;
|
|
@@ -14,7 +15,7 @@ export class TraceModel {
|
|
|
14
15
|
}
|
|
15
16
|
addMarker(sampleIndex) {
|
|
16
17
|
this.validateSampleIndex(sampleIndex);
|
|
17
|
-
const marker = { number: ++this.markerCount,
|
|
18
|
+
const marker = { number: ++this.markerCount, sampleIndex };
|
|
18
19
|
this.markers.push(marker);
|
|
19
20
|
return marker;
|
|
20
21
|
}
|
|
@@ -33,7 +34,7 @@ export class TraceModel {
|
|
|
33
34
|
}
|
|
34
35
|
markerSampleIndex(index) {
|
|
35
36
|
const marker = this.markers[index];
|
|
36
|
-
return marker
|
|
37
|
+
return marker?.sampleIndex ?? -1;
|
|
37
38
|
}
|
|
38
39
|
setMarkerSample(index, sampleIndex) {
|
|
39
40
|
const marker = this.markers[index];
|
|
@@ -41,7 +42,7 @@ export class TraceModel {
|
|
|
41
42
|
return;
|
|
42
43
|
}
|
|
43
44
|
this.validateSampleIndex(sampleIndex);
|
|
44
|
-
marker.
|
|
45
|
+
marker.sampleIndex = sampleIndex;
|
|
45
46
|
return marker;
|
|
46
47
|
}
|
|
47
48
|
setMarkerFrequency(index, frequencyHz) {
|
|
@@ -51,73 +52,47 @@ export class TraceModel {
|
|
|
51
52
|
if (!Number.isFinite(frequencyHz) || frequencyHz < 0) {
|
|
52
53
|
throw new RangeError('Marker frequency must be finite and non-negative.');
|
|
53
54
|
}
|
|
54
|
-
return this.setMarkerSample(index, this.
|
|
55
|
+
return this.setMarkerSample(index, this.samples.nearestFrequency(frequencyHz));
|
|
55
56
|
}
|
|
56
57
|
/** Returns false when dragging still selects the same sample. */
|
|
57
58
|
selectNearestPoint(marker, point) {
|
|
58
59
|
if (!this.markers.includes(marker)) {
|
|
59
60
|
return false;
|
|
60
61
|
}
|
|
61
|
-
const
|
|
62
|
-
if (
|
|
62
|
+
const sampleIndex = this.samples.nearestPoint(point);
|
|
63
|
+
if (sampleIndex === marker.sampleIndex) {
|
|
63
64
|
return false;
|
|
64
65
|
}
|
|
65
|
-
marker.
|
|
66
|
+
marker.sampleIndex = sampleIndex;
|
|
66
67
|
return true;
|
|
67
68
|
}
|
|
68
69
|
update(values, strategy) {
|
|
69
|
-
//
|
|
70
|
-
const samples =
|
|
71
|
-
const selectedIndices = this.markers.map((entry) =>
|
|
72
|
-
this.samples = samples;
|
|
73
|
-
this.markers.forEach((entry, index) => {
|
|
70
|
+
// Prepare every selection before replacing data so rejected updates are atomic.
|
|
71
|
+
const samples = values instanceof TraceBuffer ? values : TraceBuffer.from(values);
|
|
72
|
+
const selectedIndices = this.markers.map((entry) => {
|
|
74
73
|
if (strategy === 'sample-index') {
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
else if (strategy === 'reflection') {
|
|
78
|
-
entry.selectedPoint = this.nearestPoint(entry.selectedPoint.reflectionCoefficient);
|
|
74
|
+
return Math.min(entry.sampleIndex, samples.length - 1);
|
|
79
75
|
}
|
|
80
|
-
|
|
81
|
-
|
|
76
|
+
if (strategy === 'reflection') {
|
|
77
|
+
return samples.nearestPoint([
|
|
78
|
+
this.samples.real(entry.sampleIndex),
|
|
79
|
+
this.samples.imaginary(entry.sampleIndex),
|
|
80
|
+
]);
|
|
82
81
|
}
|
|
82
|
+
return samples.nearestFrequency(this.samples.frequency(entry.sampleIndex));
|
|
83
|
+
});
|
|
84
|
+
this.samples = samples;
|
|
85
|
+
this.markers.forEach((entry, index) => {
|
|
86
|
+
entry.sampleIndex = selectedIndices[index];
|
|
83
87
|
});
|
|
84
88
|
}
|
|
85
89
|
clear() {
|
|
86
|
-
this.samples =
|
|
90
|
+
this.samples = TraceBuffer.empty();
|
|
87
91
|
this.markers = [];
|
|
88
92
|
}
|
|
89
|
-
nearestFrequencyIndex(frequencyHz) {
|
|
90
|
-
let closest = 0;
|
|
91
|
-
let distance = Math.abs(this.samples[0].frequencyHz - frequencyHz);
|
|
92
|
-
for (let i = 1; i < this.samples.length; i++) {
|
|
93
|
-
const nextDistance = Math.abs(this.samples[i].frequencyHz - frequencyHz);
|
|
94
|
-
if (nextDistance < distance) {
|
|
95
|
-
closest = i;
|
|
96
|
-
distance = nextDistance;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
return closest;
|
|
100
|
-
}
|
|
101
|
-
nearestPoint(point) {
|
|
102
|
-
const distance = (sample) => Math.hypot(point[0] - sample.reflectionCoefficient[0], point[1] - sample.reflectionCoefficient[1]);
|
|
103
|
-
return this.samples.reduce((previous, current) => distance(previous) <= distance(current) ? previous : current);
|
|
104
|
-
}
|
|
105
93
|
validateSampleIndex(index) {
|
|
106
94
|
if (!Number.isInteger(index) || index < 0 || index >= this.samples.length) {
|
|
107
95
|
throw new RangeError('Sample index is outside this trace.');
|
|
108
96
|
}
|
|
109
97
|
}
|
|
110
|
-
copySamples(values) {
|
|
111
|
-
if (!values.length ||
|
|
112
|
-
values.some(({ frequencyHz, reflectionCoefficient }) => !Number.isFinite(frequencyHz) ||
|
|
113
|
-
frequencyHz < 0 ||
|
|
114
|
-
reflectionCoefficient.length !== 2 ||
|
|
115
|
-
!reflectionCoefficient.every(Number.isFinite))) {
|
|
116
|
-
throw new RangeError('A dataset requires samples with a non-negative finite frequency and two finite coordinates.');
|
|
117
|
-
}
|
|
118
|
-
return values.map(({ frequencyHz, reflectionCoefficient }) => ({
|
|
119
|
-
frequencyHz,
|
|
120
|
-
reflectionCoefficient: [reflectionCoefficient[0], reflectionCoefficient[1]],
|
|
121
|
-
}));
|
|
122
|
-
}
|
|
123
98
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SmithGroup } from '../svg/SmithGroup.js';
|
|
2
2
|
import { SmithScaler } from '../svg/SmithScaler.js';
|
|
3
3
|
import type { TraceStyle } from '../measurements.js';
|
|
4
|
-
import
|
|
4
|
+
import { TraceBuffer } from './TraceBuffer.js';
|
|
5
5
|
export interface TraceTransform {
|
|
6
6
|
x: number;
|
|
7
7
|
y: number;
|
|
@@ -17,8 +17,18 @@ export declare class TraceRenderer {
|
|
|
17
17
|
private viewportScale;
|
|
18
18
|
private visible;
|
|
19
19
|
private group;
|
|
20
|
-
|
|
20
|
+
private lineDetail;
|
|
21
|
+
private lineIndices;
|
|
22
|
+
constructor(data: TraceBuffer, color: string, transform: TraceTransform, container: SmithGroup, scaler: SmithScaler, style?: Partial<TraceStyle>);
|
|
21
23
|
private drawTrace;
|
|
24
|
+
private selectLineIndices;
|
|
25
|
+
private linePath;
|
|
26
|
+
private updateLine;
|
|
27
|
+
/** Replace geometry only in the export copy, never in the live SVG. */
|
|
28
|
+
fullExportLine(): {
|
|
29
|
+
node: SVGElement;
|
|
30
|
+
path: string;
|
|
31
|
+
} | undefined;
|
|
22
32
|
private renderPoints;
|
|
23
33
|
setViewportScale(scale: number): void;
|
|
24
34
|
zoom(transform: TraceTransform): void;
|
|
@@ -28,6 +38,6 @@ export declare class TraceRenderer {
|
|
|
28
38
|
setStyle(options: Partial<TraceStyle>): void;
|
|
29
39
|
private redraw;
|
|
30
40
|
setVisible(visible: boolean): void;
|
|
31
|
-
update(data:
|
|
41
|
+
update(data: TraceBuffer): void;
|
|
32
42
|
destroy(): void;
|
|
33
43
|
}
|
|
@@ -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",
|