@rfkit/charts 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +1 -1
  2. package/charts/Spectrum/heatmapCaptureDefaults.d.ts +2 -0
  3. package/components/Cursor/useCursorSample.d.ts +2 -0
  4. package/components/EventBus/position.d.ts +8 -0
  5. package/components/EventBus/tools.d.ts +2 -1
  6. package/components/Overlay/Popover/index.d.ts +1 -0
  7. package/components/Toolbar/icons/DeltaMeasurementIcon.d.ts +3 -0
  8. package/components/Toolbar/icons/index.d.ts +1 -0
  9. package/components/ui/cursor-follow-layer.d.ts +1 -2
  10. package/config/setting.d.ts +1 -0
  11. package/hooks/spectrum/index.d.ts +1 -0
  12. package/hooks/spectrum/waterfall.d.ts +5 -0
  13. package/index.d.ts +2 -2
  14. package/index.js +1158 -398
  15. package/modules/Heatmap/cursorValue.d.ts +38 -0
  16. package/modules/Occupancy/CursorPopover.d.ts +4 -1
  17. package/modules/Spectrum/FrequencyAllocation/model/channelModel.d.ts +16 -0
  18. package/modules/Spectrum/FrequencyAllocation/model/density.d.ts +13 -0
  19. package/modules/Spectrum/FrequencyAllocation/model/index.d.ts +4 -3
  20. package/modules/Spectrum/FrequencyAllocation/model/resolveFrequencyAllocationData.d.ts +7 -1
  21. package/modules/Spectrum/FrequencyAllocation/model/resolver.d.ts +26 -1
  22. package/modules/Spectrum/FrequencyAllocation/model/useAllocationAtCursor.d.ts +3 -1
  23. package/modules/Spectrum/FrequencyAllocation/model/useFrequencyAllocationData.d.ts +1 -0
  24. package/modules/Spectrum/FrequencyAllocation/overlays/Tooltip/index.d.ts +8 -1
  25. package/modules/Spectrum/FrequencyAllocation/presenters/AllocationInfo/index.d.ts +1 -0
  26. package/modules/Spectrum/FrequencyAllocation/presenters/AllocationSegments/index.d.ts +3 -3
  27. package/modules/Spectrum/FrequencyAllocation/tools.d.ts +11 -1
  28. package/modules/Spectrum/FrequencyAllocation/types.d.ts +3 -0
  29. package/modules/Spectrum/FrequencyDataBoard/index.d.ts +2 -0
  30. package/modules/Spectrum/Limit/thresholdStyle.d.ts +6 -0
  31. package/modules/Spectrum/Signal/index.d.ts +1 -0
  32. package/modules/Spectrum/Signal/model/index.d.ts +1 -1
  33. package/modules/Spectrum/Signal/model/resolver.d.ts +25 -0
  34. package/modules/Spectrum/Signal/model/useStationInfoAtCursor.d.ts +3 -1
  35. package/modules/Spectrum/useSpectrumAnalyzer/thresholdData.d.ts +8 -0
  36. package/package.json +1 -1
  37. package/runtime/interaction/index.d.ts +71 -0
  38. package/types/store/frequency.d.ts +8 -0
  39. package/types/store/heatmap.d.ts +2 -0
package/index.js CHANGED
@@ -571,6 +571,22 @@ var __webpack_modules__ = {
571
571
  z-index: 1000;
572
572
  }
573
573
 
574
+ [data-rfkit-charts-root] .row-0 {
575
+ grid-row: 0;
576
+ }
577
+
578
+ [data-rfkit-charts-root] .row-1 {
579
+ grid-row: 1;
580
+ }
581
+
582
+ [data-rfkit-charts-root] .row-2 {
583
+ grid-row: 2;
584
+ }
585
+
586
+ [data-rfkit-charts-root] .row-3 {
587
+ grid-row: 3;
588
+ }
589
+
574
590
  [data-rfkit-charts-root] .container {
575
591
  width: 100%;
576
592
  }
@@ -1413,6 +1429,10 @@ var __webpack_modules__ = {
1413
1429
  }
1414
1430
  }
1415
1431
 
1432
+ [data-rfkit-charts-root] .border-primary\\/50 {
1433
+ border-color: var(--primary);
1434
+ }
1435
+
1416
1436
  @supports (color: color-mix(in lab, red, red)) {
1417
1437
  [data-rfkit-charts-root] .border-primary\\/50 {
1418
1438
  border-color: color-mix(in oklab, var(--primary) 50%, transparent);
@@ -2684,34 +2704,34 @@ var __webpack_modules__ = {
2684
2704
  translate: var(--tw-translate-x) var(--tw-translate-y);
2685
2705
  }
2686
2706
 
2687
- @media (min-width: 40rem) {
2688
- [data-rfkit-charts-root] .sm\\:flex-row {
2689
- flex-direction: row;
2690
- }
2691
-
2692
- [data-rfkit-charts-root] .sm\\:justify-end {
2693
- justify-content: flex-end;
2694
- }
2695
- }
2696
-
2697
- @media (min-width: 80rem) {
2698
- [data-rfkit-charts-root] .xl\\:grid-cols-\\[220px_minmax\\(0\\,1\\.2fr\\)_320px\\] {
2707
+ @media (min-width: 1180px) {
2708
+ [data-rfkit-charts-root] .min-\\[1180px\\]\\:grid-cols-\\[220px_minmax\\(0\\,1\\.2fr\\)_320px\\] {
2699
2709
  grid-template-columns: 220px minmax(0, 1.2fr) 320px;
2700
2710
  }
2701
2711
 
2702
- [data-rfkit-charts-root] .xl\\:grid-cols-\\[minmax\\(0\\,1\\.2fr\\)_auto_auto\\] {
2712
+ [data-rfkit-charts-root] .min-\\[1180px\\]\\:grid-cols-\\[minmax\\(0\\,1\\.2fr\\)_auto_auto\\] {
2703
2713
  grid-template-columns: minmax(0, 1.2fr) auto auto;
2704
2714
  }
2705
2715
 
2706
- [data-rfkit-charts-root] .xl\\:grid-cols-\\[minmax\\(0\\,1\\.35fr\\)_320px\\] {
2716
+ [data-rfkit-charts-root] .min-\\[1180px\\]\\:grid-cols-\\[minmax\\(0\\,1\\.35fr\\)_320px\\] {
2707
2717
  grid-template-columns: minmax(0, 1.35fr) 320px;
2708
2718
  }
2709
2719
 
2710
- [data-rfkit-charts-root] .xl\\:grid-cols-\\[minmax\\(0\\,1fr\\)_minmax\\(0\\,1fr\\)\\] {
2720
+ [data-rfkit-charts-root] .min-\\[1180px\\]\\:grid-cols-\\[minmax\\(0\\,1fr\\)_minmax\\(0\\,1fr\\)\\] {
2711
2721
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
2712
2722
  }
2713
2723
  }
2714
2724
 
2725
+ @media (min-width: 40rem) {
2726
+ [data-rfkit-charts-root] .sm\\:flex-row {
2727
+ flex-direction: row;
2728
+ }
2729
+
2730
+ [data-rfkit-charts-root] .sm\\:justify-end {
2731
+ justify-content: flex-end;
2732
+ }
2733
+ }
2734
+
2715
2735
  [data-rfkit-charts-root] .\\[\\&_svg\\]\\:pointer-events-none svg {
2716
2736
  pointer-events: none;
2717
2737
  }
@@ -4355,6 +4375,7 @@ const UI_CONFIG = {
4355
4375
  ZOOM_MIN_RANGE: 10,
4356
4376
  POPOVER_MARGIN: 16
4357
4377
  };
4378
+ const SPECTRUM_THRESHOLD_COLOR = '#A855F7';
4358
4379
  const setting_defaultConfig = {
4359
4380
  line: {
4360
4381
  realData: {
@@ -4387,7 +4408,7 @@ const setting_defaultConfig = {
4387
4408
  },
4388
4409
  thresholdData: {
4389
4410
  name: 'thresholdData',
4390
- color: '#FF4C2A',
4411
+ color: SPECTRUM_THRESHOLD_COLOR,
4391
4412
  thickness: 1,
4392
4413
  label: "\u95E8\u9650\u503C",
4393
4414
  display: true
@@ -6128,7 +6149,7 @@ function useStore_useStore() {
6128
6149
  store
6129
6150
  };
6130
6151
  }
6131
- function useSelector(selector) {
6152
+ function useStore_useSelector(selector) {
6132
6153
  const { store } = useAppContext();
6133
6154
  return (0, __WEBPACK_EXTERNAL_MODULE_react__.useSyncExternalStore)(store.subscribe, ()=>selector(store.getState()), ()=>selector(store.getState()));
6134
6155
  }
@@ -6277,7 +6298,7 @@ const createNextSystemConfig = (system, size)=>({
6277
6298
  const Container_Container = (props)=>{
6278
6299
  const { children, style } = props;
6279
6300
  const dispatch = useStoreDispatch();
6280
- const system = useSelector((state)=>state.system);
6301
+ const system = useStore_useSelector((state)=>state.system);
6281
6302
  const globalID = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>createGUID(), []);
6282
6303
  const ref = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
6283
6304
  const systemRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(system);
@@ -17077,10 +17098,199 @@ const Dropdown = ({ value: value1, options, onChange, placeholder = "\u8BF7\u900
17077
17098
  });
17078
17099
  };
17079
17100
  const Overlay_Dropdown = Dropdown;
17101
+ const DEFAULT_SAMPLE_INTERVAL_MS = 80;
17102
+ const DEFAULT_SAMPLE_IDLE_DELAY_MS = 80;
17103
+ const toCursorEventSnapshot = (snapshot)=>({
17104
+ sourceId: snapshot.sourceId,
17105
+ sourceType: snapshot.sourceType,
17106
+ clientX: snapshot.clientX,
17107
+ clientY: snapshot.clientY,
17108
+ bounds: snapshot.bounds
17109
+ });
17110
+ const isSameSample = (current, next)=>current?.sourceId === next.sourceId && current?.sourceType === next.sourceType && current?.coord.left === next.coord.left && current?.coord.top === next.coord.top && current?.clientX === next.clientX && current?.clientY === next.clientY && current?.bounds.left === next.bounds.left && current?.bounds.top === next.bounds.top && current?.bounds.right === next.bounds.right && current?.bounds.bottom === next.bounds.bottom && current?.sampledIndex === next.sampledIndex && current?.globalIndex === next.globalIndex && current?.rowIndex === next.rowIndex;
17111
+ class InteractionRuntime {
17112
+ entries = new Map();
17113
+ sampleIntervalMs;
17114
+ sampleIdleDelayMs;
17115
+ now;
17116
+ requestFrame;
17117
+ cancelFrame;
17118
+ setTimer;
17119
+ clearTimer;
17120
+ constructor(options = {}){
17121
+ this.sampleIntervalMs = options.sampleIntervalMs ?? DEFAULT_SAMPLE_INTERVAL_MS;
17122
+ this.sampleIdleDelayMs = options.sampleIdleDelayMs ?? DEFAULT_SAMPLE_IDLE_DELAY_MS;
17123
+ this.now = options.now ?? (()=>Date.now());
17124
+ this.requestFrame = options.requestFrame ?? ((callback)=>{
17125
+ if ('undefined' != typeof window) return window.requestAnimationFrame(callback);
17126
+ return Number(setTimeout(callback, 16));
17127
+ });
17128
+ this.cancelFrame = options.cancelFrame ?? ((id)=>{
17129
+ if ('undefined' != typeof window) return void window.cancelAnimationFrame(id);
17130
+ clearTimeout(id);
17131
+ });
17132
+ this.setTimer = options.setTimer ?? ((callback, delay)=>{
17133
+ if ('undefined' != typeof window) return window.setTimeout(callback, delay);
17134
+ return setTimeout(callback, delay);
17135
+ });
17136
+ this.clearTimer = options.clearTimer ?? ((id)=>{
17137
+ if ('undefined' != typeof window) return void window.clearTimeout(id);
17138
+ clearTimeout(id);
17139
+ });
17140
+ }
17141
+ updatePointer(id, snapshot) {
17142
+ const entry = this.ensureEntry(id);
17143
+ entry.version += 1;
17144
+ entry.pointer = {
17145
+ ...snapshot,
17146
+ version: entry.version,
17147
+ timestamp: this.now()
17148
+ };
17149
+ this.schedulePointerFrame(entry);
17150
+ this.scheduleSample(entry);
17151
+ }
17152
+ refreshBounds(id, bounds) {
17153
+ const entry = this.ensureEntry(id);
17154
+ if (!entry.pointer) return;
17155
+ entry.version += 1;
17156
+ entry.pointer = {
17157
+ ...entry.pointer,
17158
+ bounds,
17159
+ version: entry.version,
17160
+ timestamp: this.now()
17161
+ };
17162
+ this.schedulePointerFrame(entry);
17163
+ }
17164
+ clearPointer(id, _reason = 'manual') {
17165
+ const entry = this.entries.get(id);
17166
+ if (!entry) return;
17167
+ entry.pointer = null;
17168
+ entry.sample = null;
17169
+ entry.lastSampleTimestamp = 0;
17170
+ entry.hasSampleTimestamp = false;
17171
+ this.clearEntryTimers(entry);
17172
+ this.notifyPointer(entry, null);
17173
+ this.notifySample(entry, null);
17174
+ }
17175
+ subscribePointer(id, listener) {
17176
+ const entry = this.ensureEntry(id);
17177
+ entry.pointerListeners.add(listener);
17178
+ listener(entry.pointer);
17179
+ return ()=>{
17180
+ entry.pointerListeners.delete(listener);
17181
+ this.cleanupEntryIfEmpty(id, entry);
17182
+ };
17183
+ }
17184
+ subscribeSample(id, listener) {
17185
+ const entry = this.ensureEntry(id);
17186
+ entry.sampleListeners.add(listener);
17187
+ listener(entry.sample);
17188
+ return ()=>{
17189
+ entry.sampleListeners.delete(listener);
17190
+ this.cleanupEntryIfEmpty(id, entry);
17191
+ };
17192
+ }
17193
+ getPointer(id) {
17194
+ return this.entries.get(id)?.pointer ?? null;
17195
+ }
17196
+ getSample(id) {
17197
+ return this.entries.get(id)?.sample ?? null;
17198
+ }
17199
+ dispose(id) {
17200
+ if (id) {
17201
+ const entry = this.entries.get(id);
17202
+ if (!entry) return;
17203
+ this.clearPointer(id, 'dispose');
17204
+ entry.pointerListeners.clear();
17205
+ entry.sampleListeners.clear();
17206
+ this.entries.delete(id);
17207
+ return;
17208
+ }
17209
+ for (const key of Array.from(this.entries.keys()))this.dispose(key);
17210
+ }
17211
+ ensureEntry(id) {
17212
+ const current = this.entries.get(id);
17213
+ if (current) return current;
17214
+ const entry = {
17215
+ pointer: null,
17216
+ sample: null,
17217
+ pointerListeners: new Set(),
17218
+ sampleListeners: new Set(),
17219
+ pointerFrame: null,
17220
+ sampleTimer: null,
17221
+ idleTimer: null,
17222
+ lastSampleTimestamp: 0,
17223
+ hasSampleTimestamp: false,
17224
+ version: 0
17225
+ };
17226
+ this.entries.set(id, entry);
17227
+ return entry;
17228
+ }
17229
+ schedulePointerFrame(entry) {
17230
+ if (null !== entry.pointerFrame) return;
17231
+ entry.pointerFrame = this.requestFrame(()=>{
17232
+ entry.pointerFrame = null;
17233
+ this.notifyPointer(entry, entry.pointer);
17234
+ });
17235
+ }
17236
+ scheduleSample(entry) {
17237
+ if (!entry.pointer) return;
17238
+ const now = this.now();
17239
+ const elapsed = now - entry.lastSampleTimestamp;
17240
+ if (!entry.hasSampleTimestamp || elapsed >= this.sampleIntervalMs) this.flushSample(entry);
17241
+ else if (!entry.sampleTimer) entry.sampleTimer = this.setTimer(()=>{
17242
+ entry.sampleTimer = null;
17243
+ this.flushSample(entry);
17244
+ }, this.sampleIntervalMs - elapsed);
17245
+ if (entry.idleTimer) this.clearTimer(entry.idleTimer);
17246
+ entry.idleTimer = this.setTimer(()=>{
17247
+ entry.idleTimer = null;
17248
+ this.flushSample(entry);
17249
+ }, this.sampleIdleDelayMs);
17250
+ }
17251
+ flushSample(entry) {
17252
+ if (!entry.pointer) return;
17253
+ const nextSample = {
17254
+ ...entry.pointer
17255
+ };
17256
+ entry.lastSampleTimestamp = this.now();
17257
+ entry.hasSampleTimestamp = true;
17258
+ if (isSameSample(entry.sample, nextSample)) return;
17259
+ entry.sample = nextSample;
17260
+ this.notifySample(entry, nextSample);
17261
+ }
17262
+ notifyPointer(entry, snapshot) {
17263
+ for (const listener of Array.from(entry.pointerListeners))listener(snapshot);
17264
+ }
17265
+ notifySample(entry, snapshot) {
17266
+ for (const listener of Array.from(entry.sampleListeners))listener(snapshot);
17267
+ }
17268
+ clearEntryTimers(entry) {
17269
+ if (null !== entry.pointerFrame) {
17270
+ this.cancelFrame(entry.pointerFrame);
17271
+ entry.pointerFrame = null;
17272
+ }
17273
+ if (entry.sampleTimer) {
17274
+ this.clearTimer(entry.sampleTimer);
17275
+ entry.sampleTimer = null;
17276
+ }
17277
+ if (entry.idleTimer) {
17278
+ this.clearTimer(entry.idleTimer);
17279
+ entry.idleTimer = null;
17280
+ }
17281
+ }
17282
+ cleanupEntryIfEmpty(id, entry) {
17283
+ if (entry.pointerListeners.size > 0 || entry.sampleListeners.size > 0 || entry.pointer || entry.sample) return;
17284
+ this.clearEntryTimers(entry);
17285
+ this.entries.delete(id);
17286
+ }
17287
+ }
17288
+ const interactionRuntime = new InteractionRuntime();
17289
+ const toCursorSnapshotEvent = toCursorEventSnapshot;
17080
17290
  const cursor_follow_layer_useSafeLayoutEffect = 'undefined' == typeof window ? __WEBPACK_EXTERNAL_MODULE_react__.useEffect : __WEBPACK_EXTERNAL_MODULE_react__.useLayoutEffect;
17081
17291
  const isValidBounds = (bounds)=>Number.isFinite(bounds.left) && Number.isFinite(bounds.top) && Number.isFinite(bounds.right) && Number.isFinite(bounds.bottom) && Number.isFinite(bounds.width) && Number.isFinite(bounds.height) && bounds.width > 0 && bounds.height > 0 && bounds.right > bounds.left && bounds.bottom > bounds.top;
17082
17292
  const isPointWithinBounds = (clientX, clientY, bounds)=>clientX >= bounds.left && clientX <= bounds.right && clientY >= bounds.top && clientY <= bounds.bottom;
17083
- const CursorFollowLayer = ({ children, event, margin = 8, className })=>{
17293
+ const CursorFollowLayer = ({ children, interactionId, margin = 8, className })=>{
17084
17294
  const ref = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
17085
17295
  const portalRoot = useChartsPortalContainer('cursor-follow');
17086
17296
  const renderedChildren = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>__WEBPACK_EXTERNAL_MODULE_react__.Children.toArray(children), [
@@ -17092,10 +17302,12 @@ const CursorFollowLayer = ({ children, event, margin = 8, className })=>{
17092
17302
  ref.current.style.visibility = 'hidden';
17093
17303
  ref.current.style.transform = 'translate3d(-100vw, -100vh, 0)';
17094
17304
  }, []);
17095
- const updatePosition = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)(()=>{
17096
- if (!event || !ref.current || !hasContent) return void hideLayer();
17305
+ const latestPointerRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
17306
+ const updatePosition = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((pointer = latestPointerRef.current)=>{
17307
+ if (!pointer || !ref.current || !hasContent) return void hideLayer();
17308
+ latestPointerRef.current = pointer;
17097
17309
  const node = ref.current;
17098
- const { clientX, clientY, bounds } = event;
17310
+ const { clientX, clientY, bounds } = pointer;
17099
17311
  if (!Number.isFinite(clientX) || !Number.isFinite(clientY) || !isValidBounds(bounds)) return void hideLayer();
17100
17312
  const { width, height } = node.getBoundingClientRect();
17101
17313
  const viewportWidth = window.innerWidth;
@@ -17125,11 +17337,26 @@ const CursorFollowLayer = ({ children, event, margin = 8, className })=>{
17125
17337
  node.style.visibility = 'visible';
17126
17338
  node.style.transform = `translate3d(${nextLeft}px, ${nextTop}px, 0)`;
17127
17339
  }, [
17128
- event,
17129
17340
  hasContent,
17130
17341
  hideLayer,
17131
17342
  margin
17132
17343
  ]);
17344
+ cursor_follow_layer_useSafeLayoutEffect(()=>{
17345
+ if (!hasContent || !interactionId) return void hideLayer();
17346
+ return interactionRuntime.subscribePointer(interactionId, (pointer)=>{
17347
+ if (!pointer) {
17348
+ latestPointerRef.current = null;
17349
+ hideLayer();
17350
+ return;
17351
+ }
17352
+ updatePosition(pointer);
17353
+ });
17354
+ }, [
17355
+ hasContent,
17356
+ hideLayer,
17357
+ interactionId,
17358
+ updatePosition
17359
+ ]);
17133
17360
  cursor_follow_layer_useSafeLayoutEffect(()=>{
17134
17361
  if (!portalRoot) return;
17135
17362
  portalRoot.setAttribute('data-rfkit-cursor-layer', 'true');
@@ -17145,14 +17372,17 @@ const CursorFollowLayer = ({ children, event, margin = 8, className })=>{
17145
17372
  });
17146
17373
  cursor_follow_layer_useSafeLayoutEffect(()=>{
17147
17374
  if (!ref.current || !hasContent) return;
17375
+ const handleResize = ()=>{
17376
+ updatePosition();
17377
+ };
17148
17378
  const observer = new ResizeObserver(()=>{
17149
17379
  updatePosition();
17150
17380
  });
17151
17381
  observer.observe(ref.current);
17152
- window.addEventListener('resize', updatePosition);
17382
+ window.addEventListener('resize', handleResize);
17153
17383
  return ()=>{
17154
17384
  observer.disconnect();
17155
- window.removeEventListener('resize', updatePosition);
17385
+ window.removeEventListener('resize', handleResize);
17156
17386
  };
17157
17387
  }, [
17158
17388
  hasContent,
@@ -17171,15 +17401,11 @@ const CursorFollowLayer = ({ children, event, margin = 8, className })=>{
17171
17401
  }), portalRoot);
17172
17402
  };
17173
17403
  const cursor_follow_layer = CursorFollowLayer;
17174
- const Popover = ({ children })=>{
17175
- const { state: { cursor: { event } } } = useStore_useStore();
17176
- if (!event) return null;
17177
- return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(cursor_follow_layer, {
17178
- event: event,
17404
+ const Popover = ({ children, id })=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(cursor_follow_layer, {
17405
+ interactionId: id,
17179
17406
  margin: UI_CONFIG.POPOVER_MARGIN,
17180
17407
  children: children
17181
17408
  });
17182
- };
17183
17409
  const Overlay_Popover = Popover;
17184
17410
  const Portal_Portal = ({ id, children })=>{
17185
17411
  const [container, setContainer] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(null);
@@ -18847,13 +19073,9 @@ class SpectrumAnalyzer {
18847
19073
  if (!data?.length) return;
18848
19074
  this.isProcessing = true;
18849
19075
  this.hasProcessedData = true;
18850
- let index = offset;
18851
- if (this.segments.length) {
18852
- const segment = this.segments[segmentOffset];
18853
- if (!segment) throw new DataValidationError(ERROR_MESSAGES.INVALID_SEGMENT(segmentOffset));
18854
- index = segment.startIndex + offset;
18855
- this.scanProgress = (index + data.length) / this.config.maxPoints;
18856
- } else if (data.length !== this.config.maxPoints) this.updateMaxPoints(data.length);
19076
+ const index = this.resolveGlobalIndex(segmentOffset, offset);
19077
+ if (this.segments.length) this.scanProgress = (index + data.length) / this.config.maxPoints;
19078
+ else if (data.length !== this.config.maxPoints) this.updateMaxPoints(data.length);
18857
19079
  if (fluorescenceData && void 0 !== fluorescenceMaxCount) {
18858
19080
  this.fluorescenceData = fluorescenceData;
18859
19081
  this.fluorescenceMaxCount = fluorescenceMaxCount;
@@ -18893,6 +19115,7 @@ class SpectrumAnalyzer {
18893
19115
  }
18894
19116
  initializeSegments(segments) {
18895
19117
  if (!segments?.length) throw new DataValidationError(ERROR_MESSAGES.EMPTY_SEGMENTS);
19118
+ const prevMaxPoints = this.config.maxPoints;
18896
19119
  let totalPoints = 0;
18897
19120
  this.segments = segments.map((segment)=>{
18898
19121
  const { startFrequency, stopFrequency, stepFrequency } = segment;
@@ -18909,7 +19132,17 @@ class SpectrumAnalyzer {
18909
19132
  startIndex
18910
19133
  };
18911
19134
  });
18912
- this.updateMaxPoints(totalPoints);
19135
+ this.updateMaxPoints(totalPoints, false);
19136
+ if (prevMaxPoints === totalPoints) {
19137
+ this.config = {
19138
+ ...this.config,
19139
+ outputRange: {
19140
+ start: 0,
19141
+ end: totalPoints
19142
+ }
19143
+ };
19144
+ this.reset(false);
19145
+ }
18913
19146
  }
18914
19147
  setAntennaFactor(d) {
18915
19148
  const { antennaFactorData, config: { maxPoints } } = this;
@@ -19133,8 +19366,9 @@ class SpectrumAnalyzer {
19133
19366
  this.allocateMetricsBuffers();
19134
19367
  this.clearMetricsBuffers();
19135
19368
  this.templateData = new Float32Array;
19369
+ this.occupancyData = new Float32Array;
19136
19370
  this.backgroundNoiseData = new Float32Array;
19137
- this.thresholdData = new Float32Array;
19371
+ this.clearThresholdDataState();
19138
19372
  this.waterfallData = Array.from({
19139
19373
  length: waterfallMaxFrames
19140
19374
  }, ()=>{
@@ -19156,7 +19390,6 @@ class SpectrumAnalyzer {
19156
19390
  this.templateOutputData = new Float32Array;
19157
19391
  this.occupancyOutputData = new Float32Array;
19158
19392
  this.backgroundNoiseOutputData = new Float32Array;
19159
- this.thresholdOutputData = new Float32Array;
19160
19393
  this.fluorescenceData = enableFluorescence ? new Uint32Array(maxPoints * FLUORESCENCE.LEVEL_RANGE) : new Uint32Array(0);
19161
19394
  this.fluorescenceMaxCount = 0;
19162
19395
  this.fluorescenceUpdateCounter = 0;
@@ -19253,16 +19486,30 @@ class SpectrumAnalyzer {
19253
19486
  });
19254
19487
  this.setPendingFlag("backgroundNoise", false);
19255
19488
  }
19256
- setThresholdData(data) {
19257
- if (!data || 0 === data.length) {
19258
- this.thresholdData = new Float32Array(0);
19259
- this.setPendingFlag("threshold", false);
19260
- return;
19489
+ setThresholdData(data, options) {
19490
+ if (!data || 0 === data.length) return void this.clearThresholdDataState();
19491
+ const sourceData = data instanceof Float32Array ? data : new Float32Array(data);
19492
+ if (options) {
19493
+ const index = this.resolveGlobalIndex(options.segmentOffset ?? 0, options.offset ?? 0);
19494
+ this.validateInput(sourceData, index);
19495
+ if (this.thresholdData.length !== this.config.maxPoints) {
19496
+ const next = new Float32Array(this.config.maxPoints);
19497
+ next.fill(SPECTRUM.INITIAL_VALUE);
19498
+ if (this.thresholdData.length > 0) next.set(this.thresholdData.subarray(0, this.config.maxPoints));
19499
+ this.thresholdData = next;
19500
+ }
19501
+ this.thresholdData.set(sourceData, index);
19502
+ } else {
19503
+ const normalized = new Float32Array(this.config.maxPoints);
19504
+ normalized.fill(SPECTRUM.INITIAL_VALUE);
19505
+ normalized.set(sourceData.subarray(0, this.config.maxPoints));
19506
+ this.thresholdData = normalized;
19261
19507
  }
19262
- this.thresholdData = new Float32Array(data);
19263
19508
  if (!this.hasProcessedData || this.isProcessing) return void this.setPendingFlag("threshold", true);
19509
+ const thresholdOutputData = this.resampleSingleData(this.thresholdData);
19510
+ this.thresholdOutputData = thresholdOutputData;
19264
19511
  this.notifySpectrumUpdate({
19265
- thresholdData: this.resampleSingleData(this.thresholdData)
19512
+ thresholdData: thresholdOutputData
19266
19513
  });
19267
19514
  this.setPendingFlag("threshold", false);
19268
19515
  }
@@ -19296,6 +19543,19 @@ class SpectrumAnalyzer {
19296
19543
  }
19297
19544
  return templateOverData;
19298
19545
  }
19546
+ resolveGlobalIndex(segmentOffset = 0, offset = 0) {
19547
+ if (this.segments.length) {
19548
+ const segment = this.segments[segmentOffset];
19549
+ if (!segment) throw new DataValidationError(ERROR_MESSAGES.INVALID_SEGMENT(segmentOffset));
19550
+ return segment.startIndex + offset;
19551
+ }
19552
+ return offset;
19553
+ }
19554
+ clearThresholdDataState() {
19555
+ this.thresholdData = new Float32Array(0);
19556
+ this.thresholdOutputData = new Float32Array(0);
19557
+ this.setPendingFlag("threshold", false);
19558
+ }
19299
19559
  resampleDataSeries() {
19300
19560
  const { antennaFactorData, antennaFactorSwitch, maxData, minData, avgData, templateData, occupancyData, backgroundNoiseData, thresholdData, config: { maxPoints, outputPoints } } = this;
19301
19561
  const activeAntennaFactorData = antennaFactorSwitch ? antennaFactorData : new Float32Array(maxPoints);
@@ -19368,7 +19628,7 @@ class SpectrumAnalyzer {
19368
19628
  this.waterfallData.push(newData);
19369
19629
  this.waterfallOutputData.push(outputData);
19370
19630
  }
19371
- updateMaxPoints(maxPoints) {
19631
+ updateMaxPoints(maxPoints, preserveProcessedFlag = true) {
19372
19632
  if (this.config.maxPoints === maxPoints) return;
19373
19633
  this.config = {
19374
19634
  ...this.config,
@@ -19378,7 +19638,7 @@ class SpectrumAnalyzer {
19378
19638
  end: maxPoints
19379
19639
  }
19380
19640
  };
19381
- this.reset(true);
19641
+ this.reset(preserveProcessedFlag);
19382
19642
  }
19383
19643
  validateInput(data, index) {
19384
19644
  if (index < 0 || index + data.length > this.config.maxPoints) throw new IndexOutOfBoundsError(ERROR_MESSAGES.INDEX_OUT_OF_BOUNDS(index), index);
@@ -19452,7 +19712,9 @@ class SpectrumAnalyzer {
19452
19712
  this.setPendingFlag("backgroundNoise", false);
19453
19713
  }
19454
19714
  if (this.pendingDataFlags["threshold"] && this.thresholdData.length > 0) {
19455
- pendingOutput.thresholdData = this.resampleSingleData(this.thresholdData);
19715
+ const thresholdOutputData = this.resampleSingleData(this.thresholdData);
19716
+ this.thresholdOutputData = thresholdOutputData;
19717
+ pendingOutput.thresholdData = thresholdOutputData;
19456
19718
  this.setPendingFlag("threshold", false);
19457
19719
  }
19458
19720
  if (this.pendingDataFlags["extra"] && Object.keys(this.extraData).length > 0) {
@@ -20016,6 +20278,13 @@ function getSeriesWithGraphicType(globalID) {
20016
20278
  });
20017
20279
  return result;
20018
20280
  }
20281
+ const DEFAULT_SPECTRUM_TYPE = 'singleFrequency';
20282
+ const WATERFALL_CAPABLE_SPECTRUM_TYPES = new Set([
20283
+ DEFAULT_SPECTRUM_TYPE,
20284
+ 'scan',
20285
+ 'mscan'
20286
+ ]);
20287
+ const shouldEnableSpectrumWaterfall = ({ heatmapElementID, type })=>!!heatmapElementID && WATERFALL_CAPABLE_SPECTRUM_TYPES.has(type ?? DEFAULT_SPECTRUM_TYPE);
20019
20288
  const applyAxisYRange = (currentAxisY, nextRange)=>{
20020
20289
  const [start, end] = nextRange;
20021
20290
  const currentRange = currentAxisY.range ?? constants_RANGE_DEFAULT;
@@ -20207,11 +20476,11 @@ function useSpectrumChartType({ type, heatmapElementID }) {
20207
20476
  ]);
20208
20477
  return (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
20209
20478
  let enableMetrics = false;
20210
- let enableWaterfall = false;
20211
- if (type === constants_ChartType.SingleFrequency || type === constants_ChartType.Scan || type === constants_ChartType.MScan) {
20212
- enableMetrics = true;
20213
- enableWaterfall = !!heatmapElementID;
20214
- }
20479
+ const enableWaterfall = shouldEnableSpectrumWaterfall({
20480
+ heatmapElementID,
20481
+ type
20482
+ });
20483
+ if (type === constants_ChartType.SingleFrequency || type === constants_ChartType.Scan || type === constants_ChartType.MScan) enableMetrics = true;
20215
20484
  return {
20216
20485
  enableMetrics,
20217
20486
  enableWaterfall
@@ -20473,6 +20742,25 @@ function convertCoordToVisualLeft({ coord, zoom, segments }) {
20473
20742
  const index = Math.min(Math.round(safeLift / 100 * (totalPoints - 1)), totalPoints - 1);
20474
20743
  return (index - start) * 100 / (end - start + 1);
20475
20744
  }
20745
+ const hasBounds = (target)=>'function' == typeof target?.getBoundingClientRect;
20746
+ const calculateEventRelativePositionFromSource = (source)=>{
20747
+ const { clientX = 0, clientY = 0 } = source;
20748
+ const target = source.currentTarget ?? source.target;
20749
+ const { left, top, width, height } = hasBounds(target) ? target.getBoundingClientRect() : {
20750
+ height: 0,
20751
+ left: 0,
20752
+ top: 0,
20753
+ width: 0
20754
+ };
20755
+ if (width <= 0 || height <= 0) return {
20756
+ left: 0,
20757
+ top: 0
20758
+ };
20759
+ return {
20760
+ left: (clientX - left) / width * 100,
20761
+ top: (clientY - top) / height * 100
20762
+ };
20763
+ };
20476
20764
  function getEID(id) {
20477
20765
  return `EVENTBUS-${id}`;
20478
20766
  }
@@ -20490,16 +20778,7 @@ const createMouseEnterEventManager = (id, name, func)=>subscription_createSubscr
20490
20778
  const createWheelEventManager = (id, name, func)=>subscription_createSubscriptionManager(`${generateRecursiveId(id, func)}-wheel`, name, func, id);
20491
20779
  const createDragEventManager = (id, name, func)=>subscription_createSubscriptionManager(`${generateRecursiveId(id, func)}-drag`, name, func, id);
20492
20780
  const createLongPressEventManager = (id, name, func)=>subscription_createSubscriptionManager(`${generateRecursiveId(id, func)}-long-press`, name, func, id);
20493
- const calculateEventRelativePosition = (e)=>{
20494
- const { target, clientX, clientY } = e;
20495
- const { left, top, width, height } = target.getBoundingClientRect();
20496
- const x = (clientX - left) / width * 100;
20497
- const y = (clientY - top) / height * 100;
20498
- return {
20499
- left: x,
20500
- top: y
20501
- };
20502
- };
20781
+ const calculateEventRelativePosition = (e)=>calculateEventRelativePositionFromSource(e);
20503
20782
  const EVENT_PRIORITY_LEVEL_DEFAULT = 'void';
20504
20783
  const EVENT_PRIORITY_LEVELS = {
20505
20784
  [EVENT_PRIORITY_LEVEL_DEFAULT]: 0,
@@ -20568,6 +20847,20 @@ const FrequencyDisplay = ({ frequency, unit })=>frequency ? /*#__PURE__*/ (0, __
20568
20847
  unit
20569
20848
  ]
20570
20849
  }) : null;
20850
+ const useCursorSample = (id)=>{
20851
+ const subscribe = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((listener)=>{
20852
+ if (!id) return ()=>{};
20853
+ return interactionRuntime.subscribeSample(id, ()=>{
20854
+ listener();
20855
+ });
20856
+ }, [
20857
+ id
20858
+ ]);
20859
+ const getSnapshot = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)(()=>id ? interactionRuntime.getSample(id) : null, [
20860
+ id
20861
+ ]);
20862
+ return (0, __WEBPACK_EXTERNAL_MODULE_react__.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
20863
+ };
20571
20864
  function useSeriesManager(globalID, options = {}) {
20572
20865
  const { subscribeToMode = true, subscribeToData = true, watchSeries } = options;
20573
20866
  const [updateCounter, setUpdateCounter] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(0);
@@ -20655,7 +20948,7 @@ function getStableOrder(currentNames) {
20655
20948
  }
20656
20949
  function useFilteredSeries_useFilteredSeries(globalID, filter) {
20657
20950
  const { series } = useSeriesManager(globalID);
20658
- const { state: { series: { legendExternal } } } = useStore_useStore();
20951
+ const legendExternal = useStore_useSelector((state)=>state.series.legendExternal);
20659
20952
  const filteredData = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
20660
20953
  const filtered = Array.from(series.values()).filter((config)=>{
20661
20954
  if (legendExternal.includes(config.name)) return false;
@@ -20683,9 +20976,99 @@ function useFilteredSeries_useFilteredSeries(globalID, filter) {
20683
20976
  ]);
20684
20977
  return filteredData;
20685
20978
  }
20979
+ const clampPercent = (value1)=>Math.max(0, Math.min(100, value1));
20980
+ const normalizeRange = (a, b)=>({
20981
+ end: Math.max(a, b),
20982
+ start: Math.min(a, b)
20983
+ });
20984
+ const resolveHeatmapColumnCount = (waterfallData)=>waterfallData.reduce((columnCount, row)=>Math.max(columnCount, row?.length ?? 0), 0);
20985
+ const resolveHeatmapGridInfo = (waterfallData)=>({
20986
+ columnCount: resolveHeatmapColumnCount(waterfallData),
20987
+ rowCount: waterfallData.length
20988
+ });
20989
+ const resolveHeatmapRowIndex = (top, rowCount)=>{
20990
+ if (rowCount <= 0) return -1;
20991
+ if (1 === rowCount) return 0;
20992
+ const safeTop = clampPercent(top);
20993
+ return Math.max(0, Math.min(rowCount - 1, Math.ceil((100 - safeTop) * rowCount / 100) - 1));
20994
+ };
20995
+ const resolveHeatmapColumnIndex = (left, columnCount)=>{
20996
+ if (columnCount <= 0) return -1;
20997
+ if (1 === columnCount) return 0;
20998
+ const safeLeft = clampPercent(left);
20999
+ return Math.max(0, Math.min(columnCount - 1, Math.ceil(safeLeft * columnCount / 100) - 1));
21000
+ };
21001
+ const resolveHeatmapRowRange = (topA, topB, rowCount)=>{
21002
+ const rowA = resolveHeatmapRowIndex(topA, rowCount);
21003
+ const rowB = resolveHeatmapRowIndex(topB, rowCount);
21004
+ if (rowA < 0 || rowB < 0) return null;
21005
+ const { end, start } = normalizeRange(rowA, rowB);
21006
+ return {
21007
+ endIndex: end,
21008
+ startIndex: start
21009
+ };
21010
+ };
21011
+ const resolveHeatmapColumnRange = (leftA, leftB, columnCount)=>{
21012
+ const columnA = resolveHeatmapColumnIndex(leftA, columnCount);
21013
+ const columnB = resolveHeatmapColumnIndex(leftB, columnCount);
21014
+ if (columnA < 0 || columnB < 0) return null;
21015
+ const { end, start } = normalizeRange(columnA, columnB);
21016
+ return {
21017
+ endCol: end,
21018
+ startCol: start
21019
+ };
21020
+ };
21021
+ const resolveHeatmapGridRange = (waterfallData, bounds)=>{
21022
+ const { columnCount, rowCount } = resolveHeatmapGridInfo(waterfallData);
21023
+ if (0 === rowCount || 0 === columnCount) return null;
21024
+ const rowRange = resolveHeatmapRowRange(bounds.startTop, bounds.endTop, rowCount);
21025
+ const columnRange = resolveHeatmapColumnRange(bounds.startLeft, bounds.endLeft, columnCount);
21026
+ if (!rowRange || !columnRange) return null;
21027
+ return {
21028
+ ...rowRange,
21029
+ ...columnRange
21030
+ };
21031
+ };
21032
+ const resolveHeatmapRangeData = (waterfallData, range)=>{
21033
+ const { columnCount, rowCount } = resolveHeatmapGridInfo(waterfallData);
21034
+ if (0 === rowCount || 0 === columnCount) return [];
21035
+ const startIndex = Math.max(0, Math.min(rowCount - 1, range.startIndex));
21036
+ const endIndex = Math.max(startIndex, Math.min(rowCount - 1, range.endIndex));
21037
+ const startCol = Math.max(0, Math.min(columnCount - 1, range.startCol));
21038
+ const endCol = Math.max(startCol, Math.min(columnCount - 1, range.endCol));
21039
+ return waterfallData.slice(startIndex, endIndex + 1).map((row)=>{
21040
+ const values = [];
21041
+ for(let columnIndex = startCol; columnIndex <= endCol; columnIndex += 1){
21042
+ const rawValue = row?.[columnIndex];
21043
+ values.push('number' == typeof rawValue && Number.isFinite(rawValue) ? rawValue : Number.NaN);
21044
+ }
21045
+ return values;
21046
+ });
21047
+ };
21048
+ const resolveHeatmapCursorValue = (waterfallData, coord)=>{
21049
+ const { columnCount, rowCount } = resolveHeatmapGridInfo(waterfallData);
21050
+ if (0 === rowCount || 0 === columnCount) return null;
21051
+ const rowIndex = resolveHeatmapRowIndex(coord.top, rowCount);
21052
+ const columnIndex = resolveHeatmapColumnIndex(coord.left, columnCount);
21053
+ if (rowIndex < 0 || columnIndex < 0) return null;
21054
+ const row = waterfallData[rowIndex];
21055
+ const rawValue = row?.[columnIndex];
21056
+ const value1 = 'number' == typeof rawValue && Number.isFinite(rawValue) ? rawValue : null;
21057
+ return {
21058
+ columnIndex,
21059
+ rowIndex,
21060
+ timestamp: row?.timestamp ? String(row.timestamp) : '',
21061
+ value: value1
21062
+ };
21063
+ };
20686
21064
  const HeatmapCursorPopover = ({ id })=>{
20687
- const { state: { cursor: { coord }, axisX: { frequencyFormat, unit: axisXUnit = '' }, globalID, axisY: { unit: axisYUnit } } } = useStore_useStore();
20688
- const { left, top } = coord;
21065
+ const frequencyFormat = useStore_useSelector((state)=>state.axisX.frequencyFormat);
21066
+ const axisXUnit = useStore_useSelector((state)=>state.axisX.unit ?? '');
21067
+ const globalID = useStore_useSelector((state)=>state.globalID);
21068
+ const axisYUnit = useStore_useSelector((state)=>state.axisY.unit);
21069
+ const sample = useCursorSample(id);
21070
+ const left = sample?.coord.left;
21071
+ const top = sample?.coord.top;
20689
21072
  const updateKey = useCursorPopoverUpdateKey('HeatmapPopover', id);
20690
21073
  const [value1, setValue] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)('');
20691
21074
  const [timestamp, setTimestamp] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)('');
@@ -20703,23 +21086,22 @@ const HeatmapCursorPopover = ({ id })=>{
20703
21086
  setTimestamp('');
20704
21087
  return;
20705
21088
  }
20706
- const yIndex = Math.max(0, Math.min(outputWaterfall.length - 1, Math.round(outputWaterfall.length * (100 - top) / 100)));
20707
- const outputFrame = outputWaterfall[yIndex];
20708
- if (!outputFrame || 0 === outputFrame.length) return void setValue('');
20709
- const rawFrame = snapshot.rawData?.waterfallData?.[yIndex];
20710
- const globalIndex = snapshot.cursorIndex?.globalIndex;
20711
- const rawXIndex = 'number' == typeof globalIndex && Number.isFinite(globalIndex) && rawFrame && rawFrame.length > 0 ? Math.max(0, Math.min(rawFrame.length - 1, Math.floor(globalIndex))) : void 0;
20712
- const exactRawValue = void 0 !== rawXIndex && rawFrame ? rawFrame[rawXIndex] : void 0;
20713
- const sampledXIndex = leftToIndex(left, outputFrame.length);
20714
- const sampledValue = outputFrame[sampledXIndex];
20715
- const nextValue = Number.isFinite(exactRawValue) ? exactRawValue : sampledValue;
20716
- setValue('number' == typeof nextValue && Number.isFinite(nextValue) ? nextValue.toFixed(1) : '');
20717
- const frameTimestamp = outputFrame.timestamp;
20718
- setTimestamp(frameTimestamp ? String(frameTimestamp) : '');
21089
+ const cursorValue = resolveHeatmapCursorValue(outputWaterfall, {
21090
+ left,
21091
+ top
21092
+ });
21093
+ if (!cursorValue) {
21094
+ setValue('');
21095
+ setTimestamp('');
21096
+ return;
21097
+ }
21098
+ setValue(null !== cursorValue.value && Number.isFinite(cursorValue.value) ? cursorValue.value.toFixed(1) : '');
21099
+ setTimestamp(cursorValue.timestamp);
20719
21100
  }, [
20720
21101
  globalID,
20721
21102
  left,
20722
21103
  top,
21104
+ sample?.version,
20723
21105
  updateKey
20724
21106
  ]);
20725
21107
  const frequency = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>'number' == typeof left ? frequencyFormat?.(left) ?? '' : '', [
@@ -20768,8 +21150,10 @@ const HeatmapCursorPopover = ({ id })=>{
20768
21150
  };
20769
21151
  const CursorPopover = HeatmapCursorPopover;
20770
21152
  const LevelCursorPopover = ({ id })=>{
20771
- const { state: { cursor: { coord }, globalID, axisY: { unit: axisYUnit } } } = useStore_useStore();
20772
- const { left } = coord;
21153
+ const globalID = useStore_useSelector((state)=>state.globalID);
21154
+ const axisYUnit = useStore_useSelector((state)=>state.axisY.unit);
21155
+ const sample = useCursorSample(id);
21156
+ const left = sample?.coord.left;
20773
21157
  const updateKey = useCursorPopoverUpdateKey('LevelStreamPopover', id);
20774
21158
  const [value1, setValue] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)('');
20775
21159
  const [timestamp, setTimestamp] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)('');
@@ -20796,6 +21180,7 @@ const LevelCursorPopover = ({ id })=>{
20796
21180
  }, [
20797
21181
  globalID,
20798
21182
  left,
21183
+ sample?.version,
20799
21184
  updateKey
20800
21185
  ]);
20801
21186
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)(components_Mask, {
@@ -20829,9 +21214,12 @@ const LevelCursorPopover = ({ id })=>{
20829
21214
  });
20830
21215
  };
20831
21216
  const Level_CursorPopover = LevelCursorPopover;
20832
- const OccupancyCursorPopover = ()=>{
20833
- const { state: { cursor: { coord }, axisX: { frequencyFormat, unit: axisXUnit = '' }, globalID } } = useStore_useStore();
20834
- const { left } = coord;
21217
+ const OccupancyCursorPopover = ({ id })=>{
21218
+ const frequencyFormat = useStore_useSelector((state)=>state.axisX.frequencyFormat);
21219
+ const axisXUnit = useStore_useSelector((state)=>state.axisX.unit ?? '');
21220
+ const globalID = useStore_useSelector((state)=>state.globalID);
21221
+ const sample = useCursorSample(id);
21222
+ const left = sample?.coord.left;
20835
21223
  const value1 = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
20836
21224
  if (!globalID || 'number' != typeof left || !Number.isFinite(left)) return '';
20837
21225
  const snapshot = withDatabase(globalID).getAllRawData(left);
@@ -20847,7 +21235,8 @@ const OccupancyCursorPopover = ()=>{
20847
21235
  return '';
20848
21236
  }, [
20849
21237
  globalID,
20850
- left
21238
+ left,
21239
+ sample?.version
20851
21240
  ]);
20852
21241
  const frequency = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>'number' == typeof left ? frequencyFormat?.(left) ?? '' : '', [
20853
21242
  left,
@@ -20921,7 +21310,7 @@ const compareFrequencyMatchedCandidates = (currentFrequency, a, b)=>{
20921
21310
  if (0 !== widthDiff) return widthDiff;
20922
21311
  const centerDistanceDiff = Math.abs(getRangeCenter(a.range) - currentFrequency) - Math.abs(getRangeCenter(b.range) - currentFrequency);
20923
21312
  if (0 !== centerDistanceDiff) return centerDistanceDiff;
20924
- const stationPriorityDiff = Number(isStationInfo(b.item)) - Number(isStationInfo(a.item));
21313
+ const stationPriorityDiff = Number(utils_isStationInfo(b.item)) - Number(utils_isStationInfo(a.item));
20925
21314
  if (0 !== stationPriorityDiff) return stationPriorityDiff;
20926
21315
  return getUnifiedSignalKey(a.item).localeCompare(getUnifiedSignalKey(b.item));
20927
21316
  };
@@ -20932,15 +21321,15 @@ const compareIndexMatchedCandidates = (currentFrequency, currentPointIndex, a, b
20932
21321
  if (0 !== widthDiff) return widthDiff;
20933
21322
  const frequencyDistanceDiff = getFrequencyDistanceToRange(currentFrequency, a.range) - getFrequencyDistanceToRange(currentFrequency, b.range);
20934
21323
  if (0 !== frequencyDistanceDiff) return frequencyDistanceDiff;
20935
- const stationPriorityDiff = Number(isStationInfo(b.item)) - Number(isStationInfo(a.item));
21324
+ const stationPriorityDiff = Number(utils_isStationInfo(b.item)) - Number(utils_isStationInfo(a.item));
20936
21325
  if (0 !== stationPriorityDiff) return stationPriorityDiff;
20937
21326
  return getUnifiedSignalKey(a.item).localeCompare(getUnifiedSignalKey(b.item));
20938
21327
  };
20939
- function isStationInfo(item) {
21328
+ function utils_isStationInfo(item) {
20940
21329
  return 'signalName' in item && 'orgName' in item;
20941
21330
  }
20942
21331
  function getUnifiedSignalKey(item) {
20943
- if (isStationInfo(item)) return `${item.signalName}-${item.frequency}`;
21332
+ if (utils_isStationInfo(item)) return `${item.signalName}-${item.frequency}`;
20944
21333
  if (null != item.startFrequency && null != item.stopFrequency) return `${item.startFrequency}-${item.stopFrequency}`;
20945
21334
  return `${item.frequency}-${item.bandwidth}`;
20946
21335
  }
@@ -20952,7 +21341,7 @@ function toFrequencyRangeInput(item) {
20952
21341
  stopFrequency: null != item.stopFrequency ? Number(item.stopFrequency) : void 0
20953
21342
  };
20954
21343
  }
20955
- function resolveBestSignalMatch(candidates, options) {
21344
+ function utils_resolveBestSignalMatch(candidates, options) {
20956
21345
  const { currentFrequency, currentPointIndex } = options;
20957
21346
  const indexTolerance = options.indexTolerance ?? SIGNAL_INDEX_MATCH_TOLERANCE;
20958
21347
  if (!Number.isFinite(currentFrequency) || !Number.isFinite(currentPointIndex) || !candidates.length) return;
@@ -20965,7 +21354,7 @@ function resolveBestSignalMatch(candidates, options) {
20965
21354
  return indexMatched[0];
20966
21355
  }
20967
21356
  const resolveSignalPresentation = (item)=>{
20968
- if (isStationInfo(item)) {
21357
+ if (utils_isStationInfo(item)) {
20969
21358
  const signalType = item.signalType;
20970
21359
  const signalTypeInfo = SIGNAL_TYPE_MAP[signalType];
20971
21360
  const signalTypeName = signalTypeInfo?.name || item.signalType;
@@ -21014,40 +21403,49 @@ const resolveSignalPositions = (signalItems, segment)=>resolveSignalMatchCandida
21014
21403
  tooltip
21015
21404
  };
21016
21405
  });
21017
- const resolveSignalSegments = ({ segments, signalItems, isCursorActive, currentFrequency, currentPosition })=>{
21406
+ const resolveStaticSignalSegments = ({ segments, signalItems })=>{
21018
21407
  if (!segments.length) return [];
21019
21408
  const totalSegmentPoints = segments.reduce((sum, segment)=>sum + segment.point, 0);
21409
+ let segmentLeft = 0;
21020
21410
  return segments.map((segment, segmentIndex)=>{
21021
- const signalPositions = resolveSignalPositions(signalItems, segment);
21022
- const activeMatch = isCursorActive && currentPosition.segmentIndex === segmentIndex && Number.isFinite(currentFrequency) ? resolveBestSignalMatch(signalPositions, {
21023
- currentFrequency,
21024
- currentPointIndex: currentPosition.pointIndex
21025
- }) : void 0;
21026
21411
  const segmentWidth = segment.point / totalSegmentPoints * 100;
21027
- const segmentLeft = segments.slice(0, segmentIndex).reduce((sum, item)=>sum + item.point / totalSegmentPoints * 100, 0);
21028
- return {
21412
+ const data = {
21029
21413
  segment,
21030
21414
  segmentIndex,
21031
- signalPositions,
21032
- activeSignalKey: activeMatch?.key,
21415
+ signalPositions: resolveSignalPositions(signalItems, segment),
21033
21416
  style: {
21034
21417
  left: `${segmentLeft}%`,
21035
21418
  width: `${segmentWidth}%`
21036
21419
  }
21037
21420
  };
21421
+ segmentLeft += segmentWidth;
21422
+ return data;
21038
21423
  });
21039
21424
  };
21040
- const findStationAtCursor = ({ frequency, signalItems, segments, currentPosition })=>{
21425
+ const resolveActiveSignalKey = ({ segmentData, isCursorActive, currentFrequency, currentPosition })=>{
21426
+ if (!isCursorActive || !Number.isFinite(currentFrequency) || currentPosition.segmentIndex < 0) return;
21427
+ const currentSegmentData = segmentData[currentPosition.segmentIndex];
21428
+ if (!currentSegmentData) return;
21429
+ return utils_resolveBestSignalMatch(currentSegmentData.signalPositions, {
21430
+ currentFrequency,
21431
+ currentPointIndex: currentPosition.pointIndex
21432
+ })?.key;
21433
+ };
21434
+ const createStationRangeIndex = ({ signalItems, segments })=>{
21435
+ if (!signalItems.length || !segments.length) return [];
21436
+ const stationItems = signalItems.filter(utils_isStationInfo);
21437
+ if (!stationItems.length) return [];
21438
+ return segments.map((segment)=>resolveSignalMatchCandidates(stationItems, segment));
21439
+ };
21440
+ const findStationInRangeIndex = ({ frequency, stationRangeIndex, currentPosition })=>{
21041
21441
  if (!Number.isFinite(frequency)) return;
21042
- const currentSegment = segments[currentPosition.segmentIndex];
21043
- if (!currentSegment) return;
21044
- const stationItems = signalItems.filter(isStationInfo);
21045
- if (!stationItems.length) return;
21046
- const matchedSignal = resolveBestSignalMatch(resolveSignalMatchCandidates(stationItems, currentSegment), {
21442
+ const candidates = stationRangeIndex[currentPosition.segmentIndex];
21443
+ if (!candidates?.length) return;
21444
+ const matchedSignal = utils_resolveBestSignalMatch(candidates, {
21047
21445
  currentFrequency: frequency,
21048
21446
  currentPointIndex: currentPosition.pointIndex
21049
21447
  });
21050
- return matchedSignal && isStationInfo(matchedSignal.item) ? matchedSignal.item : void 0;
21448
+ return matchedSignal && utils_isStationInfo(matchedSignal.item) ? matchedSignal.item : void 0;
21051
21449
  };
21052
21450
  const withStationDataUpdate = (globalID, name, func)=>{
21053
21451
  const subscriptionId = `stationData-update-${globalID}`;
@@ -21063,7 +21461,10 @@ const STATION_DATA = (globalID, data)=>{
21063
21461
  return result;
21064
21462
  };
21065
21463
  function useUnifiedSignals({ respectVisibility = false } = {}) {
21066
- const { state: { globalID, signal } } = useStore_useStore();
21464
+ const globalID = useStore_useSelector((state)=>state.globalID);
21465
+ const signalData = useStore_useSelector((state)=>state.signal.data);
21466
+ const signalDisplay = useStore_useSelector((state)=>state.signal.display);
21467
+ const signalShow = useStore_useSelector((state)=>state.signal.show);
21067
21468
  const [updateTrigger, setUpdateTrigger] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(0);
21068
21469
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
21069
21470
  const subscriberName = `useUnifiedSignals-${globalID}-${Date.now()}`;
@@ -21079,30 +21480,39 @@ function useUnifiedSignals({ respectVisibility = false } = {}) {
21079
21480
  globalID
21080
21481
  ]);
21081
21482
  return (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
21082
- if (respectVisibility && (!signal.show || !signal.display)) return [];
21483
+ if (respectVisibility && (!signalShow || !signalDisplay)) return [];
21083
21484
  const stationData = STATION_DATA(globalID);
21084
- const signalData = signal.data || [];
21485
+ const nextSignalData = signalData || [];
21085
21486
  return [
21086
21487
  ...stationData,
21087
- ...signalData
21488
+ ...nextSignalData
21088
21489
  ];
21089
21490
  }, [
21090
21491
  globalID,
21091
- signal.data,
21092
- signal.display,
21093
- signal.show,
21492
+ signalData,
21493
+ signalDisplay,
21494
+ signalShow,
21094
21495
  respectVisibility,
21095
21496
  updateTrigger
21096
21497
  ]);
21097
21498
  }
21098
- function useStationInfoAtCursor({ frequency, enabled = true }) {
21099
- const { state: { cursor, segments } } = useStore_useStore();
21100
- const { coord: { left } } = cursor;
21499
+ function useStationInfoAtCursor({ frequency, enabled = true, cursorSample }) {
21500
+ const cursor = useStore_useSelector((state)=>state.cursor);
21501
+ const segments = useStore_useSelector((state)=>state.segments);
21502
+ const left = cursorSample?.coord.left ?? cursor.coord.left;
21101
21503
  const signalItems = useUnifiedSignals({
21102
21504
  respectVisibility: enabled
21103
21505
  });
21104
- const isCursorActive = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>enabled && cursor_hasActiveSpectrumCursor(cursor), [
21506
+ const stationRangeIndex = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>createStationRangeIndex({
21507
+ signalItems,
21508
+ segments
21509
+ }), [
21510
+ segments,
21511
+ signalItems
21512
+ ]);
21513
+ const isCursorActive = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>enabled && (cursorSample ? true : cursor_hasActiveSpectrumCursor(cursor)), [
21105
21514
  cursor,
21515
+ cursorSample,
21106
21516
  enabled
21107
21517
  ]);
21108
21518
  const currentPosition = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>isCursorActive && 'number' == typeof left ? frequencyCalculation_calculateCursorPosition(left, segments) : {
@@ -21114,29 +21524,27 @@ function useStationInfoAtCursor({ frequency, enabled = true }) {
21114
21524
  segments
21115
21525
  ]);
21116
21526
  return (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
21117
- if (!enabled || 'number' != typeof left || !Number.isFinite(left) || left < 0 || !signalItems.length || !segments?.length) return;
21527
+ if (!enabled || 'number' != typeof left || !Number.isFinite(left) || left < 0 || !stationRangeIndex.length || !segments?.length) return;
21118
21528
  if (!isCursorActive) return;
21119
21529
  const currentFrequency = frequencyCalculation_getCursorFrequencyAtPosition(segments, currentPosition);
21120
21530
  if (!Number.isFinite(currentFrequency)) {
21121
21531
  const fallbackFrequency = Number(frequency);
21122
21532
  if (!Number.isFinite(fallbackFrequency)) return;
21123
- return findStationAtCursor({
21533
+ return findStationInRangeIndex({
21124
21534
  frequency: fallbackFrequency,
21125
- signalItems,
21126
- segments,
21535
+ stationRangeIndex,
21127
21536
  currentPosition
21128
21537
  });
21129
21538
  }
21130
- return findStationAtCursor({
21539
+ return findStationInRangeIndex({
21131
21540
  frequency: currentFrequency,
21132
- signalItems,
21133
- segments,
21541
+ stationRangeIndex,
21134
21542
  currentPosition
21135
21543
  });
21136
21544
  }, [
21137
21545
  enabled,
21138
21546
  frequency,
21139
- signalItems,
21547
+ stationRangeIndex,
21140
21548
  segments,
21141
21549
  currentPosition,
21142
21550
  left,
@@ -21209,16 +21617,21 @@ const StationInfoPanel = ({ stationInfo })=>{
21209
21617
  });
21210
21618
  };
21211
21619
  const panels_StationInfoPanel = /*#__PURE__*/ __WEBPACK_EXTERNAL_MODULE_react__["default"].memo(StationInfoPanel);
21212
- const FrequencyDataBoard = ({ left, updateKey, onChange, showStationInfo = true })=>{
21213
- const { state: { axisY, axisX: { frequencyFormat, unit }, globalID } } = useStore_useStore();
21214
- const filteredSeries = useFilteredSeries_useFilteredSeries(globalID, (config)=>false !== config.display);
21620
+ const FrequencyDataBoard = ({ left, updateKey, onChange, showStationInfo = true, cursorSample })=>{
21621
+ const axisYUnit = useStore_useSelector((state)=>state.axisY.unit);
21622
+ const frequencyFormat = useStore_useSelector((state)=>state.axisX.frequencyFormat);
21623
+ const unit = useStore_useSelector((state)=>state.axisX.unit);
21624
+ const globalID = useStore_useSelector((state)=>state.globalID);
21625
+ const snapshotCacheRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
21626
+ const filterVisibleSeries = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((config)=>false !== config.display, []);
21627
+ const filteredSeries = useFilteredSeries_useFilteredSeries(globalID, filterVisibleSeries);
21215
21628
  const calculateIndex = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((values, series, sampledIndex, rawValue)=>{
21216
21629
  if (!values || 0 === values.length) return null;
21217
21630
  const safeSampledIndex = Math.max(0, Math.min(values.length - 1, Math.floor(sampledIndex)));
21218
21631
  const displayValue = Number.isFinite(rawValue) ? rawValue : values[safeSampledIndex];
21219
21632
  if ('number' != typeof displayValue) return null;
21220
- const unit = axisY.unit ?? '';
21221
- const level = getVirtualLevel(unit, displayValue)?.toFixed(1);
21633
+ const nextUnit = axisYUnit ?? '';
21634
+ const level = getVirtualLevel(nextUnit, displayValue)?.toFixed(1);
21222
21635
  if (!(0, utils_array.Ri)(level)) return null;
21223
21636
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)("div", {
21224
21637
  className: "grid max-w-[220px] grid-cols-[minmax(0,1fr)_auto] items-center gap-x-1 text-xs",
@@ -21238,14 +21651,14 @@ const FrequencyDataBoard = ({ left, updateKey, onChange, showStationInfo = true
21238
21651
  children: level
21239
21652
  }),
21240
21653
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("span", {
21241
- children: unit
21654
+ children: nextUnit
21242
21655
  })
21243
21656
  ]
21244
21657
  })
21245
21658
  ]
21246
21659
  }, series.name);
21247
21660
  }, [
21248
- axisY.unit
21661
+ axisYUnit
21249
21662
  ]);
21250
21663
  const { value: value1, currentIndex } = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
21251
21664
  if (!globalID) return {
@@ -21257,7 +21670,16 @@ const FrequencyDataBoard = ({ left, updateKey, onChange, showStationInfo = true
21257
21670
  value: null,
21258
21671
  currentIndex: Number.NaN
21259
21672
  };
21260
- const snapshot = db.getAllRawData(left);
21673
+ const sampleVersion = cursorSample?.version;
21674
+ const cachedSnapshot = snapshotCacheRef.current;
21675
+ const snapshot = cachedSnapshot && cachedSnapshot.globalID === globalID && cachedSnapshot.left === left && cachedSnapshot.sampleVersion === sampleVersion && cachedSnapshot.updateKey === updateKey ? cachedSnapshot.snapshot : db.getAllRawData(left);
21676
+ snapshotCacheRef.current = {
21677
+ globalID,
21678
+ left,
21679
+ sampleVersion,
21680
+ updateKey,
21681
+ snapshot
21682
+ };
21261
21683
  const cursorGlobalIndex = snapshot.cursorIndex?.globalIndex;
21262
21684
  const cursorSampledIndex = snapshot.cursorIndex?.sampledIndex;
21263
21685
  const sampledSeriesMap = {
@@ -21314,7 +21736,8 @@ const FrequencyDataBoard = ({ left, updateKey, onChange, showStationInfo = true
21314
21736
  globalID,
21315
21737
  filteredSeries,
21316
21738
  updateKey,
21317
- left
21739
+ left,
21740
+ cursorSample?.version
21318
21741
  ]);
21319
21742
  const frequency = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>frequencyFormat?.(left) ?? '', [
21320
21743
  left,
@@ -21332,7 +21755,8 @@ const FrequencyDataBoard = ({ left, updateKey, onChange, showStationInfo = true
21332
21755
  ]);
21333
21756
  const matchedStation = useStationInfoAtCursor({
21334
21757
  frequency,
21335
- enabled: showStationInfo
21758
+ enabled: showStationInfo,
21759
+ cursorSample
21336
21760
  });
21337
21761
  const hasStationInfo = showStationInfo && !!matchedStation;
21338
21762
  const hasValue = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>value1 && (Array.isArray(value1) ? value1.length > 0 : true), [
@@ -21361,12 +21785,16 @@ const FrequencyDataBoard = ({ left, updateKey, onChange, showStationInfo = true
21361
21785
  };
21362
21786
  const Spectrum_FrequencyDataBoard = /*#__PURE__*/ __WEBPACK_EXTERNAL_MODULE_react__["default"].memo(FrequencyDataBoard);
21363
21787
  const SpectrumCursorPopover = ({ id })=>{
21364
- const { state: { signal, cursor: { coord: { left } } } } = useStore_useStore();
21788
+ const signalShow = useStore_useSelector((state)=>state.signal.show);
21789
+ const signalDisplay = useStore_useSelector((state)=>state.signal.display);
21790
+ const sample = useCursorSample(id);
21791
+ const left = sample?.coord.left;
21365
21792
  const updateKey = useCursorPopoverUpdateKey('SpectrumPopover', id);
21366
21793
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Spectrum_FrequencyDataBoard, {
21367
- left: left,
21794
+ left: 'number' == typeof left ? left : -1,
21368
21795
  updateKey: updateKey,
21369
- showStationInfo: signal.show && signal.display
21796
+ showStationInfo: signalShow && signalDisplay,
21797
+ cursorSample: sample
21370
21798
  });
21371
21799
  };
21372
21800
  const Spectrum_CursorPopover = SpectrumCursorPopover;
@@ -21380,35 +21808,46 @@ const resolveCursorPopover = ({ id, mode, type })=>{
21380
21808
  if (type === constants_ModuleType.Heatmap) return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(CursorPopover, {
21381
21809
  id: id
21382
21810
  });
21383
- if (type === constants_ModuleType.Occupancy) return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Occupancy_CursorPopover, {});
21811
+ if (type === constants_ModuleType.Occupancy) return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Occupancy_CursorPopover, {
21812
+ id: id
21813
+ });
21384
21814
  return null;
21385
21815
  };
21386
21816
  const Cursor_COMPONENT_KEY = 'Cursor';
21387
21817
  const CURSOR_BOUNDS_TOLERANCE = 1;
21388
21818
  const Cursor_isPointWithinBounds = (clientX, clientY, bounds, tolerance = CURSOR_BOUNDS_TOLERANCE)=>clientX >= bounds.left - tolerance && clientX <= bounds.right + tolerance && clientY >= bounds.top - tolerance && clientY <= bounds.bottom + tolerance;
21389
- const buildCursorEventSnapshot = (event, sourceId, sourceType)=>{
21819
+ const buildCursorPointerSnapshot = (event, coord, sourceId, sourceType, cachedBounds)=>{
21390
21820
  const target = event.currentTarget;
21391
21821
  if (!(target instanceof HTMLElement)) return null;
21392
- const bounds = resolveCursorVisibleBounds(target);
21822
+ const bounds = cachedBounds ?? resolveCursorVisibleBounds(target);
21393
21823
  return {
21394
21824
  sourceId,
21395
21825
  sourceType,
21396
21826
  clientX: event.clientX,
21397
21827
  clientY: event.clientY,
21828
+ coord,
21398
21829
  bounds
21399
21830
  };
21400
21831
  };
21832
+ const resolveCursorTarget = (event)=>{
21833
+ const target = event.currentTarget;
21834
+ return target instanceof HTMLElement ? target : null;
21835
+ };
21401
21836
  const isSameCursorPayload = (currentCursor, nextCoord, nextEvent)=>{
21402
21837
  const prevEvent = currentCursor.event;
21403
21838
  return currentCursor.coord.left === nextCoord.left && currentCursor.coord.top === nextCoord.top && prevEvent?.sourceId === nextEvent?.sourceId && prevEvent?.sourceType === nextEvent?.sourceType && prevEvent?.clientX === nextEvent?.clientX && prevEvent?.clientY === nextEvent?.clientY && prevEvent?.bounds.left === nextEvent?.bounds.left && prevEvent?.bounds.top === nextEvent?.bounds.top && prevEvent?.bounds.right === nextEvent?.bounds.right && prevEvent?.bounds.bottom === nextEvent?.bounds.bottom;
21404
21839
  };
21405
21840
  const Cursor = ({ id, type })=>{
21406
21841
  const { state: { cursor, globalID }, dispatch } = useStore_useStore();
21407
- const { active, coord, show, mode, event } = cursor;
21842
+ const { active, show, mode } = cursor;
21408
21843
  const [isEnabled, setIsEnabled] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(false);
21409
21844
  const cursorRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(cursor);
21410
21845
  const activeRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(active);
21411
21846
  const isEnabledRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(isEnabled);
21847
+ const boundsRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
21848
+ const targetRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
21849
+ const xLineRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
21850
+ const yLineRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
21412
21851
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
21413
21852
  cursorRef.current = cursor;
21414
21853
  activeRef.current = active;
@@ -21418,9 +21857,16 @@ const Cursor = ({ id, type })=>{
21418
21857
  active,
21419
21858
  isEnabled
21420
21859
  ]);
21421
- const clearCursorIfOwned = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>()=>{
21860
+ const clearCursorIfOwned = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>(reason = 'leave')=>{
21422
21861
  setIsEnabled(false);
21423
- if (cursorRef.current.event?.sourceId !== id) return;
21862
+ const currentPointer = interactionRuntime.getPointer(id);
21863
+ if (cursorRef.current.event?.sourceId !== id && currentPointer?.sourceId !== id) {
21864
+ isEnabledRef.current = false;
21865
+ boundsRef.current = null;
21866
+ targetRef.current = null;
21867
+ interactionRuntime.clearPointer(id, reason);
21868
+ return;
21869
+ }
21424
21870
  const nextCursor = {
21425
21871
  ...cursorRef.current,
21426
21872
  event: null,
@@ -21431,6 +21877,9 @@ const Cursor = ({ id, type })=>{
21431
21877
  };
21432
21878
  cursorRef.current = nextCursor;
21433
21879
  isEnabledRef.current = false;
21880
+ boundsRef.current = null;
21881
+ targetRef.current = null;
21882
+ interactionRuntime.clearPointer(id, reason);
21434
21883
  (0, __WEBPACK_EXTERNAL_MODULE_react_dom_7136dc57__.flushSync)(()=>{
21435
21884
  setIsEnabled(false);
21436
21885
  dispatch({
@@ -21443,27 +21892,86 @@ const Cursor = ({ id, type })=>{
21443
21892
  dispatch,
21444
21893
  id
21445
21894
  ]);
21895
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
21896
+ if (show) return;
21897
+ setIsEnabled(false);
21898
+ isEnabledRef.current = false;
21899
+ boundsRef.current = null;
21900
+ targetRef.current = null;
21901
+ interactionRuntime.clearPointer(id, 'manual');
21902
+ }, [
21903
+ id,
21904
+ show
21905
+ ]);
21906
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>()=>{
21907
+ interactionRuntime.dispose(id);
21908
+ }, [
21909
+ id
21910
+ ]);
21446
21911
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
21447
21912
  if (!globalID || !show) return;
21448
- const unsubscribeEnter = createMouseEnterEventManager(id, Cursor_COMPONENT_KEY, ()=>{
21449
- setIsEnabled(true);
21450
- });
21451
- const unsubscribeMove = createMoveEventManager(id, Cursor_COMPONENT_KEY, (event, coord)=>{
21452
- if (!isEnabledRef.current) return;
21453
- const nextEvent = buildCursorEventSnapshot(event, id, type);
21454
- if (nextEvent && !Cursor_isPointWithinBounds(nextEvent.clientX, nextEvent.clientY, nextEvent.bounds)) return void clearCursorIfOwned();
21455
- if (isSameCursorPayload(cursorRef.current, coord, nextEvent)) return;
21913
+ return interactionRuntime.subscribeSample(id, (sample)=>{
21914
+ if (!sample || sample.sourceId !== id) return;
21915
+ const nextEvent = toCursorSnapshotEvent(sample);
21916
+ if (isSameCursorPayload(cursorRef.current, sample.coord, nextEvent)) return;
21917
+ const nextCursor = {
21918
+ ...cursorRef.current,
21919
+ event: nextEvent,
21920
+ coord: sample.coord
21921
+ };
21922
+ cursorRef.current = nextCursor;
21456
21923
  dispatch({
21457
21924
  payload: {
21458
- cursor: {
21459
- ...cursorRef.current,
21460
- event: nextEvent,
21461
- coord
21462
- }
21925
+ cursor: nextCursor
21463
21926
  }
21464
21927
  });
21465
21928
  if (activeRef.current) CURSOR_SETACTIVE(globalID)();
21466
21929
  });
21930
+ }, [
21931
+ dispatch,
21932
+ globalID,
21933
+ id,
21934
+ show
21935
+ ]);
21936
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
21937
+ if (!show || !active) return;
21938
+ return interactionRuntime.subscribePointer(id, (pointer)=>{
21939
+ const xLine = xLineRef.current;
21940
+ const yLine = yLineRef.current;
21941
+ if (!pointer || pointer.sourceId !== id) {
21942
+ if (xLine) xLine.style.left = '-200%';
21943
+ if (yLine) yLine.style.top = '-200%';
21944
+ return;
21945
+ }
21946
+ if (xLine) xLine.style.left = `${pointer.coord.left}%`;
21947
+ if (yLine) yLine.style.top = `${pointer.coord.top}%`;
21948
+ });
21949
+ }, [
21950
+ active,
21951
+ id,
21952
+ show
21953
+ ]);
21954
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
21955
+ if (!globalID || !show) return;
21956
+ const unsubscribeEnter = createMouseEnterEventManager(id, Cursor_COMPONENT_KEY, ()=>{
21957
+ isEnabledRef.current = true;
21958
+ setIsEnabled(true);
21959
+ });
21960
+ const unsubscribeMove = createMoveEventManager(id, Cursor_COMPONENT_KEY, (event, coord)=>{
21961
+ if (!isEnabledRef.current) return;
21962
+ const target = resolveCursorTarget(event);
21963
+ if (!target) return;
21964
+ if (targetRef.current !== target || !boundsRef.current) {
21965
+ const bounds = resolveCursorVisibleBounds(target);
21966
+ targetRef.current = target;
21967
+ boundsRef.current = bounds;
21968
+ interactionRuntime.refreshBounds(id, bounds);
21969
+ }
21970
+ const nextPointer = buildCursorPointerSnapshot(event, coord, id, type, boundsRef.current);
21971
+ if (!nextPointer) return;
21972
+ if (!Cursor_isPointWithinBounds(nextPointer.clientX, nextPointer.clientY, nextPointer.bounds)) return void clearCursorIfOwned('bounds');
21973
+ interactionRuntime.updatePointer(id, nextPointer);
21974
+ });
21467
21975
  const unsubscribeLeave = createMouseLeaveEventManager(id, Cursor_COMPONENT_KEY, clearCursorIfOwned);
21468
21976
  return ()=>{
21469
21977
  unsubscribeEnter?.();
@@ -21474,15 +21982,36 @@ const Cursor = ({ id, type })=>{
21474
21982
  id,
21475
21983
  globalID,
21476
21984
  show,
21985
+ type,
21477
21986
  clearCursorIfOwned
21478
21987
  ]);
21988
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
21989
+ if (!show) return;
21990
+ const refreshBounds = ()=>{
21991
+ const target = targetRef.current;
21992
+ if (!target) return;
21993
+ const bounds = resolveCursorVisibleBounds(target);
21994
+ boundsRef.current = bounds;
21995
+ interactionRuntime.refreshBounds(id, bounds);
21996
+ };
21997
+ window.addEventListener('resize', refreshBounds);
21998
+ window.addEventListener('scroll', refreshBounds, true);
21999
+ return ()=>{
22000
+ window.removeEventListener('resize', refreshBounds);
22001
+ window.removeEventListener('scroll', refreshBounds, true);
22002
+ };
22003
+ }, [
22004
+ id,
22005
+ show
22006
+ ]);
21479
22007
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
21480
22008
  if (!show) return;
21481
22009
  const handleGlobalPointerMove = (event)=>{
21482
22010
  if (!isEnabledRef.current) return;
21483
- const currentEvent = cursorRef.current.event;
21484
- if (!currentEvent || currentEvent.sourceId !== id) return;
21485
- if (currentEvent.bounds.width <= 0 || currentEvent.bounds.height <= 0 || !Cursor_isPointWithinBounds(event.clientX, event.clientY, currentEvent.bounds)) clearCursorIfOwned();
22011
+ const currentPointer = interactionRuntime.getPointer(id);
22012
+ const bounds = currentPointer?.bounds ?? cursorRef.current.event?.bounds;
22013
+ if (!currentPointer || currentPointer.sourceId !== id || !bounds) return;
22014
+ if (bounds.width <= 0 || bounds.height <= 0 || !Cursor_isPointWithinBounds(event.clientX, event.clientY, bounds)) clearCursorIfOwned('bounds');
21486
22015
  };
21487
22016
  window.addEventListener('pointermove', handleGlobalPointerMove, true);
21488
22017
  return ()=>{
@@ -21493,18 +22022,28 @@ const Cursor = ({ id, type })=>{
21493
22022
  id,
21494
22023
  clearCursorIfOwned
21495
22024
  ]);
21496
- const dashedStyle = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>({
21497
- x: {
21498
- left: `${coord.left || -100}%`,
21499
- opacity: active ? 0.5 : 0
21500
- },
21501
- y: {
21502
- top: `${coord.top || -100}%`,
21503
- opacity: active ? 0.5 : 0
21504
- }
21505
- }), [
21506
- active,
21507
- coord
22025
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
22026
+ if (!show) return;
22027
+ const handleWindowBlur = ()=>{
22028
+ clearCursorIfOwned('blur');
22029
+ };
22030
+ const handleDocumentVisibilityChange = ()=>{
22031
+ if ('hidden' === document.visibilityState) clearCursorIfOwned('visibility');
22032
+ };
22033
+ const handleDocumentMouseOut = (event)=>{
22034
+ if (null === event.relatedTarget) clearCursorIfOwned('mouseout');
22035
+ };
22036
+ window.addEventListener('blur', handleWindowBlur);
22037
+ document.addEventListener('visibilitychange', handleDocumentVisibilityChange);
22038
+ document.addEventListener('mouseout', handleDocumentMouseOut);
22039
+ return ()=>{
22040
+ window.removeEventListener('blur', handleWindowBlur);
22041
+ document.removeEventListener('visibilitychange', handleDocumentVisibilityChange);
22042
+ document.removeEventListener('mouseout', handleDocumentMouseOut);
22043
+ };
22044
+ }, [
22045
+ clearCursorIfOwned,
22046
+ show
21508
22047
  ]);
21509
22048
  const popoverContent = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>resolveCursorPopover({
21510
22049
  id,
@@ -21515,19 +22054,20 @@ const Cursor = ({ id, type })=>{
21515
22054
  mode,
21516
22055
  type
21517
22056
  ]);
21518
- if (!show || !isEnabled || !active || event?.sourceId !== id) return null;
22057
+ if (!show || !isEnabled || !active) return null;
21519
22058
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)(Zoom_ZoomViewportLayer, {
21520
22059
  className: "z-[6]",
21521
22060
  children: [
21522
22061
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
21523
- className: "pointer-events-none absolute left-[-200%] top-0 h-full border-l border-dashed border-chart-highlight/80",
21524
- style: dashedStyle.x
22062
+ ref: xLineRef,
22063
+ className: "pointer-events-none absolute left-[-200%] top-0 h-full border-l border-dashed border-chart-highlight/80 opacity-50"
21525
22064
  }),
21526
22065
  type === constants_ModuleType.Heatmap && /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
21527
- className: "absolute left-0 top-[-200%] w-full border-t border-dashed border-chart-highlight/80",
21528
- style: dashedStyle.y
22066
+ ref: yLineRef,
22067
+ className: "absolute left-0 top-[-200%] w-full border-t border-dashed border-chart-highlight/80 opacity-50"
21529
22068
  }),
21530
22069
  popoverContent && /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Overlay_Popover, {
22070
+ id: id,
21531
22071
  children: popoverContent
21532
22072
  }, `${mode ?? type}-${id}`)
21533
22073
  ]
@@ -21563,7 +22103,7 @@ function useEventBusCallback(id) {
21563
22103
  ]);
21564
22104
  }
21565
22105
  const EventBus_EventBus = ({ id })=>{
21566
- const globalID = useSelector((state)=>state.globalID);
22106
+ const globalID = useStore_useSelector((state)=>state.globalID);
21567
22107
  const EID = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>getEID(id), [
21568
22108
  id
21569
22109
  ]);
@@ -21893,7 +22433,6 @@ function useZoomEvent(id, name) {
21893
22433
  handleDrag
21894
22434
  ]);
21895
22435
  }
21896
- const PERCENTAGE = 100;
21897
22436
  const tools_PRECISION = 1e4;
21898
22437
  const defaultAreaInfoResult = {
21899
22438
  startIndex: 0,
@@ -21912,28 +22451,27 @@ const defaultAreaInfoResult = {
21912
22451
  };
21913
22452
  function calculateAreaInfo({ endLeft, startLeft, startTop, endTop, frequencyFormat, globalID }) {
21914
22453
  const { waterfallData } = withDatabase(globalID).getAllRawData();
21915
- if (!waterfallData?.length || !waterfallData[0]?.length) return defaultAreaInfoResult;
21916
- const rowCount = waterfallData.length;
21917
- const colCount = waterfallData[0].length;
21918
- const indices = {
21919
- top: Math.max(0, Math.min(rowCount - 1, Math.ceil(rowCount * (PERCENTAGE - startTop) / PERCENTAGE) - 1)),
21920
- bottom: Math.max(0, Math.min(rowCount - 1, Math.ceil(rowCount * (PERCENTAGE - endTop) / PERCENTAGE) - 1)),
21921
- start: Math.max(0, Math.min(colCount - 1, Math.ceil(colCount * startLeft / PERCENTAGE) - 1)),
21922
- end: Math.max(0, Math.min(colCount - 1, Math.ceil(colCount * endLeft / PERCENTAGE) - 1))
21923
- };
22454
+ if (!waterfallData?.length) return defaultAreaInfoResult;
22455
+ const indices = resolveHeatmapGridRange(waterfallData, {
22456
+ endLeft,
22457
+ endTop,
22458
+ startLeft,
22459
+ startTop
22460
+ });
22461
+ if (!indices) return defaultAreaInfoResult;
21924
22462
  const formatFrequency = frequencyFormat;
21925
22463
  const frequencies = {
21926
- start: Math.round(Number(formatFrequency(startLeft)) * tools_PRECISION) / tools_PRECISION,
21927
- end: Math.round(Number(formatFrequency(endLeft)) * tools_PRECISION) / tools_PRECISION
22464
+ start: Math.round(Number(formatFrequency(Math.min(startLeft, endLeft))) * tools_PRECISION) / tools_PRECISION,
22465
+ end: Math.round(Number(formatFrequency(Math.max(startLeft, endLeft))) * tools_PRECISION) / tools_PRECISION
21928
22466
  };
21929
22467
  const bandwidth = Math.abs(frequencies.end - frequencies.start);
21930
- const startTimestamp = waterfallData[indices.top]?.timestamp || '';
21931
- const endTimestamp = waterfallData[indices.bottom]?.timestamp || '';
22468
+ const startTimestamp = waterfallData[indices.startIndex]?.timestamp || '';
22469
+ const endTimestamp = waterfallData[indices.endIndex]?.timestamp || '';
21932
22470
  const result = {
21933
- startIndex: indices.top,
21934
- endIndex: indices.bottom,
21935
- startCol: indices.start,
21936
- endCol: indices.end,
22471
+ startIndex: indices.startIndex,
22472
+ endIndex: indices.endIndex,
22473
+ startCol: indices.startCol,
22474
+ endCol: indices.endCol,
21937
22475
  startTimestamp,
21938
22476
  endTimestamp,
21939
22477
  startFrequency: frequencies.start,
@@ -21942,30 +22480,32 @@ function calculateAreaInfo({ endLeft, startLeft, startTop, endTop, frequencyForm
21942
22480
  endFrequencyFormat: String(frequencies.end),
21943
22481
  bandwidth,
21944
22482
  bandwidthFormat: getFrequencyToFixed(bandwidth),
21945
- data: waterfallData.slice(indices.bottom, indices.top + 1).map((row)=>Array.from(row.slice(indices.start, indices.end + 1)))
22483
+ data: resolveHeatmapRangeData(waterfallData, indices)
21946
22484
  };
21947
22485
  return result;
21948
22486
  }
21949
22487
  const heatmapCaptureUpdate = (globalID, func)=>subscription_createSubscriptionManager(`heatmapCaptureUpdate-${globalID}`, '0', func, globalID);
21950
22488
  const Area_COMPONENT_KEY = constants_ToolType.HeatmapCapture;
21951
- const Area = (props)=>{
21952
- const { state: { heatmapCapture, segments, axisX: { frequencyFormat, unit }, system, globalID } } = useStore_useStore();
22489
+ const Area_Area = (props)=>{
22490
+ const { state: { heatmapCapture, axisX: { frequencyFormat, unit }, system, globalID } } = useStore_useStore();
21953
22491
  const { id } = props;
21954
- const { type, show, sync, onChange } = heatmapCapture;
21955
- const canArea = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>type === heatmap_HeatmapCaptureType.Area && show, [
21956
- type
22492
+ const { type, show, display, onChange } = heatmapCapture;
22493
+ const canArea = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>type === heatmap_HeatmapCaptureType.Area && show && display, [
22494
+ type,
22495
+ show,
22496
+ display
21957
22497
  ]);
21958
22498
  const [info, setInfo] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(defaultAreaInfoResult);
21959
22499
  const [areaStyle, setAreaStyle] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)();
21960
22500
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
21961
22501
  if (canArea) {
21962
- createMouseUpEventManager(id, Area_COMPONENT_KEY, ()=>{
22502
+ const cleanupMouseUp = createMouseUpEventManager(id, Area_COMPONENT_KEY, ()=>{
21963
22503
  onChange(info);
21964
22504
  });
21965
- createMouseLeaveEventManager(id, Area_COMPONENT_KEY, ()=>{
22505
+ const cleanupMouseLeave = createMouseLeaveEventManager(id, Area_COMPONENT_KEY, ()=>{
21966
22506
  onChange(info);
21967
22507
  });
21968
- createDragEventManager(id, Area_COMPONENT_KEY, (start, end)=>{
22508
+ const cleanupDrag = createDragEventManager(id, Area_COMPONENT_KEY, (start, end)=>{
21969
22509
  if (compareEventPriority(id, Area_COMPONENT_KEY) && start && end) {
21970
22510
  const { left: startLeft, top: startTop } = start;
21971
22511
  const { left: endLeft, top: endTop } = end;
@@ -21996,16 +22536,19 @@ const Area = (props)=>{
21996
22536
  }));
21997
22537
  }
21998
22538
  });
22539
+ return ()=>{
22540
+ cleanupMouseUp?.();
22541
+ cleanupMouseLeave?.();
22542
+ cleanupDrag?.();
22543
+ };
21999
22544
  }
22000
22545
  }, [
22001
22546
  id,
22002
22547
  canArea,
22003
- sync,
22004
- areaStyle,
22005
22548
  info,
22006
- segments,
22007
22549
  frequencyFormat,
22008
- globalID
22550
+ globalID,
22551
+ onChange
22009
22552
  ]);
22010
22553
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
22011
22554
  if (!canArea) {
@@ -22086,13 +22629,15 @@ const Area = (props)=>{
22086
22629
  ]
22087
22630
  });
22088
22631
  };
22089
- const Capture_Area = Area;
22632
+ const Area = Area_Area;
22090
22633
  const RowIndex_COMPONENT_KEY = constants_ToolType.HeatmapCapture;
22091
22634
  const RowIndex_RowIndex = ({ id })=>{
22092
22635
  const { state: { heatmapCapture, globalID, publish } } = useStore_useStore();
22093
22636
  const { onChange: onRowIndexChange, show, type, display } = heatmapCapture;
22094
- const canRowindex = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>type === heatmap_HeatmapCaptureType.RowIndex, [
22095
- type
22637
+ const canRowindex = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>type === heatmap_HeatmapCaptureType.RowIndex && show && display, [
22638
+ type,
22639
+ show,
22640
+ display
22096
22641
  ]);
22097
22642
  const [info, setInfo] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(null);
22098
22643
  const [currentPosition, setCurrentPosition] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(null);
@@ -22121,7 +22666,7 @@ const RowIndex_RowIndex = ({ id })=>{
22121
22666
  publish
22122
22667
  ]);
22123
22668
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
22124
- const isInteractive = globalID && show && display && canRowindex;
22669
+ const isInteractive = globalID && canRowindex;
22125
22670
  if (!isInteractive) return;
22126
22671
  const handleMouseDown = ()=>{
22127
22672
  setIsDragging(true);
@@ -22147,12 +22692,10 @@ const RowIndex_RowIndex = ({ id })=>{
22147
22692
  }, [
22148
22693
  id,
22149
22694
  globalID,
22150
- show,
22151
22695
  canRowindex,
22152
- display,
22153
22696
  updateRowData
22154
22697
  ]);
22155
- if (!canRowindex || !show || !display) return null;
22698
+ if (!canRowindex) return null;
22156
22699
  const getMaskPosition = ()=>{
22157
22700
  if (!currentPosition) return {};
22158
22701
  const topPosition = currentPosition.top;
@@ -22932,16 +23475,18 @@ const Slider = ({ id })=>{
22932
23475
  const [heatmapData, len] = getHeatmapData();
22933
23476
  if (len <= 0) return null;
22934
23477
  const { position: pos, height: h, leftPosition: left, width: w } = r;
22935
- const endIndex = Math.round((100 - pos) / 100 * (len - 1));
22936
- const startIndex = Math.round((100 - (pos + h)) / 100 * (len - 1));
23478
+ const gridInfo = resolveHeatmapGridInfo(heatmapData);
23479
+ const rowRange = resolveHeatmapRowRange(pos + h, pos, len);
23480
+ if (!rowRange) return null;
23481
+ const { startIndex, endIndex } = rowRange;
22937
23482
  const startTimestamp = heatmapData[startIndex]?.timestamp ?? '';
22938
23483
  const endTimestamp = heatmapData[endIndex]?.timestamp ?? '';
22939
23484
  const startTs = dateTimeToTimestamp(startTimestamp);
22940
23485
  const endTs = dateTimeToTimestamp(endTimestamp);
22941
23486
  const duration = startTs > 0 && endTs > 0 ? Math.abs(endTs - startTs) : 0;
22942
- const colCount = heatmapData[0]?.length || 0;
22943
- const startCol = Math.max(0, Math.min(colCount - 1, Math.ceil(colCount * left / 100) - 1));
22944
- const endCol = Math.max(0, Math.min(colCount - 1, Math.ceil(colCount * (left + w) / 100) - 1));
23487
+ const columnRange = resolveHeatmapColumnRange(left, left + w, gridInfo.columnCount);
23488
+ if (!columnRange) return null;
23489
+ const { startCol, endCol } = columnRange;
22945
23490
  const formatFn = frequencyFormatRef.current;
22946
23491
  const startFreqStr = formatFn?.(left);
22947
23492
  const endFreqStr = formatFn?.(left + w);
@@ -23013,7 +23558,7 @@ const Slider = ({ id })=>{
23013
23558
  const applyInterval = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((newInterval)=>{
23014
23559
  const { startIndex, endIndex, startFrequency, endFrequency } = newInterval;
23015
23560
  const [_, len] = getHeatmapData();
23016
- const rowChanged = !(startIndex === info?.startIndex && endIndex === info?.endIndex) && len > 0 && startIndex >= 0 && endIndex <= len && endIndex - startIndex >= Math.ceil(MIN_SIZE * len / 100);
23561
+ const rowChanged = !(startIndex === info?.startIndex && endIndex === info?.endIndex) && len > 0 && startIndex >= 0 && endIndex < len && endIndex - startIndex >= Math.ceil(MIN_SIZE * len / 100);
23017
23562
  let freqChanged = false;
23018
23563
  let newLeftPosition = currentRect.leftPosition;
23019
23564
  let newWidth = currentRect.width;
@@ -23123,7 +23668,7 @@ const HeatmapCapture = (props)=>{
23123
23668
  ...props
23124
23669
  }) : type === heatmap_HeatmapCaptureType.RowIndex ? /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(RowIndex, {
23125
23670
  ...props
23126
- }) : /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Capture_Area, {
23671
+ }) : /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Area, {
23127
23672
  ...props
23128
23673
  });
23129
23674
  };
@@ -23850,7 +24395,7 @@ const SegmentsDisplayControl_SegmentsDisplayControl = ()=>{
23850
24395
  });
23851
24396
  };
23852
24397
  const SegmentsDisplayControl = SegmentsDisplayControl_SegmentsDisplayControl;
23853
- const SeriesControl_SeriesControl = ({ type })=>{
24398
+ const SeriesControl = ({ type })=>{
23854
24399
  const { state: { globalID } } = useStore_useStore();
23855
24400
  const { mode: currentMode } = useSeriesManager(globalID);
23856
24401
  const handleSeriesControl = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)(()=>{
@@ -23972,7 +24517,7 @@ const SeriesControl_SeriesControl = ({ type })=>{
23972
24517
  children: renderIcon()
23973
24518
  });
23974
24519
  };
23975
- const SeriesControl = SeriesControl_SeriesControl;
24520
+ const controls_SeriesControl = SeriesControl;
23976
24521
  const SeriesDisplayControl = ()=>{
23977
24522
  const { state: { globalID, series: seriesConfig } } = useStore_useStore();
23978
24523
  const filteredSeries = useFilteredSeries_useFilteredSeries(globalID);
@@ -24358,10 +24903,50 @@ const FluorescenceSwitch = ()=>{
24358
24903
  });
24359
24904
  };
24360
24905
  const Fluorescence_Switch = FluorescenceSwitch;
24906
+ const DeltaMeasurementIcon_DeltaMeasurementIcon = ()=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)("svg", {
24907
+ viewBox: "0 0 1024 1024",
24908
+ xmlns: "http://www.w3.org/2000/svg",
24909
+ width: "24",
24910
+ height: "24",
24911
+ style: {
24912
+ transition: 'transform 0.2s ease'
24913
+ },
24914
+ children: [
24915
+ /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("path", {
24916
+ d: "M512 200 L812 824 L212 824 Z",
24917
+ fill: "none",
24918
+ stroke: "currentColor",
24919
+ strokeWidth: "60",
24920
+ strokeLinejoin: "miter"
24921
+ }),
24922
+ /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("line", {
24923
+ x1: "350",
24924
+ y1: "650",
24925
+ x2: "674",
24926
+ y2: "650",
24927
+ stroke: "currentColor",
24928
+ strokeWidth: "40",
24929
+ strokeDasharray: "10,10"
24930
+ }),
24931
+ /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("path", {
24932
+ d: "M 360 650 L 390 630 L 390 670 Z",
24933
+ fill: "currentColor"
24934
+ }),
24935
+ /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("path", {
24936
+ d: "M 664 650 L 634 630 L 634 670 Z",
24937
+ fill: "currentColor"
24938
+ })
24939
+ ]
24940
+ });
24941
+ const DeltaMeasurementIcon = DeltaMeasurementIcon_DeltaMeasurementIcon;
24361
24942
  const Switch_Switch = ()=>{
24362
24943
  const { state: { heatmapCapture }, dispatch } = useStore_useStore();
24363
- const { show, display, type } = heatmapCapture;
24364
- const { title, svg } = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
24944
+ const { show, display, type, toolbarVariant } = heatmapCapture;
24945
+ const { title, icon } = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
24946
+ if ('deltaMeasurement' === toolbarVariant) return {
24947
+ title: display ? "\u9000\u51FA\u0394\u6D4B\u91CF\u6A21\u5F0F" : "\u8FDB\u5165\u0394\u6D4B\u91CF\u6A21\u5F0F",
24948
+ icon: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(DeltaMeasurementIcon, {})
24949
+ };
24365
24950
  let title = "\u7011\u5E03\u56FE\u6355\u83B7-\u533A\u57DF\u6D4B\u91CF";
24366
24951
  let svg = /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)(__WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.Fragment, {
24367
24952
  children: [
@@ -24408,11 +24993,16 @@ const Switch_Switch = ()=>{
24408
24993
  }
24409
24994
  return {
24410
24995
  title,
24411
- svg
24996
+ icon: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("svg", {
24997
+ viewBox: "0 0 1024 1024",
24998
+ xmlns: "http://www.w3.org/2000/svg",
24999
+ children: svg
25000
+ })
24412
25001
  };
24413
25002
  }, [
24414
25003
  type,
24415
- display
25004
+ display,
25005
+ toolbarVariant
24416
25006
  ]);
24417
25007
  const setActive = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((e)=>{
24418
25008
  dispatch({
@@ -24434,11 +25024,7 @@ const Switch_Switch = ()=>{
24434
25024
  setActive(!display);
24435
25025
  },
24436
25026
  title: title,
24437
- children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("svg", {
24438
- viewBox: "0 0 1024 1024",
24439
- xmlns: "http://www.w3.org/2000/svg",
24440
- children: svg
24441
- })
25027
+ children: icon
24442
25028
  });
24443
25029
  };
24444
25030
  const Capture_Switch = /*#__PURE__*/ __WEBPACK_EXTERNAL_MODULE_react__["default"].memo(Switch_Switch);
@@ -24488,50 +25074,13 @@ const DeltaMeasurementSwitch = ()=>{
24488
25074
  deltaMeasurement,
24489
25075
  dispatch
24490
25076
  ]);
24491
- const DeltaIcon = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)("svg", {
24492
- viewBox: "0 0 1024 1024",
24493
- xmlns: "http://www.w3.org/2000/svg",
24494
- width: "24",
24495
- height: "24",
24496
- style: {
24497
- transition: 'transform 0.2s ease'
24498
- },
24499
- children: [
24500
- /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("path", {
24501
- d: "M512 200 L812 824 L212 824 Z",
24502
- fill: "none",
24503
- stroke: "currentColor",
24504
- strokeWidth: "60",
24505
- strokeLinejoin: "miter"
24506
- }),
24507
- /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("line", {
24508
- x1: "350",
24509
- y1: "650",
24510
- x2: "674",
24511
- y2: "650",
24512
- stroke: "currentColor",
24513
- strokeWidth: "40",
24514
- strokeDasharray: "10,10"
24515
- }),
24516
- /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("path", {
24517
- d: "M 360 650 L 390 630 L 390 670 Z",
24518
- fill: "currentColor"
24519
- }),
24520
- /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("path", {
24521
- d: "M 664 650 L 634 630 L 634 670 Z",
24522
- fill: "currentColor"
24523
- })
24524
- ]
24525
- }), [
24526
- display
24527
- ]);
24528
25077
  if (!show) return null;
24529
25078
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(primitives_IconBox, {
24530
25079
  active: display,
24531
25080
  tone: "primary",
24532
25081
  onClick: ()=>setDisplay(!display),
24533
25082
  title: display ? "\u9000\u51FA\u0394\u6D4B\u91CF\u6A21\u5F0F" : "\u8FDB\u5165\u0394\u6D4B\u91CF\u6A21\u5F0F",
24534
- children: DeltaIcon
25083
+ children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(DeltaMeasurementIcon, {})
24535
25084
  });
24536
25085
  };
24537
25086
  const DeltaMeasurement_Switch = DeltaMeasurementSwitch;
@@ -25047,7 +25596,7 @@ const TOOLBAR_ITEM_CONFIGS = [
25047
25596
  ]
25048
25597
  },
25049
25598
  {
25050
- component: SeriesControl,
25599
+ component: controls_SeriesControl,
25051
25600
  toolType: constants_ToolbarItemType.SeriesControl,
25052
25601
  supportedCharts: [
25053
25602
  constants_ChartType.SingleFrequency,
@@ -25159,8 +25708,8 @@ const resolveToolbarItemProps = (config, chartType)=>{
25159
25708
  return config.props;
25160
25709
  };
25161
25710
  const Toolbar = ({ type })=>{
25162
- const show = useSelector((state)=>state.toolbar.show);
25163
- const hiddenTools = useSelector((state)=>state.toolbar.hiddenTools ?? []);
25711
+ const show = useStore_useSelector((state)=>state.toolbar.show);
25712
+ const hiddenTools = useStore_useSelector((state)=>state.toolbar.hiddenTools ?? []);
25164
25713
  const { width, pluginBoxWidth } = useAxisYWidth_useAxisYWidth();
25165
25714
  const axisStyle = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>({
25166
25715
  marginLeft: width,
@@ -25316,7 +25865,7 @@ class Occupancy extends BaseRenderer {
25316
25865
  });
25317
25866
  }
25318
25867
  }
25319
- const Level_Level = (props)=>{
25868
+ const Level = (props)=>{
25320
25869
  const { opacity } = props;
25321
25870
  const { chart, Chart } = hooks_useChart({
25322
25871
  Render: Occupancy,
@@ -25339,7 +25888,7 @@ const Level_Level = (props)=>{
25339
25888
  style: style
25340
25889
  });
25341
25890
  };
25342
- const Level = Level_Level;
25891
+ const modules_Level = Level;
25343
25892
  const LINE_WIDTH_BASE = 0.5;
25344
25893
  const MAJOR_TICK_LENGTH = 6;
25345
25894
  const MINOR_TICK_LENGTH = 4;
@@ -25354,7 +25903,7 @@ const MINOR_TICK_LINE_WIDTH = LINE_WIDTH_BASE;
25354
25903
  const AXIS_LINE_WIDTH = LINE_WIDTH_BASE;
25355
25904
  function useCanvasAxisY(options) {
25356
25905
  const { ranging } = options;
25357
- const axisY = useSelector((state)=>state.axisY);
25906
+ const axisY = useStore_useSelector((state)=>state.axisY);
25358
25907
  const { range: axisYRange, disabled } = axisY;
25359
25908
  const canvasRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
25360
25909
  const containerRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
@@ -25965,6 +26514,17 @@ const DragFrame = ({ id })=>{
25965
26514
  });
25966
26515
  };
25967
26516
  const Spectrum_DragFrame = /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react__.memo)(DragFrame);
26517
+ const FREQUENCY_ALLOCATION_LANE_HEIGHT = 14;
26518
+ const FREQUENCY_ALLOCATION_COMPACT_LANE_HEIGHT = 5;
26519
+ const FREQUENCY_ALLOCATION_COMPACT_THRESHOLD = 4;
26520
+ const resolveFrequencyAllocationDensity = ({ density = 'auto', channelCount })=>{
26521
+ const compact = 'compact' === density || 'auto' === density && channelCount > FREQUENCY_ALLOCATION_COMPACT_THRESHOLD;
26522
+ return {
26523
+ compact,
26524
+ laneHeight: compact ? FREQUENCY_ALLOCATION_COMPACT_LANE_HEIGHT : FREQUENCY_ALLOCATION_LANE_HEIGHT,
26525
+ showLabels: !compact
26526
+ };
26527
+ };
25968
26528
  const originalColors = [
25969
26529
  '#B22222',
25970
26530
  '#CD5C5C',
@@ -26536,19 +27096,65 @@ const FrequencyAllocation_data = [
26536
27096
  }
26537
27097
  ];
26538
27098
  const STORAGE_KEY = 'rfkit-charts-frequency-allocation';
26539
- const getFrequencyAllocationFromCache = ()=>{
27099
+ const isFrequencyAllocationChannelCache = (data)=>{
27100
+ if (!data || 'object' != typeof data) return false;
27101
+ const cache = data;
27102
+ return 2 === cache.version && Array.isArray(cache.channels);
27103
+ };
27104
+ const readFrequencyAllocationCache = ()=>{
26540
27105
  const cached = localStorage.getItem(STORAGE_KEY);
26541
27106
  if (!cached) return null;
26542
27107
  const data = JSON.parse(cached);
26543
- return Array.isArray(data) ? data : null;
27108
+ if (Array.isArray(data)) return data;
27109
+ if (isFrequencyAllocationChannelCache(data)) return data;
27110
+ return null;
27111
+ };
27112
+ const getFrequencyAllocationFromCache = ()=>{
27113
+ const cache = readFrequencyAllocationCache();
27114
+ return Array.isArray(cache) ? cache : null;
27115
+ };
27116
+ const getFrequencyAllocationChannelsFromCache = ()=>{
27117
+ const cache = readFrequencyAllocationCache();
27118
+ return isFrequencyAllocationChannelCache(cache) ? cache.channels : null;
26544
27119
  };
26545
27120
  const setFrequencyAllocationToCache = (data)=>{
26546
27121
  localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
26547
27122
  };
26548
- function resolveFrequencyAllocationData(data) {
26549
- const cachedData = getFrequencyAllocationFromCache() ?? [];
27123
+ const setFrequencyAllocationChannelsToCache = (channels)=>{
27124
+ localStorage.setItem(STORAGE_KEY, JSON.stringify({
27125
+ version: 2,
27126
+ channels
27127
+ }));
27128
+ };
27129
+ const DEFAULT_FREQUENCY_ALLOCATION_CHANNEL_ID = 'default';
27130
+ const resolveChannelId = (channel, index)=>channel.id || channel.title || `${DEFAULT_FREQUENCY_ALLOCATION_CHANNEL_ID}-${index}`;
27131
+ const normalizeChannels = (channels, normalizeData)=>channels.map((channel, index)=>({
27132
+ id: resolveChannelId(channel, index),
27133
+ title: channel.title,
27134
+ data: normalizeData(channel.data ?? [])
27135
+ })).filter((channel)=>channel.data.length > 0);
27136
+ const normalizeSingleChannel = (data, normalizeData)=>[
27137
+ {
27138
+ id: DEFAULT_FREQUENCY_ALLOCATION_CHANNEL_ID,
27139
+ data: normalizeData(data)
27140
+ }
27141
+ ];
27142
+ function resolveFrequencyAllocationChannelModel({ data, channels, cachedData, cachedChannels, presetData, normalizeData }) {
27143
+ if (channels) return channels.length ? normalizeChannels(channels, normalizeData) : normalizeSingleChannel(data?.length ? data : presetData, normalizeData);
27144
+ if (cachedChannels?.length) return normalizeChannels(cachedChannels, normalizeData);
26550
27145
  const inputData = data ?? [];
26551
- return sortAndRecolorFrequencyAllocationData(cachedData.length > 0 ? cachedData : inputData.length > 0 ? inputData : FrequencyAllocation_data);
27146
+ const fallbackData = cachedData && cachedData.length > 0 ? cachedData : inputData.length > 0 ? inputData : presetData;
27147
+ return normalizeSingleChannel(fallbackData, normalizeData);
27148
+ }
27149
+ function resolveFrequencyAllocationChannels({ data, channels }) {
27150
+ return resolveFrequencyAllocationChannelModel({
27151
+ data,
27152
+ channels,
27153
+ cachedData: getFrequencyAllocationFromCache(),
27154
+ cachedChannels: getFrequencyAllocationChannelsFromCache(),
27155
+ presetData: FrequencyAllocation_data,
27156
+ normalizeData: sortAndRecolorFrequencyAllocationData
27157
+ });
26552
27158
  }
26553
27159
  const resolveFrequencyAllocationRange = (band)=>{
26554
27160
  if (null != band.startFrequency && null != band.stopFrequency) {
@@ -26564,7 +27170,7 @@ const resolveFrequencyAllocationRange = (band)=>{
26564
27170
  }
26565
27171
  return null;
26566
27172
  };
26567
- const resolveFrequencyAllocationSegments = ({ segments, allocations })=>{
27173
+ const resolveFrequencyAllocationSegments = ({ segments, allocations, channelIndex, channelTitle })=>{
26568
27174
  if (!segments.length || !allocations.length) return [];
26569
27175
  const totalSegmentPoints = segments.reduce((sum, segment)=>sum + segment.point, 0);
26570
27176
  return segments.map((segment, segmentIndex)=>{
@@ -26578,6 +27184,8 @@ const resolveFrequencyAllocationSegments = ({ segments, allocations })=>{
26578
27184
  return {
26579
27185
  band,
26580
27186
  range,
27187
+ channelIndex: channelIndex ?? 0,
27188
+ channelTitle,
26581
27189
  position: {
26582
27190
  left: `${left}%`,
26583
27191
  width: `${width}%`
@@ -26597,15 +27205,30 @@ const resolveFrequencyAllocationSegments = ({ segments, allocations })=>{
26597
27205
  };
26598
27206
  });
26599
27207
  };
26600
- function useFrequencyAllocationData_useFrequencyAllocationData() {
26601
- const { state: { frequencyAllocation: { data } } } = useStore_useStore();
26602
- return (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>resolveFrequencyAllocationData(data), [
26603
- data
27208
+ const resolveFrequencyAllocationLanes = ({ segments, channels })=>channels.map((channel, channelIndex)=>({
27209
+ channel,
27210
+ channelIndex,
27211
+ segmentData: resolveFrequencyAllocationSegments({
27212
+ segments,
27213
+ allocations: channel.data,
27214
+ channelIndex,
27215
+ channelTitle: channel.title
27216
+ })
27217
+ })).filter((lane)=>lane.segmentData.some((segment)=>segment.bandPositions.length > 0));
27218
+ function useFrequencyAllocationChannels() {
27219
+ const data = useStore_useSelector((state)=>state.frequencyAllocation.data);
27220
+ const channels = useStore_useSelector((state)=>state.frequencyAllocation.channels);
27221
+ return (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>resolveFrequencyAllocationChannels({
27222
+ data,
27223
+ channels
27224
+ }), [
27225
+ data,
27226
+ channels
26604
27227
  ]);
26605
27228
  }
26606
27229
  const AllocationInfo_AllocationInfo = ({ allocationInfo, variant = 'default' })=>{
26607
27230
  if (!allocationInfo) return null;
26608
- const { title, description, startFrequency, stopFrequency, centerFrequency, stepFrequency, bandwidth, modulation } = allocationInfo;
27231
+ const { title, description, startFrequency, stopFrequency, centerFrequency, stepFrequency, bandwidth, modulation, channelTitle } = allocationInfo;
26609
27232
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)("div", {
26610
27233
  className: cn_cn('text-xs leading-5 text-popover-foreground', 'board' === variant && 'mt-[calc(var(--size-gap-base)/2)] border-t border-dashed border-border pt-[calc(var(--size-gap-base)/2)]'),
26611
27234
  children: [
@@ -26616,6 +27239,12 @@ const AllocationInfo_AllocationInfo = ({ allocationInfo, variant = 'default' })=
26616
27239
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)("div", {
26617
27240
  className: "mb-1 text-primary",
26618
27241
  children: [
27242
+ channelTitle ? /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)("div", {
27243
+ children: [
27244
+ "\u901A\u9053\uFF1A",
27245
+ channelTitle
27246
+ ]
27247
+ }) : null,
26619
27248
  startFrequency && stopFrequency && /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)("div", {
26620
27249
  children: [
26621
27250
  "\u9891\u7387\u8303\u56F4\uFF1A",
@@ -26661,57 +27290,91 @@ const AllocationInfo_AllocationInfo = ({ allocationInfo, variant = 'default' })=
26661
27290
  });
26662
27291
  };
26663
27292
  const AllocationInfo = /*#__PURE__*/ __WEBPACK_EXTERNAL_MODULE_react__["default"].memo(AllocationInfo_AllocationInfo);
26664
- const AllocationSegments_AllocationSegments = /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react__.memo)(({ style, bandPositions, onMouseEnter, onMouseMove, onMouseLeave })=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
27293
+ const AllocationSegments = /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react__.memo)(({ style, bandPositions, showLabels, onMouseEnter, onMouseMove, onMouseLeave })=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
26665
27294
  className: "absolute top-0 h-full [contain:layout]",
26666
27295
  style: style,
26667
- children: bandPositions.map(({ band, range, position })=>{
27296
+ children: bandPositions.map((bandPosition)=>{
27297
+ const { band, channelIndex, range, position } = bandPosition;
26668
27298
  const backgroundStyle = band.gradientColors ? {
26669
27299
  backgroundImage: `linear-gradient(to right, ${band.gradientColors[0]}, ${band.gradientColors[1]})`
26670
27300
  } : {
26671
27301
  backgroundColor: band.color || 'var(--primary)'
26672
27302
  };
26673
27303
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
26674
- className: "pointer-events-auto absolute flex h-full items-center justify-center overflow-hidden px-1 text-xs text-foreground/90 opacity-50 backdrop-blur-sm transition-[opacity,box-shadow] duration-200 hover:z-[1] hover:opacity-100 hover:shadow-lg",
27304
+ className: "pointer-events-auto absolute flex h-full items-center justify-center overflow-hidden px-1 text-xs text-foreground/90 opacity-60 backdrop-blur-sm transition-[opacity,box-shadow] duration-200 hover:z-[1] hover:opacity-100 hover:shadow-lg",
26675
27305
  style: {
26676
27306
  ...backgroundStyle,
26677
27307
  left: position.left,
26678
27308
  width: position.width
26679
27309
  },
26680
- onMouseEnter: onMouseEnter(band, range),
27310
+ onMouseEnter: onMouseEnter(bandPosition),
26681
27311
  onMouseMove: onMouseMove,
26682
27312
  onMouseLeave: onMouseLeave,
26683
- children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("span", {
27313
+ children: showLabels ? /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("span", {
26684
27314
  className: "truncate",
26685
27315
  children: band.title
26686
- })
26687
- }, `band-${band.title}-${range.start}-${range.stop}-${position.left}`);
27316
+ }) : null
27317
+ }, `band-${channelIndex ?? 0}-${band.title}-${range.start}-${range.stop}-${position.left}`);
26688
27318
  })
26689
27319
  }));
26690
- const AllocationSegments = AllocationSegments_AllocationSegments;
26691
- const overlays_Tooltip_Tooltip = ({ title, description, visible, x, y, startFrequency, stopFrequency, centerFrequency, stepFrequency, bandwidth, modulation })=>{
27320
+ const presenters_AllocationSegments = AllocationSegments;
27321
+ const overlays_Tooltip_Tooltip = ({ title, description, visible, x, y, startFrequency, stopFrequency, centerFrequency, stepFrequency, bandwidth, modulation, channelTitle, positionRef, scheduleRef })=>{
26692
27322
  const tooltipRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
26693
- const [position, setPosition] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)({
27323
+ const frameRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
27324
+ const updatePosition = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)(()=>{
27325
+ if (!visible || !tooltipRef.current) return;
27326
+ const viewportPadding = 12;
27327
+ const tooltip = tooltipRef.current;
27328
+ const tooltipWidth = tooltip.offsetWidth;
27329
+ const tooltipHeight = tooltip.offsetHeight;
27330
+ const windowWidth = window.innerWidth;
27331
+ const windowHeight = window.innerHeight;
27332
+ const sourcePosition = positionRef.current ?? {
27333
+ x,
27334
+ y
27335
+ };
27336
+ const sourceX = sourcePosition.x;
27337
+ const sourceY = sourcePosition.y;
27338
+ const nextX = sourceX + tooltipWidth > windowWidth - viewportPadding ? sourceX - tooltipWidth - 10 : sourceX;
27339
+ const nextY = sourceY + tooltipHeight > windowHeight - viewportPadding ? sourceY - tooltipHeight - 10 : sourceY;
27340
+ const clampedX = Math.max(viewportPadding, Math.min(nextX, windowWidth - tooltipWidth - viewportPadding));
27341
+ const clampedY = Math.max(viewportPadding, Math.min(nextY, windowHeight - tooltipHeight - viewportPadding));
27342
+ tooltip.style.transform = `translate3d(${clampedX}px, ${clampedY}px, 0)`;
27343
+ }, [
27344
+ positionRef,
27345
+ visible,
26694
27346
  x,
26695
27347
  y
26696
- });
27348
+ ]);
27349
+ const schedulePositionUpdate = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)(()=>{
27350
+ if (!visible || null !== frameRef.current) return;
27351
+ frameRef.current = requestAnimationFrame(()=>{
27352
+ frameRef.current = null;
27353
+ updatePosition();
27354
+ });
27355
+ }, [
27356
+ updatePosition,
27357
+ visible
27358
+ ]);
26697
27359
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
26698
- if (visible && tooltipRef.current) {
26699
- const viewportPadding = 12;
26700
- const tooltip = tooltipRef.current;
26701
- const tooltipWidth = tooltip.offsetWidth;
26702
- const tooltipHeight = tooltip.offsetHeight;
26703
- const windowWidth = window.innerWidth;
26704
- const windowHeight = window.innerHeight;
26705
- const nextX = x + tooltipWidth > windowWidth - viewportPadding ? x - tooltipWidth - 10 : x;
26706
- const nextY = y + tooltipHeight > windowHeight - viewportPadding ? y - tooltipHeight - 10 : y;
26707
- setPosition({
26708
- x: Math.max(viewportPadding, Math.min(nextX, windowWidth - tooltipWidth - viewportPadding)),
26709
- y: Math.max(viewportPadding, Math.min(nextY, windowHeight - tooltipHeight - viewportPadding))
26710
- });
26711
- }
27360
+ scheduleRef.current = schedulePositionUpdate;
27361
+ return ()=>{
27362
+ if (scheduleRef.current === schedulePositionUpdate) scheduleRef.current = null;
27363
+ };
26712
27364
  }, [
26713
- x,
26714
- y,
27365
+ schedulePositionUpdate,
27366
+ scheduleRef
27367
+ ]);
27368
+ (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
27369
+ if (!visible) return;
27370
+ schedulePositionUpdate();
27371
+ return ()=>{
27372
+ if (null === frameRef.current) return;
27373
+ cancelAnimationFrame(frameRef.current);
27374
+ frameRef.current = null;
27375
+ };
27376
+ }, [
27377
+ schedulePositionUpdate,
26715
27378
  visible
26716
27379
  ]);
26717
27380
  if (!visible) return null;
@@ -26719,8 +27382,9 @@ const overlays_Tooltip_Tooltip = ({ title, description, visible, x, y, startFreq
26719
27382
  ref: tooltipRef,
26720
27383
  className: "pointer-events-none fixed z-[1000] max-w-[300px] rounded-[var(--radius-surface)] border border-border/70 bg-chart-panel/95 p-[var(--size-gap-base)] text-chart-panel-foreground shadow-lg backdrop-blur-md",
26721
27384
  style: {
26722
- left: position.x,
26723
- top: position.y
27385
+ left: 0,
27386
+ top: 0,
27387
+ transform: `translate3d(${x}px, ${y}px, 0)`
26724
27388
  },
26725
27389
  children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(AllocationInfo, {
26726
27390
  allocationInfo: {
@@ -26731,43 +27395,64 @@ const overlays_Tooltip_Tooltip = ({ title, description, visible, x, y, startFreq
26731
27395
  centerFrequency,
26732
27396
  stepFrequency,
26733
27397
  bandwidth,
26734
- modulation
27398
+ modulation,
27399
+ channelTitle
26735
27400
  }
26736
27401
  })
26737
27402
  });
26738
27403
  };
26739
27404
  const overlays_Tooltip = overlays_Tooltip_Tooltip;
26740
- const FrequencyAllocation = ()=>{
26741
- const unit = useSelector((state)=>state.axisX.unit);
26742
- const segments = useSelector((state)=>state.segments);
26743
- const display = useSelector((state)=>state.frequencyAllocation.display);
26744
- const show = useSelector((state)=>state.frequencyAllocation.show);
26745
- const zoomOffStyle = useSelector((state)=>state.zoom.style);
26746
- const frequencyAllocationData = useFrequencyAllocationData_useFrequencyAllocationData();
27405
+ const FrequencyAllocation_FrequencyAllocation = ()=>{
27406
+ const unit = useStore_useSelector((state)=>state.axisX.unit);
27407
+ const segments = useStore_useSelector((state)=>state.segments);
27408
+ const display = useStore_useSelector((state)=>state.frequencyAllocation.display);
27409
+ const show = useStore_useSelector((state)=>state.frequencyAllocation.show);
27410
+ const density = useStore_useSelector((state)=>state.frequencyAllocation.density);
27411
+ const zoomOffStyle = useStore_useSelector((state)=>state.zoom.style);
27412
+ const frequencyAllocationChannels = useFrequencyAllocationChannels();
26747
27413
  const [tooltipInfo, setTooltipInfo] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)({
26748
27414
  visible: false,
26749
27415
  x: 0,
26750
27416
  y: 0
26751
27417
  });
26752
- const segmentData = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>resolveFrequencyAllocationSegments({
27418
+ const tooltipPositionRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)({
27419
+ x: 0,
27420
+ y: 0
27421
+ });
27422
+ const scheduleTooltipPositionRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
27423
+ const updateTooltipPosition = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((event)=>{
27424
+ tooltipPositionRef.current = {
27425
+ x: event.clientX + 10,
27426
+ y: event.clientY + 10
27427
+ };
27428
+ scheduleTooltipPositionRef.current?.();
27429
+ }, []);
27430
+ const laneData = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>resolveFrequencyAllocationLanes({
26753
27431
  segments,
26754
- allocations: frequencyAllocationData
27432
+ channels: frequencyAllocationChannels
26755
27433
  }), [
26756
27434
  segments,
26757
- frequencyAllocationData
27435
+ frequencyAllocationChannels
26758
27436
  ]);
27437
+ const { laneHeight, showLabels } = resolveFrequencyAllocationDensity({
27438
+ density,
27439
+ channelCount: laneData.length
27440
+ });
27441
+ const containerHeight = Math.max(laneHeight, laneData.length * laneHeight);
26759
27442
  const handleTooltipUpdate = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((tooltipData)=>{
26760
27443
  setTooltipInfo((prev)=>({
26761
27444
  ...prev,
26762
27445
  ...tooltipData
26763
27446
  }));
26764
27447
  }, []);
26765
- const handleMouseEnter = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((band, range)=>(e)=>{
27448
+ const handleMouseEnter = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)(({ band, channelTitle, range })=>(e)=>{
27449
+ updateTooltipPosition(e);
26766
27450
  const tooltipData = {
26767
27451
  ...band,
26768
27452
  visible: true,
26769
- x: e.clientX + 10,
26770
- y: e.clientY + 10,
27453
+ x: tooltipPositionRef.current.x,
27454
+ y: tooltipPositionRef.current.y,
27455
+ channelTitle,
26771
27456
  startFrequency: `${range.start}${unit}`,
26772
27457
  stopFrequency: `${range.stop}${unit}`
26773
27458
  };
@@ -26778,15 +27463,13 @@ const FrequencyAllocation = ()=>{
26778
27463
  handleTooltipUpdate(tooltipData);
26779
27464
  }, [
26780
27465
  unit,
26781
- handleTooltipUpdate
27466
+ handleTooltipUpdate,
27467
+ updateTooltipPosition
26782
27468
  ]);
26783
27469
  const handleMouseMove = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((e)=>{
26784
- handleTooltipUpdate({
26785
- x: e.clientX + 10,
26786
- y: e.clientY + 10
26787
- });
27470
+ updateTooltipPosition(e);
26788
27471
  }, [
26789
- handleTooltipUpdate
27472
+ updateTooltipPosition
26790
27473
  ]);
26791
27474
  const handleMouseLeave = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)(()=>{
26792
27475
  handleTooltipUpdate({
@@ -26795,28 +27478,42 @@ const FrequencyAllocation = ()=>{
26795
27478
  }, [
26796
27479
  handleTooltipUpdate
26797
27480
  ]);
26798
- if (!show || !display) return null;
27481
+ if (!show || !display || 0 === laneData.length) return null;
26799
27482
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)("div", {
26800
- className: "pointer-events-none absolute inset-x-0 bottom-0 z-[5] flex h-3.5 w-full select-none items-center overflow-hidden bg-transparent",
27483
+ className: "pointer-events-none absolute inset-x-0 bottom-0 z-[5] flex w-full select-none items-center overflow-hidden",
27484
+ style: {
27485
+ height: containerHeight,
27486
+ backgroundColor: 'color-mix(in srgb, var(--chart-surface) 12%, transparent)'
27487
+ },
26801
27488
  children: [
26802
27489
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
26803
- className: "absolute right-0 top-0 flex h-full w-full items-end will-change-transform",
27490
+ className: "absolute right-0 top-0 h-full w-full will-change-transform",
26804
27491
  style: zoomOffStyle ?? void 0,
26805
- children: segmentData.map(({ segmentIndex, bandPositions, style })=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(AllocationSegments, {
26806
- style: style,
26807
- bandPositions: bandPositions,
26808
- onMouseEnter: handleMouseEnter,
26809
- onMouseMove: handleMouseMove,
26810
- onMouseLeave: handleMouseLeave
26811
- }, `segment-${segmentIndex}`))
27492
+ children: laneData.map(({ channel, channelIndex, segmentData })=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
27493
+ className: "absolute left-0 w-full",
27494
+ style: {
27495
+ bottom: channelIndex * laneHeight,
27496
+ height: laneHeight
27497
+ },
27498
+ children: segmentData.map(({ segmentIndex, bandPositions, style })=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(presenters_AllocationSegments, {
27499
+ style: style,
27500
+ bandPositions: bandPositions,
27501
+ showLabels: showLabels,
27502
+ onMouseEnter: handleMouseEnter,
27503
+ onMouseMove: handleMouseMove,
27504
+ onMouseLeave: handleMouseLeave
27505
+ }, `channel-${channel.id}-segment-${segmentIndex}`))
27506
+ }, `channel-${channel.id}`))
26812
27507
  }),
26813
27508
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(overlays_Tooltip, {
26814
- ...tooltipInfo
27509
+ ...tooltipInfo,
27510
+ positionRef: tooltipPositionRef,
27511
+ scheduleRef: scheduleTooltipPositionRef
26815
27512
  })
26816
27513
  ]
26817
27514
  });
26818
27515
  };
26819
- const Spectrum_FrequencyAllocation = FrequencyAllocation;
27516
+ const FrequencyAllocation = FrequencyAllocation_FrequencyAllocation;
26820
27517
  const useUpdateKey = (id)=>{
26821
27518
  const [updateKey, setUpdateKey] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(0);
26822
27519
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
@@ -26950,6 +27647,12 @@ const FrequencyTagLine_FrequencyTagLine = (props)=>{
26950
27647
  });
26951
27648
  };
26952
27649
  const FrequencyTagLine = /*#__PURE__*/ __WEBPACK_EXTERNAL_MODULE_react__["default"].memo(FrequencyTagLine_FrequencyTagLine);
27650
+ const LIMIT_THRESHOLD_TEXT_STYLE = {
27651
+ color: SPECTRUM_THRESHOLD_COLOR
27652
+ };
27653
+ const LIMIT_THRESHOLD_LINE_STYLE = {
27654
+ borderColor: SPECTRUM_THRESHOLD_COLOR
27655
+ };
26953
27656
  const Item_Item = ({ value: value1, onChange })=>{
26954
27657
  const { state: { axisY, limit } } = useStore_useStore();
26955
27658
  const { label, disabled } = limit;
@@ -27014,6 +27717,7 @@ const Item_Item = ({ value: value1, onChange })=>{
27014
27717
  type: "button",
27015
27718
  disabled: disabled,
27016
27719
  className: "pointer-events-auto absolute right-7 top-[-28px] z-[8] flex h-6 appearance-none items-center justify-center rounded-[var(--radius-control)] border-0 bg-secondary px-2 text-xs text-foreground",
27720
+ style: LIMIT_THRESHOLD_TEXT_STYLE,
27017
27721
  onClick: ()=>setIsEdit(true),
27018
27722
  children: [
27019
27723
  label,
@@ -27023,6 +27727,7 @@ const Item_Item = ({ value: value1, onChange })=>{
27023
27727
  ]
27024
27728
  }) : /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)("div", {
27025
27729
  className: "pointer-events-auto absolute right-7 top-[-28px] z-[8] flex h-6 items-center justify-between bg-secondary px-2 text-xs text-foreground",
27730
+ style: LIMIT_THRESHOLD_TEXT_STYLE,
27026
27731
  children: [
27027
27732
  label,
27028
27733
  "\xa0",
@@ -27034,7 +27739,8 @@ const Item_Item = ({ value: value1, onChange })=>{
27034
27739
  min: min,
27035
27740
  max: max,
27036
27741
  step: step / 5,
27037
- className: "h-auto w-14 border-none bg-transparent p-0 text-center text-primary outline-none [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none",
27742
+ className: "h-auto w-14 border-none bg-transparent p-0 text-center outline-none [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none",
27743
+ style: LIMIT_THRESHOLD_TEXT_STYLE,
27038
27744
  onKeyDown: onEnter
27039
27745
  }),
27040
27746
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
@@ -27044,7 +27750,8 @@ const Item_Item = ({ value: value1, onChange })=>{
27044
27750
  ]
27045
27751
  }),
27046
27752
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
27047
- className: "absolute right-0 top-[-0.5px] z-[8] h-0 w-full border-b border-dashed border-primary"
27753
+ className: "absolute right-0 top-[-0.5px] z-[8] h-0 w-full border-b border-dashed",
27754
+ style: LIMIT_THRESHOLD_LINE_STYLE
27048
27755
  })
27049
27756
  ]
27050
27757
  })
@@ -27185,7 +27892,8 @@ const useMarkerEvents = (props)=>{
27185
27892
  const stateRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)({
27186
27893
  isDown: null,
27187
27894
  dragStart: null,
27188
- isHover: ''
27895
+ isHover: '',
27896
+ hoverId: null
27189
27897
  });
27190
27898
  const getEventContainer = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)(()=>document.getElementById(getEID(id)) ?? document.getElementById(id), [
27191
27899
  id
@@ -27238,47 +27946,56 @@ const useMarkerEvents = (props)=>{
27238
27946
  ]);
27239
27947
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
27240
27948
  const isShow = display;
27241
- createMoveEventManager(id, useMarkerEvents_COMPONENT_KEY, (_, e)=>{
27949
+ const cleanupMove = createMoveEventManager(id, useMarkerEvents_COMPONENT_KEY, (_, e)=>{
27242
27950
  if (!isShow) return;
27243
27951
  if (void 0 !== e.left) {
27244
- stateRef.current.isHover = checkHover({
27952
+ const nextHover = checkHover({
27245
27953
  left: e.left
27246
27954
  });
27955
+ const nextHoverId = 'object' == typeof nextHover ? nextHover.id : null;
27956
+ if (stateRef.current.hoverId === nextHoverId) {
27957
+ stateRef.current.isHover = nextHover;
27958
+ return;
27959
+ }
27960
+ stateRef.current.isHover = nextHover;
27961
+ stateRef.current.hoverId = nextHoverId;
27247
27962
  onHover({
27248
27963
  left: e.left
27249
27964
  });
27250
27965
  }
27251
27966
  });
27252
- createDragEventManager(id, useMarkerEvents_COMPONENT_KEY, (_, e)=>{
27967
+ const cleanupDrag = createDragEventManager(id, useMarkerEvents_COMPONENT_KEY, (_, e)=>{
27253
27968
  const { isDown } = stateRef.current;
27254
27969
  if (isShow && isDown && compareEventPriority(id, useMarkerEvents_COMPONENT_KEY) && !fixed) onUpdateMarker(isDown.id, {
27255
27970
  left: e.left,
27256
27971
  top: e.top
27257
27972
  });
27258
27973
  });
27259
- createMouseDownEventManager(id, useMarkerEvents_COMPONENT_KEY, (e)=>{
27974
+ const cleanupMouseDown = createMouseDownEventManager(id, useMarkerEvents_COMPONENT_KEY, (e)=>{
27260
27975
  if (!isShow) return;
27261
27976
  const marker = findMarkerByPosition(e) || ('object' == typeof stateRef.current.isHover ? stateRef.current.isHover : null);
27262
27977
  if (marker && !fixed) stateRef.current.isDown = marker;
27263
27978
  });
27264
- createMouseUpEventManager(id, useMarkerEvents_COMPONENT_KEY, ()=>{
27979
+ const cleanupMouseUp = createMouseUpEventManager(id, useMarkerEvents_COMPONENT_KEY, ()=>{
27265
27980
  if (!isShow) return;
27266
27981
  stateRef.current.isDown = null;
27267
27982
  resetEventLevel(id, useMarkerEvents_COMPONENT_KEY);
27268
27983
  });
27269
- createMouseLeaveEventManager(id, useMarkerEvents_COMPONENT_KEY, ()=>{
27984
+ const cleanupMouseLeave = createMouseLeaveEventManager(id, useMarkerEvents_COMPONENT_KEY, ()=>{
27270
27985
  if (!isShow) return;
27986
+ const hadHover = null !== stateRef.current.hoverId;
27271
27987
  stateRef.current.isDown = null;
27272
27988
  stateRef.current.isHover = '';
27989
+ stateRef.current.hoverId = null;
27273
27990
  resetEventLevel(id, useMarkerEvents_COMPONENT_KEY);
27274
- onResetHover();
27991
+ if (hadHover) onResetHover();
27275
27992
  });
27276
- createLongPressEventManager(id, useMarkerEvents_COMPONENT_KEY, (_, e)=>{
27993
+ const cleanupLongPress = createLongPressEventManager(id, useMarkerEvents_COMPONENT_KEY, (_, e)=>{
27277
27994
  if (!isShow || !compareEventPriority(id, useMarkerEvents_COMPONENT_KEY)) return;
27278
27995
  const marker = findMarkerByPosition(e) || ('object' == typeof stateRef.current.isHover ? stateRef.current.isHover : null);
27279
27996
  if (marker?.id) onToggleSelect(marker.id);
27280
27997
  });
27281
- createDoubleClickEventManager(id, useMarkerEvents_COMPONENT_KEY, (_, e)=>{
27998
+ const cleanupDoubleClick = createDoubleClickEventManager(id, useMarkerEvents_COMPONENT_KEY, (_, e)=>{
27282
27999
  if (!isShow || !compareEventPriority(id, useMarkerEvents_COMPONENT_KEY)) return;
27283
28000
  if (void 0 !== e.left) {
27284
28001
  const nearbyMarker = checkHover({
@@ -27290,6 +28007,15 @@ const useMarkerEvents = (props)=>{
27290
28007
  });
27291
28008
  }
27292
28009
  });
28010
+ return ()=>{
28011
+ cleanupMove?.();
28012
+ cleanupDrag?.();
28013
+ cleanupMouseDown?.();
28014
+ cleanupMouseUp?.();
28015
+ cleanupMouseLeave?.();
28016
+ cleanupLongPress?.();
28017
+ cleanupDoubleClick?.();
28018
+ };
27293
28019
  }, [
27294
28020
  id,
27295
28021
  display,
@@ -28680,19 +29406,17 @@ function useSignalDataManager() {
28680
29406
  updateSignalData
28681
29407
  };
28682
29408
  }
28683
- const Signal = ({ show = true, display = true })=>{
28684
- const segments = useSelector((state)=>state.segments);
28685
- const zoomOffStyle = useSelector((state)=>state.zoom.style);
28686
- const cursor = useSelector((state)=>state.cursor);
28687
- const signal = useSelector((state)=>state.signal);
28688
- const { coord: { left } } = cursor;
29409
+ const Signal = ({ id, show = true, display = true })=>{
29410
+ const segments = useStore_useSelector((state)=>state.segments);
29411
+ const zoomOffStyle = useStore_useSelector((state)=>state.zoom.style);
29412
+ const signal = useStore_useSelector((state)=>state.signal);
29413
+ const cursorSample = useCursorSample(id);
29414
+ const left = cursorSample?.coord.left;
28689
29415
  const signalItems = useUnifiedSignals({
28690
29416
  respectVisibility: true
28691
29417
  });
28692
29418
  const shouldDisplay = signal.show && signal.display && display;
28693
- const isCursorActive = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>cursor_hasActiveSpectrumCursor(cursor), [
28694
- cursor
28695
- ]);
29419
+ const isCursorActive = !!cursorSample;
28696
29420
  const currentPosition = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>isCursorActive && 'number' == typeof left ? frequencyCalculation_calculateCursorPosition(left, segments) : {
28697
29421
  segmentIndex: -1,
28698
29422
  pointIndex: -1
@@ -28706,18 +29430,23 @@ const Signal = ({ show = true, display = true })=>{
28706
29430
  isCursorActive,
28707
29431
  segments
28708
29432
  ]);
28709
- const segmentData = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>resolveSignalSegments({
29433
+ const segmentData = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>resolveStaticSignalSegments({
28710
29434
  segments,
28711
- signalItems,
29435
+ signalItems
29436
+ }), [
29437
+ segments,
29438
+ signalItems
29439
+ ]);
29440
+ const activeSignalKey = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>resolveActiveSignalKey({
29441
+ segmentData,
28712
29442
  isCursorActive,
28713
29443
  currentFrequency,
28714
29444
  currentPosition
28715
29445
  }), [
28716
- segments,
28717
- signalItems,
28718
- isCursorActive,
28719
29446
  currentFrequency,
28720
- currentPosition
29447
+ currentPosition,
29448
+ isCursorActive,
29449
+ segmentData
28721
29450
  ]);
28722
29451
  if (!show || !shouldDisplay) return null;
28723
29452
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
@@ -28725,10 +29454,10 @@ const Signal = ({ show = true, display = true })=>{
28725
29454
  children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
28726
29455
  className: "absolute right-0 top-0 flex h-full w-full",
28727
29456
  style: zoomOffStyle ?? void 0,
28728
- children: segmentData.map(({ segmentIndex, signalPositions, activeSignalKey, style })=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(SignalSegments, {
29457
+ children: segmentData.map(({ segmentIndex, signalPositions, style })=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(SignalSegments, {
28729
29458
  style: style,
28730
29459
  signalPositions: signalPositions,
28731
- activeSignalKey: activeSignalKey,
29460
+ activeSignalKey: currentPosition.segmentIndex === segmentIndex ? activeSignalKey : void 0,
28732
29461
  segmentIndex: segmentIndex
28733
29462
  }, `segment-${segmentIndex}`))
28734
29463
  })
@@ -28737,7 +29466,7 @@ const Signal = ({ show = true, display = true })=>{
28737
29466
  const Spectrum_Signal = Signal;
28738
29467
  const Stripe_COMPONENT_KEY = constants_ToolType.Stripe;
28739
29468
  const EDGE_HIT_SLOP = 1.5;
28740
- const clampPercent = (value1)=>Math.max(0, Math.min(100, value1));
29469
+ const Stripe_clampPercent = (value1)=>Math.max(0, Math.min(100, value1));
28741
29470
  const resolveDragMode = ({ cursor, left, right })=>{
28742
29471
  const leftDistance = Math.abs(cursor - left);
28743
29472
  const rightDistance = Math.abs(cursor - right);
@@ -28782,7 +29511,7 @@ const Stripe_Stripe = ({ id })=>{
28782
29511
  const updateStripe = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((e)=>{
28783
29512
  const dragState = dragStateRef.current;
28784
29513
  if (!dragState || !Number.isFinite(e?.left)) return;
28785
- const coordinateCursor = clampPercent(e.left);
29514
+ const coordinateCursor = Stripe_clampPercent(e.left);
28786
29515
  const currentStripe = stripeRef.current;
28787
29516
  const { mode, startCursor, startLeft, startRight } = dragState;
28788
29517
  let nextLeft = startLeft;
@@ -28790,7 +29519,7 @@ const Stripe_Stripe = ({ id })=>{
28790
29519
  if ('move' === mode) {
28791
29520
  const delta = coordinateCursor - startCursor;
28792
29521
  const width = startRight - startLeft;
28793
- nextLeft = clampPercent(startLeft + delta);
29522
+ nextLeft = Stripe_clampPercent(startLeft + delta);
28794
29523
  nextRight = nextLeft + width;
28795
29524
  if (nextRight > 100) {
28796
29525
  nextRight = 100;
@@ -28834,7 +29563,7 @@ const Stripe_Stripe = ({ id })=>{
28834
29563
  createMouseDownEventManager(id, Stripe_COMPONENT_KEY, (e)=>{
28835
29564
  if (!show || !display || !Number.isFinite(e?.left)) return;
28836
29565
  const currentStripe = stripeRef.current;
28837
- const cursor = clampPercent(e.left);
29566
+ const cursor = Stripe_clampPercent(e.left);
28838
29567
  dragStateRef.current = {
28839
29568
  mode: resolveDragMode({
28840
29569
  cursor,
@@ -28996,7 +29725,9 @@ const Spectrum_Spectrum = (props)=>{
28996
29725
  id: id,
28997
29726
  type: constants_ModuleType.Spectrum
28998
29727
  }),
28999
- /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Spectrum_Signal, {}),
29728
+ /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Spectrum_Signal, {
29729
+ id: id
29730
+ }),
29000
29731
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Spectrum_DragFrame, {
29001
29732
  id: id
29002
29733
  }),
@@ -29008,7 +29739,7 @@ const Spectrum_Spectrum = (props)=>{
29008
29739
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(FrequencyTagLine, {
29009
29740
  id: id
29010
29741
  }),
29011
- /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Spectrum_FrequencyAllocation, {}),
29742
+ /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(FrequencyAllocation, {}),
29012
29743
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(DeltaMeasurement, {})
29013
29744
  ]
29014
29745
  })
@@ -29050,7 +29781,7 @@ const LevelStream_Chart_Chart = (props)=>{
29050
29781
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(components_FlexBox, {
29051
29782
  children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(modules_Spectrum, {
29052
29783
  children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(PluginBox, {
29053
- children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Level, {
29784
+ children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(modules_Level, {
29054
29785
  opacity: 0.5
29055
29786
  })
29056
29787
  })
@@ -29301,9 +30032,9 @@ const charts_Occupancy_Occupancy = withChartPublisher(OccupancyChart, 'Occupancy
29301
30032
  const charts_Occupancy = charts_Occupancy_Occupancy;
29302
30033
  const Zoom_Zoom = ()=>{
29303
30034
  const dispatch = useStoreDispatch();
29304
- const zoom = useSelector((state)=>state.zoom);
29305
- const totalPoints = useSelector((state)=>state.segments.totalPoints) ?? 0;
29306
- const frequencyFormat = useSelector((state)=>state.axisX.frequencyFormat);
30035
+ const zoom = useStore_useSelector((state)=>state.zoom);
30036
+ const totalPoints = useStore_useSelector((state)=>state.segments.totalPoints) ?? 0;
30037
+ const frequencyFormat = useStore_useSelector((state)=>state.axisX.frequencyFormat);
29307
30038
  const { interval: { start, end }, onChange } = zoom;
29308
30039
  const ticks = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
29309
30040
  if (!totalPoints || !frequencyFormat) return [
@@ -29587,6 +30318,16 @@ const useMarkerPublish_useMarkerPublish = ({ globalID })=>{
29587
30318
  };
29588
30319
  };
29589
30320
  const useMarkerPublish = useMarkerPublish_useMarkerPublish;
30321
+ function resolveThresholdDataOptions({ segmentOffset, offset }) {
30322
+ const options = {};
30323
+ if (void 0 !== segmentOffset) options.segmentOffset = segmentOffset;
30324
+ if (void 0 !== offset) options.offset = offset;
30325
+ return void 0 !== options.segmentOffset || void 0 !== options.offset ? options : void 0;
30326
+ }
30327
+ function setAnalyzerThresholdData(analyzer, payload) {
30328
+ if (!('thresholdData' in payload)) return;
30329
+ analyzer.setThresholdData(payload.thresholdData, resolveThresholdDataOptions(payload));
30330
+ }
29590
30331
  function useTemplateComparison() {
29591
30332
  const { state: { globalID, axisX: { frequencyFormat }, signal: { onChange } } } = useStore_useStore();
29592
30333
  const frequencyFormatRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(frequencyFormat);
@@ -29764,7 +30505,7 @@ function useSpectrumAnalyzer(props) {
29764
30505
  break;
29765
30506
  case constants_PSType.Spectrum:
29766
30507
  if (e.data) analyzer.current.process(e);
29767
- if ('thresholdData' in e) analyzer.current.setThresholdData(e.thresholdData);
30508
+ setAnalyzerThresholdData(analyzer.current, e);
29768
30509
  if (e.maxData) analyzer.current.setMaxData(e.maxData);
29769
30510
  if (e.minData) analyzer.current.setMinData(e.minData);
29770
30511
  if (e.avgData) analyzer.current.setAvgData(e.avgData);
@@ -29920,12 +30661,31 @@ const Spectrum_Chart_Chart = (props)=>{
29920
30661
  });
29921
30662
  };
29922
30663
  const Spectrum_Chart = Spectrum_Chart_Chart;
29923
- const SpectrumChart = (props)=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(src_store, {
30664
+ const heatmapCaptureDefaults_DEFAULT_SPECTRUM_TYPE = 'singleFrequency';
30665
+ const DEFAULT_HEATMAP_CAPTURE_TYPE = 'slider';
30666
+ const withSpectrumHeatmapCaptureDefaults = (props)=>{
30667
+ const type = props.type ?? heatmapCaptureDefaults_DEFAULT_SPECTRUM_TYPE;
30668
+ if (!props.heatmapElementID || type !== heatmapCaptureDefaults_DEFAULT_SPECTRUM_TYPE && 'scan' !== type && 'mscan' !== type) return props;
30669
+ return {
29924
30670
  ...props,
30671
+ heatmapCapture: {
30672
+ show: true,
30673
+ display: false,
30674
+ type: DEFAULT_HEATMAP_CAPTURE_TYPE,
30675
+ toolbarVariant: 'deltaMeasurement',
30676
+ ...props.heatmapCapture
30677
+ }
30678
+ };
30679
+ };
30680
+ const SpectrumChart = (props)=>{
30681
+ const normalizedProps = withSpectrumHeatmapCaptureDefaults(props);
30682
+ return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(src_store, {
30683
+ ...normalizedProps,
29925
30684
  children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Spectrum_Chart, {
29926
- ...props
30685
+ ...normalizedProps
29927
30686
  })
29928
30687
  });
30688
+ };
29929
30689
  const charts_Spectrum_Spectrum = withChartPublisher(SpectrumChart, 'Spectrum');
29930
30690
  const charts_Spectrum = charts_Spectrum_Spectrum;
29931
30691
  function initChartsTheme(options = {}) {
@@ -29942,4 +30702,4 @@ function initChartsTheme(options = {}) {
29942
30702
  };
29943
30703
  }
29944
30704
  initializeChartsThemeEnvironment();
29945
- export { constants_ChartType as ChartType, charts_Dial as Dial, constants_FrequencyUnit as FrequencyUnit, charts_Gauge as Gauge, charts_Heatmap as Heatmap, heatmap_HeatmapCaptureType as HeatmapCaptureType, IQ, LevelStream, constants_MarkerEventType as MarkerEventType, marker_MarkerMode as MarkerMode, constants_ModuleType as ModuleType, charts_Occupancy as Occupancy, constants_OptionKey as OptionKey, constants_PSType as PSType, constants_SegmentsEvent as SegmentsEvent, constants_SeriesType as SeriesType, signal_SignalDataType as SignalDataType, charts_Spectrum as Spectrum, constants_ToolType as ToolType, constants_ToolbarItemType as ToolbarItemType, formatFrequencyUnit, formatFrequencyUnitFromHz, formatFrequencyUnitFromMHz, getChartsThemeState, initChartsTheme, setFrequencyAllocationToCache, subscribeChartsThemeChange, useSafePublish, withChartPublisher };
30705
+ export { constants_ChartType as ChartType, charts_Dial as Dial, constants_FrequencyUnit as FrequencyUnit, charts_Gauge as Gauge, charts_Heatmap as Heatmap, heatmap_HeatmapCaptureType as HeatmapCaptureType, IQ, LevelStream, constants_MarkerEventType as MarkerEventType, marker_MarkerMode as MarkerMode, constants_ModuleType as ModuleType, charts_Occupancy as Occupancy, constants_OptionKey as OptionKey, constants_PSType as PSType, constants_SegmentsEvent as SegmentsEvent, constants_SeriesType as SeriesType, signal_SignalDataType as SignalDataType, charts_Spectrum as Spectrum, constants_ToolType as ToolType, constants_ToolbarItemType as ToolbarItemType, formatFrequencyUnit, formatFrequencyUnitFromHz, formatFrequencyUnitFromMHz, getChartsThemeState, initChartsTheme, setFrequencyAllocationChannelsToCache, setFrequencyAllocationToCache, subscribeChartsThemeChange, useSafePublish, withChartPublisher };