Skip to content

Commit 4a66de2

Browse files
committed
feat(rtsa): ✨ configurable canvas sizes, marker detection, and UI tweaks
- introduce width/height parameters on RTSAScreen and use them to size canvases (higher resolution) - pass explicit sizes to SpectralDensityPlot and WaterfallDisplay for single/both modes - compute topMarkers, select highest markerIndex, and draw selected marker; add isUpdateMarkers flag - add marker navigation and logging in ACMkrBtn - refactor info bar markup/CSS and add config button; adjust canvas height and label fonts - remove noisy Logger.warn from continuous rotary knob wheel handler
1 parent 3183ce7 commit 4a66de2

7 files changed

Lines changed: 201 additions & 72 deletions

File tree

src/components/rotary-knob/continuous-rotary-knob.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { html } from "@app/engine/utils/development/formatter";
22
import { qs } from "@app/engine/utils/query-selector";
33
import { EventBus } from "@app/events/event-bus";
44
import { Events } from "@app/events/events";
5-
import { Logger } from "@app/logging/logger";
65
import './continuous-rotary-knob.css';
76

87
export class ContinuousRotaryKnob {
@@ -86,8 +85,6 @@ export class ContinuousRotaryKnob {
8685
e.preventDefault();
8786
const delta = -Math.sign(e.deltaY) * this.step;
8887

89-
Logger.warn('ContinuousRotaryKnob', `Wheel event delta: ${delta}`);
90-
9188
this.setAngle_(this.angle + delta);
9289
}
9390

src/equipment/real-time-spectrum-analyzer/analyzer-control/ac-mkr-btn/ac-mkr-btn.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Logger } from "@app/logging/logger";
12
import { AnalyzerControl } from "../../analyzer-control";
23
import { BaseControlButton } from "../base-control-button";
34
import './ac-mkr-btn.css';
@@ -21,8 +22,33 @@ export class ACMkrBtn extends BaseControlButton {
2122

2223
this.analyzerControl.specA.state.isMarkerOn = !this.analyzerControl.specA.state.isMarkerOn;
2324

25+
// Trigger marker update if marker is turned on
26+
this.analyzerControl.specA.state.isUpdateMarkers = this.analyzerControl.specA.state.isMarkerOn;
27+
2428
// Note: Marker drawing would need to be implemented in SpectrumAnalyzer
2529

2630
this.playSound();
2731
}
32+
33+
onMajorTickChange(value: number): void {
34+
// Positive value means increment marker index, negative means decrement
35+
this.changeMarkerIndex(value < 0 ? 1 : -1);
36+
}
37+
38+
onMinorTickChange(value: number): void {
39+
// Positive value means increment marker index, negative means decrement
40+
this.changeMarkerIndex(value < 0 ? 1 : -1);
41+
}
42+
43+
private changeMarkerIndex(delta: number): void {
44+
if (!this.analyzerControl.specA.state.isMarkerOn || this.analyzerControl.specA.state.topMarkers.length === 0) {
45+
return;
46+
}
47+
48+
const numMarkers = this.analyzerControl.specA.state.topMarkers.length;
49+
this.analyzerControl.specA.state.markerIndex =
50+
(this.analyzerControl.specA.state.markerIndex + delta + numMarkers) % numMarkers;
51+
52+
Logger.info('ACMkrBtn', 'changeMarkerIndex', `Marker index changed to ${this.analyzerControl.specA.state.markerIndex}`);
53+
}
2854
}

src/equipment/real-time-spectrum-analyzer/real-time-spectrum-analyzer.css

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
.spec-a-canvas-container canvas.spec-a-canvas-single {
3030
display: block;
3131
width: 100%;
32-
height: 400px;
32+
height: 460px;
3333
}
3434

3535
/* Both mode canvases */
@@ -46,15 +46,39 @@
4646
}
4747

4848
/* Info Section */
49-
.spec-a-info {
49+
.spec-a-info-bar {
5050
display: flex;
51-
justify-content: space-around;
52-
margin-bottom: 12px;
51+
justify-content: space-between;
52+
align-items: center;
53+
width: auto;
54+
border-radius: 4px;
55+
margin: 0 8px 12px 8px;
5356
padding: 8px;
5457
background-color: #1a1a1a;
55-
border-radius: 4px;
56-
color: #fff;
57-
font-size: 14px;
58+
59+
.btn-config {
60+
top: 8px;
61+
right: 8px;
62+
z-index: 10;
63+
background: rgba(0, 0, 0, 0.7);
64+
border: none;
65+
color: #fff;
66+
padding: 2px 12px;
67+
font-size: 28px;
68+
font-weight: bold;
69+
border-radius: 4px;
70+
cursor: pointer;
71+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
72+
text-shadow: 0 1px 2px #000, 0 0 2px #fff;
73+
}
74+
75+
.spec-a-info {
76+
display: flex;
77+
justify-content: space-around;
78+
color: #fff;
79+
font-size: 14px;
80+
flex: 1;
81+
}
5882
}
5983

6084
.spec-a-info div {
@@ -77,22 +101,6 @@
77101
color: #fff;
78102
}
79103

80-
.spec-a-controls button:hover {
81-
filter: brightness(1.1);
82-
}
83-
84-
.btn-mode-screen {
85-
min-width: 160px;
86-
}
87-
88-
.btn-mode-if-rf {
89-
width: 65px;
90-
}
91-
92-
.btn-pause.active {
93-
background-color: #f44336;
94-
color: #fff;
95-
}
96104

97105
/* Responsive adjustments */
98106
@media (max-width: 768px) {

src/equipment/real-time-spectrum-analyzer/real-time-spectrum-analyzer.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import './real-time-spectrum-analyzer.css';
1111
import { SpectralDensityPlot } from './rtsa-screen/spectral-density-plot';
1212
import { WaterfallDisplay } from "./rtsa-screen/waterfall-display";
1313

14+
type MarkerPoint = { x: number; y: number; signal: number };
15+
1416
export interface RealTimeSpectrumAnalyzerState {
1517
/** This is the reference level that all dBm values are relative to */
1618
referenceLevel: number;
@@ -28,6 +30,9 @@ export interface RealTimeSpectrumAnalyzerState {
2830
isMaxHold: boolean;
2931
isMinHold: boolean;
3032
isMarkerOn: boolean;
33+
isUpdateMarkers: boolean;
34+
topMarkers: MarkerPoint[];
35+
markerIndex: number;
3136
refreshRate: number; // in Hz
3237
centerFrequency: Hertz; // Hz - center frequency
3338
span: Hertz;
@@ -74,6 +79,9 @@ export class RealTimeSpectrumAnalyzer extends BaseEquipment {
7479
isMaxHold: false,
7580
isMinHold: false,
7681
isMarkerOn: false,
82+
isUpdateMarkers: false,
83+
topMarkers: [],
84+
markerIndex: 0,
7785

7886
referenceLevel: 0, // dBm
7987

@@ -127,22 +135,22 @@ export class RealTimeSpectrumAnalyzer extends BaseEquipment {
127135
<canvas id="specA${this.uuid}-waterfall" width="747" height="200" class="spec-a-canvas-waterfall"></canvas>
128136
</div>
129137
130-
<div class="spec-a-info">
131-
<div>CF: ${this.state.centerFrequency / 1e6} MHz</div>
132-
<div>Input: ${this.state.inputValue} ${this.state.inputUnit}</div>
133-
<div>RF Front End: ${this.state.rfFeUuid.split('-')[0]}</div>
138+
<div class="spec-a-info-bar">
139+
<button class="btn-config" data-action="config" title="Open Configuration Panel">
140+
<span class="icon-advanced">&#9881;</span>
141+
</button>
142+
<div class="spec-a-info">
143+
<div>CF: ${this.state.centerFrequency / 1e6} MHz</div>
144+
<div>Input: ${this.state.inputValue} ${this.state.inputUnit}</div>
145+
<div>RF Front End: ${this.state.rfFeUuid.split('-')[0]}</div>
146+
</div>
134147
</div>
135148
136149
<!-- Bottom Status Bar -->
137150
<div class="equipment-case-footer">
138151
<div class="bottom-status-bar">
139152
SYSTEM NORMAL
140153
</div>
141-
<div>
142-
<button class="btn-config" data-action="config" title="Open Configuration Panel">
143-
<span class="icon-advanced">&#9881;</span>
144-
</button>
145-
</div>
146154
</div>
147155
</div>
148156
`;
@@ -192,12 +200,12 @@ export class RealTimeSpectrumAnalyzer extends BaseEquipment {
192200
if (!this.domCache['canvasWaterfall']) throw new Error('Waterfall canvas element not found for Spectrum Analyzer');
193201

194202
// Initialize single-mode screens
195-
this.spectralDensity = new SpectralDensityPlot(this.domCache['canvas'] as HTMLCanvasElement, this);
196-
this.waterfall = new WaterfallDisplay(this.domCache['canvas'] as HTMLCanvasElement, this);
203+
this.spectralDensity = new SpectralDensityPlot(this.domCache['canvas'] as HTMLCanvasElement, this, 1600, 1000);
204+
this.waterfall = new WaterfallDisplay(this.domCache['canvas'] as HTMLCanvasElement, this, 1600, 1000);
197205

198206
// Initialize "both" mode screens with their dedicated canvases
199-
this.spectralDensityBoth = new SpectralDensityPlot(this.domCache['canvasSpectral'] as HTMLCanvasElement, this);
200-
this.waterfallBoth = new WaterfallDisplay(this.domCache['canvasWaterfall'] as HTMLCanvasElement, this);
207+
this.spectralDensityBoth = new SpectralDensityPlot(this.domCache['canvasSpectral'] as HTMLCanvasElement, this, 1600, 500);
208+
this.waterfallBoth = new WaterfallDisplay(this.domCache['canvasWaterfall'] as HTMLCanvasElement, this, 1600, 500);
201209

202210
// Set initial screen mode
203211
this.updateScreenVisibility();

src/equipment/real-time-spectrum-analyzer/rtsa-screen/rtsa-screen.ts

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Logger } from "@app/logging/logger";
12
import { RealTimeSpectrumAnalyzer } from "../real-time-spectrum-analyzer";
23

34
export abstract class RTSAScreen {
@@ -7,14 +8,18 @@ export abstract class RTSAScreen {
78
protected readonly specA: RealTimeSpectrumAnalyzer;
89

910
// Canvas dimensions
10-
protected width: number = 1600; // More width to increase resolution (especially for noise floor)
11-
protected height: number = 400;
11+
protected width_: number = 1600; // More width to increase resolution (especially for noise floor)
12+
protected height_: number = 460;
1213

13-
constructor(canvas: HTMLCanvasElement, specA: RealTimeSpectrumAnalyzer) {
14+
constructor(canvas: HTMLCanvasElement, specA: RealTimeSpectrumAnalyzer, width = 1600, height = 1000) {
1415
this.canvas = canvas;
1516
this.specA = specA;
16-
this.width = canvas.width;
17-
this.height = canvas.height;
17+
this.width_ = width;
18+
this.height_ = height;
19+
this.canvas.width = this.width_;
20+
this.canvas.height = this.height_;
21+
22+
Logger.info('RTSAScreen', 'constructor', `Canvas initialized with width=${this.width_}, height=${this.height_}`);
1823

1924
const context = this.canvas.getContext('2d');
2025
if (!context) {
@@ -23,6 +28,24 @@ export abstract class RTSAScreen {
2328
this.ctx = context;
2429
}
2530

31+
get width(): number {
32+
return this.width_;
33+
}
34+
35+
get height(): number {
36+
return this.height_;
37+
}
38+
39+
set width(value: number) {
40+
this.width_ = value;
41+
Logger.warn('RTSAScreen', 'set width', `Width set to ${value}, resizing canvas`);
42+
}
43+
44+
set height(value: number) {
45+
this.height_ = value;
46+
Logger.warn('RTSAScreen', 'set height', `Height set to ${value}, resizing canvas`);
47+
}
48+
2649
public resetMaxHold(): void {
2750
// To be implemented by subclasses if needed
2851
}

0 commit comments

Comments
 (0)