@rfkit/charts 1.5.1 → 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 (35) hide show
  1. package/charts/Spectrum/heatmapCaptureDefaults.d.ts +2 -0
  2. package/components/Cursor/useCursorSample.d.ts +2 -0
  3. package/components/EventBus/position.d.ts +8 -0
  4. package/components/EventBus/tools.d.ts +2 -1
  5. package/components/Overlay/Popover/index.d.ts +1 -0
  6. package/components/Toolbar/icons/DeltaMeasurementIcon.d.ts +3 -0
  7. package/components/Toolbar/icons/index.d.ts +1 -0
  8. package/components/ui/cursor-follow-layer.d.ts +1 -2
  9. package/hooks/spectrum/index.d.ts +1 -0
  10. package/hooks/spectrum/waterfall.d.ts +5 -0
  11. package/index.d.ts +2 -2
  12. package/index.js +1073 -374
  13. package/modules/Heatmap/cursorValue.d.ts +38 -0
  14. package/modules/Occupancy/CursorPopover.d.ts +4 -1
  15. package/modules/Spectrum/FrequencyAllocation/model/channelModel.d.ts +16 -0
  16. package/modules/Spectrum/FrequencyAllocation/model/density.d.ts +13 -0
  17. package/modules/Spectrum/FrequencyAllocation/model/index.d.ts +4 -3
  18. package/modules/Spectrum/FrequencyAllocation/model/resolveFrequencyAllocationData.d.ts +7 -1
  19. package/modules/Spectrum/FrequencyAllocation/model/resolver.d.ts +26 -1
  20. package/modules/Spectrum/FrequencyAllocation/model/useAllocationAtCursor.d.ts +3 -1
  21. package/modules/Spectrum/FrequencyAllocation/model/useFrequencyAllocationData.d.ts +1 -0
  22. package/modules/Spectrum/FrequencyAllocation/overlays/Tooltip/index.d.ts +8 -1
  23. package/modules/Spectrum/FrequencyAllocation/presenters/AllocationInfo/index.d.ts +1 -0
  24. package/modules/Spectrum/FrequencyAllocation/presenters/AllocationSegments/index.d.ts +3 -3
  25. package/modules/Spectrum/FrequencyAllocation/tools.d.ts +11 -1
  26. package/modules/Spectrum/FrequencyAllocation/types.d.ts +3 -0
  27. package/modules/Spectrum/FrequencyDataBoard/index.d.ts +2 -0
  28. package/modules/Spectrum/Signal/index.d.ts +1 -0
  29. package/modules/Spectrum/Signal/model/index.d.ts +1 -1
  30. package/modules/Spectrum/Signal/model/resolver.d.ts +25 -0
  31. package/modules/Spectrum/Signal/model/useStationInfoAtCursor.d.ts +3 -1
  32. package/package.json +1 -1
  33. package/runtime/interaction/index.d.ts +71 -0
  34. package/types/store/frequency.d.ts +8 -0
  35. 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
  }
@@ -2688,34 +2704,34 @@ var __webpack_modules__ = {
2688
2704
  translate: var(--tw-translate-x) var(--tw-translate-y);
2689
2705
  }
2690
2706
 
2691
- @media (min-width: 40rem) {
2692
- [data-rfkit-charts-root] .sm\\:flex-row {
2693
- flex-direction: row;
2694
- }
2695
-
2696
- [data-rfkit-charts-root] .sm\\:justify-end {
2697
- justify-content: flex-end;
2698
- }
2699
- }
2700
-
2701
- @media (min-width: 80rem) {
2702
- [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\\] {
2703
2709
  grid-template-columns: 220px minmax(0, 1.2fr) 320px;
2704
2710
  }
2705
2711
 
2706
- [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\\] {
2707
2713
  grid-template-columns: minmax(0, 1.2fr) auto auto;
2708
2714
  }
2709
2715
 
2710
- [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\\] {
2711
2717
  grid-template-columns: minmax(0, 1.35fr) 320px;
2712
2718
  }
2713
2719
 
2714
- [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\\)\\] {
2715
2721
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
2716
2722
  }
2717
2723
  }
2718
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
+
2719
2735
  [data-rfkit-charts-root] .\\[\\&_svg\\]\\:pointer-events-none svg {
2720
2736
  pointer-events: none;
2721
2737
  }
@@ -6133,7 +6149,7 @@ function useStore_useStore() {
6133
6149
  store
6134
6150
  };
6135
6151
  }
6136
- function useSelector(selector) {
6152
+ function useStore_useSelector(selector) {
6137
6153
  const { store } = useAppContext();
6138
6154
  return (0, __WEBPACK_EXTERNAL_MODULE_react__.useSyncExternalStore)(store.subscribe, ()=>selector(store.getState()), ()=>selector(store.getState()));
6139
6155
  }
@@ -6282,7 +6298,7 @@ const createNextSystemConfig = (system, size)=>({
6282
6298
  const Container_Container = (props)=>{
6283
6299
  const { children, style } = props;
6284
6300
  const dispatch = useStoreDispatch();
6285
- const system = useSelector((state)=>state.system);
6301
+ const system = useStore_useSelector((state)=>state.system);
6286
6302
  const globalID = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>createGUID(), []);
6287
6303
  const ref = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
6288
6304
  const systemRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(system);
@@ -17082,10 +17098,199 @@ const Dropdown = ({ value: value1, options, onChange, placeholder = "\u8BF7\u900
17082
17098
  });
17083
17099
  };
17084
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;
17085
17290
  const cursor_follow_layer_useSafeLayoutEffect = 'undefined' == typeof window ? __WEBPACK_EXTERNAL_MODULE_react__.useEffect : __WEBPACK_EXTERNAL_MODULE_react__.useLayoutEffect;
17086
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;
17087
17292
  const isPointWithinBounds = (clientX, clientY, bounds)=>clientX >= bounds.left && clientX <= bounds.right && clientY >= bounds.top && clientY <= bounds.bottom;
17088
- const CursorFollowLayer = ({ children, event, margin = 8, className })=>{
17293
+ const CursorFollowLayer = ({ children, interactionId, margin = 8, className })=>{
17089
17294
  const ref = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
17090
17295
  const portalRoot = useChartsPortalContainer('cursor-follow');
17091
17296
  const renderedChildren = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>__WEBPACK_EXTERNAL_MODULE_react__.Children.toArray(children), [
@@ -17097,10 +17302,12 @@ const CursorFollowLayer = ({ children, event, margin = 8, className })=>{
17097
17302
  ref.current.style.visibility = 'hidden';
17098
17303
  ref.current.style.transform = 'translate3d(-100vw, -100vh, 0)';
17099
17304
  }, []);
17100
- const updatePosition = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)(()=>{
17101
- 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;
17102
17309
  const node = ref.current;
17103
- const { clientX, clientY, bounds } = event;
17310
+ const { clientX, clientY, bounds } = pointer;
17104
17311
  if (!Number.isFinite(clientX) || !Number.isFinite(clientY) || !isValidBounds(bounds)) return void hideLayer();
17105
17312
  const { width, height } = node.getBoundingClientRect();
17106
17313
  const viewportWidth = window.innerWidth;
@@ -17130,11 +17337,26 @@ const CursorFollowLayer = ({ children, event, margin = 8, className })=>{
17130
17337
  node.style.visibility = 'visible';
17131
17338
  node.style.transform = `translate3d(${nextLeft}px, ${nextTop}px, 0)`;
17132
17339
  }, [
17133
- event,
17134
17340
  hasContent,
17135
17341
  hideLayer,
17136
17342
  margin
17137
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
+ ]);
17138
17360
  cursor_follow_layer_useSafeLayoutEffect(()=>{
17139
17361
  if (!portalRoot) return;
17140
17362
  portalRoot.setAttribute('data-rfkit-cursor-layer', 'true');
@@ -17150,14 +17372,17 @@ const CursorFollowLayer = ({ children, event, margin = 8, className })=>{
17150
17372
  });
17151
17373
  cursor_follow_layer_useSafeLayoutEffect(()=>{
17152
17374
  if (!ref.current || !hasContent) return;
17375
+ const handleResize = ()=>{
17376
+ updatePosition();
17377
+ };
17153
17378
  const observer = new ResizeObserver(()=>{
17154
17379
  updatePosition();
17155
17380
  });
17156
17381
  observer.observe(ref.current);
17157
- window.addEventListener('resize', updatePosition);
17382
+ window.addEventListener('resize', handleResize);
17158
17383
  return ()=>{
17159
17384
  observer.disconnect();
17160
- window.removeEventListener('resize', updatePosition);
17385
+ window.removeEventListener('resize', handleResize);
17161
17386
  };
17162
17387
  }, [
17163
17388
  hasContent,
@@ -17176,15 +17401,11 @@ const CursorFollowLayer = ({ children, event, margin = 8, className })=>{
17176
17401
  }), portalRoot);
17177
17402
  };
17178
17403
  const cursor_follow_layer = CursorFollowLayer;
17179
- const Popover = ({ children })=>{
17180
- const { state: { cursor: { event } } } = useStore_useStore();
17181
- if (!event) return null;
17182
- return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(cursor_follow_layer, {
17183
- event: event,
17404
+ const Popover = ({ children, id })=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(cursor_follow_layer, {
17405
+ interactionId: id,
17184
17406
  margin: UI_CONFIG.POPOVER_MARGIN,
17185
17407
  children: children
17186
17408
  });
17187
- };
17188
17409
  const Overlay_Popover = Popover;
17189
17410
  const Portal_Portal = ({ id, children })=>{
17190
17411
  const [container, setContainer] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(null);
@@ -20057,6 +20278,13 @@ function getSeriesWithGraphicType(globalID) {
20057
20278
  });
20058
20279
  return result;
20059
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);
20060
20288
  const applyAxisYRange = (currentAxisY, nextRange)=>{
20061
20289
  const [start, end] = nextRange;
20062
20290
  const currentRange = currentAxisY.range ?? constants_RANGE_DEFAULT;
@@ -20248,11 +20476,11 @@ function useSpectrumChartType({ type, heatmapElementID }) {
20248
20476
  ]);
20249
20477
  return (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
20250
20478
  let enableMetrics = false;
20251
- let enableWaterfall = false;
20252
- if (type === constants_ChartType.SingleFrequency || type === constants_ChartType.Scan || type === constants_ChartType.MScan) {
20253
- enableMetrics = true;
20254
- enableWaterfall = !!heatmapElementID;
20255
- }
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;
20256
20484
  return {
20257
20485
  enableMetrics,
20258
20486
  enableWaterfall
@@ -20514,6 +20742,25 @@ function convertCoordToVisualLeft({ coord, zoom, segments }) {
20514
20742
  const index = Math.min(Math.round(safeLift / 100 * (totalPoints - 1)), totalPoints - 1);
20515
20743
  return (index - start) * 100 / (end - start + 1);
20516
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
+ };
20517
20764
  function getEID(id) {
20518
20765
  return `EVENTBUS-${id}`;
20519
20766
  }
@@ -20531,16 +20778,7 @@ const createMouseEnterEventManager = (id, name, func)=>subscription_createSubscr
20531
20778
  const createWheelEventManager = (id, name, func)=>subscription_createSubscriptionManager(`${generateRecursiveId(id, func)}-wheel`, name, func, id);
20532
20779
  const createDragEventManager = (id, name, func)=>subscription_createSubscriptionManager(`${generateRecursiveId(id, func)}-drag`, name, func, id);
20533
20780
  const createLongPressEventManager = (id, name, func)=>subscription_createSubscriptionManager(`${generateRecursiveId(id, func)}-long-press`, name, func, id);
20534
- const calculateEventRelativePosition = (e)=>{
20535
- const { target, clientX, clientY } = e;
20536
- const { left, top, width, height } = target.getBoundingClientRect();
20537
- const x = (clientX - left) / width * 100;
20538
- const y = (clientY - top) / height * 100;
20539
- return {
20540
- left: x,
20541
- top: y
20542
- };
20543
- };
20781
+ const calculateEventRelativePosition = (e)=>calculateEventRelativePositionFromSource(e);
20544
20782
  const EVENT_PRIORITY_LEVEL_DEFAULT = 'void';
20545
20783
  const EVENT_PRIORITY_LEVELS = {
20546
20784
  [EVENT_PRIORITY_LEVEL_DEFAULT]: 0,
@@ -20609,6 +20847,20 @@ const FrequencyDisplay = ({ frequency, unit })=>frequency ? /*#__PURE__*/ (0, __
20609
20847
  unit
20610
20848
  ]
20611
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
+ };
20612
20864
  function useSeriesManager(globalID, options = {}) {
20613
20865
  const { subscribeToMode = true, subscribeToData = true, watchSeries } = options;
20614
20866
  const [updateCounter, setUpdateCounter] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(0);
@@ -20696,7 +20948,7 @@ function getStableOrder(currentNames) {
20696
20948
  }
20697
20949
  function useFilteredSeries_useFilteredSeries(globalID, filter) {
20698
20950
  const { series } = useSeriesManager(globalID);
20699
- const { state: { series: { legendExternal } } } = useStore_useStore();
20951
+ const legendExternal = useStore_useSelector((state)=>state.series.legendExternal);
20700
20952
  const filteredData = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
20701
20953
  const filtered = Array.from(series.values()).filter((config)=>{
20702
20954
  if (legendExternal.includes(config.name)) return false;
@@ -20724,9 +20976,99 @@ function useFilteredSeries_useFilteredSeries(globalID, filter) {
20724
20976
  ]);
20725
20977
  return filteredData;
20726
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
+ };
20727
21064
  const HeatmapCursorPopover = ({ id })=>{
20728
- const { state: { cursor: { coord }, axisX: { frequencyFormat, unit: axisXUnit = '' }, globalID, axisY: { unit: axisYUnit } } } = useStore_useStore();
20729
- 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;
20730
21072
  const updateKey = useCursorPopoverUpdateKey('HeatmapPopover', id);
20731
21073
  const [value1, setValue] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)('');
20732
21074
  const [timestamp, setTimestamp] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)('');
@@ -20744,23 +21086,22 @@ const HeatmapCursorPopover = ({ id })=>{
20744
21086
  setTimestamp('');
20745
21087
  return;
20746
21088
  }
20747
- const yIndex = Math.max(0, Math.min(outputWaterfall.length - 1, Math.round(outputWaterfall.length * (100 - top) / 100)));
20748
- const outputFrame = outputWaterfall[yIndex];
20749
- if (!outputFrame || 0 === outputFrame.length) return void setValue('');
20750
- const rawFrame = snapshot.rawData?.waterfallData?.[yIndex];
20751
- const globalIndex = snapshot.cursorIndex?.globalIndex;
20752
- 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;
20753
- const exactRawValue = void 0 !== rawXIndex && rawFrame ? rawFrame[rawXIndex] : void 0;
20754
- const sampledXIndex = leftToIndex(left, outputFrame.length);
20755
- const sampledValue = outputFrame[sampledXIndex];
20756
- const nextValue = Number.isFinite(exactRawValue) ? exactRawValue : sampledValue;
20757
- setValue('number' == typeof nextValue && Number.isFinite(nextValue) ? nextValue.toFixed(1) : '');
20758
- const frameTimestamp = outputFrame.timestamp;
20759
- 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);
20760
21100
  }, [
20761
21101
  globalID,
20762
21102
  left,
20763
21103
  top,
21104
+ sample?.version,
20764
21105
  updateKey
20765
21106
  ]);
20766
21107
  const frequency = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>'number' == typeof left ? frequencyFormat?.(left) ?? '' : '', [
@@ -20809,8 +21150,10 @@ const HeatmapCursorPopover = ({ id })=>{
20809
21150
  };
20810
21151
  const CursorPopover = HeatmapCursorPopover;
20811
21152
  const LevelCursorPopover = ({ id })=>{
20812
- const { state: { cursor: { coord }, globalID, axisY: { unit: axisYUnit } } } = useStore_useStore();
20813
- 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;
20814
21157
  const updateKey = useCursorPopoverUpdateKey('LevelStreamPopover', id);
20815
21158
  const [value1, setValue] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)('');
20816
21159
  const [timestamp, setTimestamp] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)('');
@@ -20837,6 +21180,7 @@ const LevelCursorPopover = ({ id })=>{
20837
21180
  }, [
20838
21181
  globalID,
20839
21182
  left,
21183
+ sample?.version,
20840
21184
  updateKey
20841
21185
  ]);
20842
21186
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)(components_Mask, {
@@ -20870,9 +21214,12 @@ const LevelCursorPopover = ({ id })=>{
20870
21214
  });
20871
21215
  };
20872
21216
  const Level_CursorPopover = LevelCursorPopover;
20873
- const OccupancyCursorPopover = ()=>{
20874
- const { state: { cursor: { coord }, axisX: { frequencyFormat, unit: axisXUnit = '' }, globalID } } = useStore_useStore();
20875
- 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;
20876
21223
  const value1 = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
20877
21224
  if (!globalID || 'number' != typeof left || !Number.isFinite(left)) return '';
20878
21225
  const snapshot = withDatabase(globalID).getAllRawData(left);
@@ -20888,7 +21235,8 @@ const OccupancyCursorPopover = ()=>{
20888
21235
  return '';
20889
21236
  }, [
20890
21237
  globalID,
20891
- left
21238
+ left,
21239
+ sample?.version
20892
21240
  ]);
20893
21241
  const frequency = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>'number' == typeof left ? frequencyFormat?.(left) ?? '' : '', [
20894
21242
  left,
@@ -20962,7 +21310,7 @@ const compareFrequencyMatchedCandidates = (currentFrequency, a, b)=>{
20962
21310
  if (0 !== widthDiff) return widthDiff;
20963
21311
  const centerDistanceDiff = Math.abs(getRangeCenter(a.range) - currentFrequency) - Math.abs(getRangeCenter(b.range) - currentFrequency);
20964
21312
  if (0 !== centerDistanceDiff) return centerDistanceDiff;
20965
- const stationPriorityDiff = Number(isStationInfo(b.item)) - Number(isStationInfo(a.item));
21313
+ const stationPriorityDiff = Number(utils_isStationInfo(b.item)) - Number(utils_isStationInfo(a.item));
20966
21314
  if (0 !== stationPriorityDiff) return stationPriorityDiff;
20967
21315
  return getUnifiedSignalKey(a.item).localeCompare(getUnifiedSignalKey(b.item));
20968
21316
  };
@@ -20973,15 +21321,15 @@ const compareIndexMatchedCandidates = (currentFrequency, currentPointIndex, a, b
20973
21321
  if (0 !== widthDiff) return widthDiff;
20974
21322
  const frequencyDistanceDiff = getFrequencyDistanceToRange(currentFrequency, a.range) - getFrequencyDistanceToRange(currentFrequency, b.range);
20975
21323
  if (0 !== frequencyDistanceDiff) return frequencyDistanceDiff;
20976
- const stationPriorityDiff = Number(isStationInfo(b.item)) - Number(isStationInfo(a.item));
21324
+ const stationPriorityDiff = Number(utils_isStationInfo(b.item)) - Number(utils_isStationInfo(a.item));
20977
21325
  if (0 !== stationPriorityDiff) return stationPriorityDiff;
20978
21326
  return getUnifiedSignalKey(a.item).localeCompare(getUnifiedSignalKey(b.item));
20979
21327
  };
20980
- function isStationInfo(item) {
21328
+ function utils_isStationInfo(item) {
20981
21329
  return 'signalName' in item && 'orgName' in item;
20982
21330
  }
20983
21331
  function getUnifiedSignalKey(item) {
20984
- if (isStationInfo(item)) return `${item.signalName}-${item.frequency}`;
21332
+ if (utils_isStationInfo(item)) return `${item.signalName}-${item.frequency}`;
20985
21333
  if (null != item.startFrequency && null != item.stopFrequency) return `${item.startFrequency}-${item.stopFrequency}`;
20986
21334
  return `${item.frequency}-${item.bandwidth}`;
20987
21335
  }
@@ -20993,7 +21341,7 @@ function toFrequencyRangeInput(item) {
20993
21341
  stopFrequency: null != item.stopFrequency ? Number(item.stopFrequency) : void 0
20994
21342
  };
20995
21343
  }
20996
- function resolveBestSignalMatch(candidates, options) {
21344
+ function utils_resolveBestSignalMatch(candidates, options) {
20997
21345
  const { currentFrequency, currentPointIndex } = options;
20998
21346
  const indexTolerance = options.indexTolerance ?? SIGNAL_INDEX_MATCH_TOLERANCE;
20999
21347
  if (!Number.isFinite(currentFrequency) || !Number.isFinite(currentPointIndex) || !candidates.length) return;
@@ -21006,7 +21354,7 @@ function resolveBestSignalMatch(candidates, options) {
21006
21354
  return indexMatched[0];
21007
21355
  }
21008
21356
  const resolveSignalPresentation = (item)=>{
21009
- if (isStationInfo(item)) {
21357
+ if (utils_isStationInfo(item)) {
21010
21358
  const signalType = item.signalType;
21011
21359
  const signalTypeInfo = SIGNAL_TYPE_MAP[signalType];
21012
21360
  const signalTypeName = signalTypeInfo?.name || item.signalType;
@@ -21055,40 +21403,49 @@ const resolveSignalPositions = (signalItems, segment)=>resolveSignalMatchCandida
21055
21403
  tooltip
21056
21404
  };
21057
21405
  });
21058
- const resolveSignalSegments = ({ segments, signalItems, isCursorActive, currentFrequency, currentPosition })=>{
21406
+ const resolveStaticSignalSegments = ({ segments, signalItems })=>{
21059
21407
  if (!segments.length) return [];
21060
21408
  const totalSegmentPoints = segments.reduce((sum, segment)=>sum + segment.point, 0);
21409
+ let segmentLeft = 0;
21061
21410
  return segments.map((segment, segmentIndex)=>{
21062
- const signalPositions = resolveSignalPositions(signalItems, segment);
21063
- const activeMatch = isCursorActive && currentPosition.segmentIndex === segmentIndex && Number.isFinite(currentFrequency) ? resolveBestSignalMatch(signalPositions, {
21064
- currentFrequency,
21065
- currentPointIndex: currentPosition.pointIndex
21066
- }) : void 0;
21067
21411
  const segmentWidth = segment.point / totalSegmentPoints * 100;
21068
- const segmentLeft = segments.slice(0, segmentIndex).reduce((sum, item)=>sum + item.point / totalSegmentPoints * 100, 0);
21069
- return {
21412
+ const data = {
21070
21413
  segment,
21071
21414
  segmentIndex,
21072
- signalPositions,
21073
- activeSignalKey: activeMatch?.key,
21415
+ signalPositions: resolveSignalPositions(signalItems, segment),
21074
21416
  style: {
21075
21417
  left: `${segmentLeft}%`,
21076
21418
  width: `${segmentWidth}%`
21077
21419
  }
21078
21420
  };
21421
+ segmentLeft += segmentWidth;
21422
+ return data;
21079
21423
  });
21080
21424
  };
21081
- 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 })=>{
21082
21441
  if (!Number.isFinite(frequency)) return;
21083
- const currentSegment = segments[currentPosition.segmentIndex];
21084
- if (!currentSegment) return;
21085
- const stationItems = signalItems.filter(isStationInfo);
21086
- if (!stationItems.length) return;
21087
- const matchedSignal = resolveBestSignalMatch(resolveSignalMatchCandidates(stationItems, currentSegment), {
21442
+ const candidates = stationRangeIndex[currentPosition.segmentIndex];
21443
+ if (!candidates?.length) return;
21444
+ const matchedSignal = utils_resolveBestSignalMatch(candidates, {
21088
21445
  currentFrequency: frequency,
21089
21446
  currentPointIndex: currentPosition.pointIndex
21090
21447
  });
21091
- return matchedSignal && isStationInfo(matchedSignal.item) ? matchedSignal.item : void 0;
21448
+ return matchedSignal && utils_isStationInfo(matchedSignal.item) ? matchedSignal.item : void 0;
21092
21449
  };
21093
21450
  const withStationDataUpdate = (globalID, name, func)=>{
21094
21451
  const subscriptionId = `stationData-update-${globalID}`;
@@ -21104,7 +21461,10 @@ const STATION_DATA = (globalID, data)=>{
21104
21461
  return result;
21105
21462
  };
21106
21463
  function useUnifiedSignals({ respectVisibility = false } = {}) {
21107
- 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);
21108
21468
  const [updateTrigger, setUpdateTrigger] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(0);
21109
21469
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
21110
21470
  const subscriberName = `useUnifiedSignals-${globalID}-${Date.now()}`;
@@ -21120,30 +21480,39 @@ function useUnifiedSignals({ respectVisibility = false } = {}) {
21120
21480
  globalID
21121
21481
  ]);
21122
21482
  return (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
21123
- if (respectVisibility && (!signal.show || !signal.display)) return [];
21483
+ if (respectVisibility && (!signalShow || !signalDisplay)) return [];
21124
21484
  const stationData = STATION_DATA(globalID);
21125
- const signalData = signal.data || [];
21485
+ const nextSignalData = signalData || [];
21126
21486
  return [
21127
21487
  ...stationData,
21128
- ...signalData
21488
+ ...nextSignalData
21129
21489
  ];
21130
21490
  }, [
21131
21491
  globalID,
21132
- signal.data,
21133
- signal.display,
21134
- signal.show,
21492
+ signalData,
21493
+ signalDisplay,
21494
+ signalShow,
21135
21495
  respectVisibility,
21136
21496
  updateTrigger
21137
21497
  ]);
21138
21498
  }
21139
- function useStationInfoAtCursor({ frequency, enabled = true }) {
21140
- const { state: { cursor, segments } } = useStore_useStore();
21141
- 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;
21142
21503
  const signalItems = useUnifiedSignals({
21143
21504
  respectVisibility: enabled
21144
21505
  });
21145
- 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)), [
21146
21514
  cursor,
21515
+ cursorSample,
21147
21516
  enabled
21148
21517
  ]);
21149
21518
  const currentPosition = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>isCursorActive && 'number' == typeof left ? frequencyCalculation_calculateCursorPosition(left, segments) : {
@@ -21155,29 +21524,27 @@ function useStationInfoAtCursor({ frequency, enabled = true }) {
21155
21524
  segments
21156
21525
  ]);
21157
21526
  return (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
21158
- 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;
21159
21528
  if (!isCursorActive) return;
21160
21529
  const currentFrequency = frequencyCalculation_getCursorFrequencyAtPosition(segments, currentPosition);
21161
21530
  if (!Number.isFinite(currentFrequency)) {
21162
21531
  const fallbackFrequency = Number(frequency);
21163
21532
  if (!Number.isFinite(fallbackFrequency)) return;
21164
- return findStationAtCursor({
21533
+ return findStationInRangeIndex({
21165
21534
  frequency: fallbackFrequency,
21166
- signalItems,
21167
- segments,
21535
+ stationRangeIndex,
21168
21536
  currentPosition
21169
21537
  });
21170
21538
  }
21171
- return findStationAtCursor({
21539
+ return findStationInRangeIndex({
21172
21540
  frequency: currentFrequency,
21173
- signalItems,
21174
- segments,
21541
+ stationRangeIndex,
21175
21542
  currentPosition
21176
21543
  });
21177
21544
  }, [
21178
21545
  enabled,
21179
21546
  frequency,
21180
- signalItems,
21547
+ stationRangeIndex,
21181
21548
  segments,
21182
21549
  currentPosition,
21183
21550
  left,
@@ -21250,16 +21617,21 @@ const StationInfoPanel = ({ stationInfo })=>{
21250
21617
  });
21251
21618
  };
21252
21619
  const panels_StationInfoPanel = /*#__PURE__*/ __WEBPACK_EXTERNAL_MODULE_react__["default"].memo(StationInfoPanel);
21253
- const FrequencyDataBoard = ({ left, updateKey, onChange, showStationInfo = true })=>{
21254
- const { state: { axisY, axisX: { frequencyFormat, unit }, globalID } } = useStore_useStore();
21255
- 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);
21256
21628
  const calculateIndex = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((values, series, sampledIndex, rawValue)=>{
21257
21629
  if (!values || 0 === values.length) return null;
21258
21630
  const safeSampledIndex = Math.max(0, Math.min(values.length - 1, Math.floor(sampledIndex)));
21259
21631
  const displayValue = Number.isFinite(rawValue) ? rawValue : values[safeSampledIndex];
21260
21632
  if ('number' != typeof displayValue) return null;
21261
- const unit = axisY.unit ?? '';
21262
- const level = getVirtualLevel(unit, displayValue)?.toFixed(1);
21633
+ const nextUnit = axisYUnit ?? '';
21634
+ const level = getVirtualLevel(nextUnit, displayValue)?.toFixed(1);
21263
21635
  if (!(0, utils_array.Ri)(level)) return null;
21264
21636
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)("div", {
21265
21637
  className: "grid max-w-[220px] grid-cols-[minmax(0,1fr)_auto] items-center gap-x-1 text-xs",
@@ -21279,14 +21651,14 @@ const FrequencyDataBoard = ({ left, updateKey, onChange, showStationInfo = true
21279
21651
  children: level
21280
21652
  }),
21281
21653
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("span", {
21282
- children: unit
21654
+ children: nextUnit
21283
21655
  })
21284
21656
  ]
21285
21657
  })
21286
21658
  ]
21287
21659
  }, series.name);
21288
21660
  }, [
21289
- axisY.unit
21661
+ axisYUnit
21290
21662
  ]);
21291
21663
  const { value: value1, currentIndex } = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
21292
21664
  if (!globalID) return {
@@ -21298,7 +21670,16 @@ const FrequencyDataBoard = ({ left, updateKey, onChange, showStationInfo = true
21298
21670
  value: null,
21299
21671
  currentIndex: Number.NaN
21300
21672
  };
21301
- 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
+ };
21302
21683
  const cursorGlobalIndex = snapshot.cursorIndex?.globalIndex;
21303
21684
  const cursorSampledIndex = snapshot.cursorIndex?.sampledIndex;
21304
21685
  const sampledSeriesMap = {
@@ -21355,7 +21736,8 @@ const FrequencyDataBoard = ({ left, updateKey, onChange, showStationInfo = true
21355
21736
  globalID,
21356
21737
  filteredSeries,
21357
21738
  updateKey,
21358
- left
21739
+ left,
21740
+ cursorSample?.version
21359
21741
  ]);
21360
21742
  const frequency = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>frequencyFormat?.(left) ?? '', [
21361
21743
  left,
@@ -21373,7 +21755,8 @@ const FrequencyDataBoard = ({ left, updateKey, onChange, showStationInfo = true
21373
21755
  ]);
21374
21756
  const matchedStation = useStationInfoAtCursor({
21375
21757
  frequency,
21376
- enabled: showStationInfo
21758
+ enabled: showStationInfo,
21759
+ cursorSample
21377
21760
  });
21378
21761
  const hasStationInfo = showStationInfo && !!matchedStation;
21379
21762
  const hasValue = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>value1 && (Array.isArray(value1) ? value1.length > 0 : true), [
@@ -21402,12 +21785,16 @@ const FrequencyDataBoard = ({ left, updateKey, onChange, showStationInfo = true
21402
21785
  };
21403
21786
  const Spectrum_FrequencyDataBoard = /*#__PURE__*/ __WEBPACK_EXTERNAL_MODULE_react__["default"].memo(FrequencyDataBoard);
21404
21787
  const SpectrumCursorPopover = ({ id })=>{
21405
- 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;
21406
21792
  const updateKey = useCursorPopoverUpdateKey('SpectrumPopover', id);
21407
21793
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Spectrum_FrequencyDataBoard, {
21408
- left: left,
21794
+ left: 'number' == typeof left ? left : -1,
21409
21795
  updateKey: updateKey,
21410
- showStationInfo: signal.show && signal.display
21796
+ showStationInfo: signalShow && signalDisplay,
21797
+ cursorSample: sample
21411
21798
  });
21412
21799
  };
21413
21800
  const Spectrum_CursorPopover = SpectrumCursorPopover;
@@ -21421,35 +21808,46 @@ const resolveCursorPopover = ({ id, mode, type })=>{
21421
21808
  if (type === constants_ModuleType.Heatmap) return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(CursorPopover, {
21422
21809
  id: id
21423
21810
  });
21424
- 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
+ });
21425
21814
  return null;
21426
21815
  };
21427
21816
  const Cursor_COMPONENT_KEY = 'Cursor';
21428
21817
  const CURSOR_BOUNDS_TOLERANCE = 1;
21429
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;
21430
- const buildCursorEventSnapshot = (event, sourceId, sourceType)=>{
21819
+ const buildCursorPointerSnapshot = (event, coord, sourceId, sourceType, cachedBounds)=>{
21431
21820
  const target = event.currentTarget;
21432
21821
  if (!(target instanceof HTMLElement)) return null;
21433
- const bounds = resolveCursorVisibleBounds(target);
21822
+ const bounds = cachedBounds ?? resolveCursorVisibleBounds(target);
21434
21823
  return {
21435
21824
  sourceId,
21436
21825
  sourceType,
21437
21826
  clientX: event.clientX,
21438
21827
  clientY: event.clientY,
21828
+ coord,
21439
21829
  bounds
21440
21830
  };
21441
21831
  };
21832
+ const resolveCursorTarget = (event)=>{
21833
+ const target = event.currentTarget;
21834
+ return target instanceof HTMLElement ? target : null;
21835
+ };
21442
21836
  const isSameCursorPayload = (currentCursor, nextCoord, nextEvent)=>{
21443
21837
  const prevEvent = currentCursor.event;
21444
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;
21445
21839
  };
21446
21840
  const Cursor = ({ id, type })=>{
21447
21841
  const { state: { cursor, globalID }, dispatch } = useStore_useStore();
21448
- const { active, coord, show, mode, event } = cursor;
21842
+ const { active, show, mode } = cursor;
21449
21843
  const [isEnabled, setIsEnabled] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(false);
21450
21844
  const cursorRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(cursor);
21451
21845
  const activeRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(active);
21452
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);
21453
21851
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
21454
21852
  cursorRef.current = cursor;
21455
21853
  activeRef.current = active;
@@ -21459,9 +21857,16 @@ const Cursor = ({ id, type })=>{
21459
21857
  active,
21460
21858
  isEnabled
21461
21859
  ]);
21462
- const clearCursorIfOwned = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>()=>{
21860
+ const clearCursorIfOwned = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>(reason = 'leave')=>{
21463
21861
  setIsEnabled(false);
21464
- 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
+ }
21465
21870
  const nextCursor = {
21466
21871
  ...cursorRef.current,
21467
21872
  event: null,
@@ -21472,6 +21877,9 @@ const Cursor = ({ id, type })=>{
21472
21877
  };
21473
21878
  cursorRef.current = nextCursor;
21474
21879
  isEnabledRef.current = false;
21880
+ boundsRef.current = null;
21881
+ targetRef.current = null;
21882
+ interactionRuntime.clearPointer(id, reason);
21475
21883
  (0, __WEBPACK_EXTERNAL_MODULE_react_dom_7136dc57__.flushSync)(()=>{
21476
21884
  setIsEnabled(false);
21477
21885
  dispatch({
@@ -21484,27 +21892,86 @@ const Cursor = ({ id, type })=>{
21484
21892
  dispatch,
21485
21893
  id
21486
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
+ ]);
21487
21911
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
21488
21912
  if (!globalID || !show) return;
21489
- const unsubscribeEnter = createMouseEnterEventManager(id, Cursor_COMPONENT_KEY, ()=>{
21490
- setIsEnabled(true);
21491
- });
21492
- const unsubscribeMove = createMoveEventManager(id, Cursor_COMPONENT_KEY, (event, coord)=>{
21493
- if (!isEnabledRef.current) return;
21494
- const nextEvent = buildCursorEventSnapshot(event, id, type);
21495
- if (nextEvent && !Cursor_isPointWithinBounds(nextEvent.clientX, nextEvent.clientY, nextEvent.bounds)) return void clearCursorIfOwned();
21496
- 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;
21497
21923
  dispatch({
21498
21924
  payload: {
21499
- cursor: {
21500
- ...cursorRef.current,
21501
- event: nextEvent,
21502
- coord
21503
- }
21925
+ cursor: nextCursor
21504
21926
  }
21505
21927
  });
21506
21928
  if (activeRef.current) CURSOR_SETACTIVE(globalID)();
21507
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
+ });
21508
21975
  const unsubscribeLeave = createMouseLeaveEventManager(id, Cursor_COMPONENT_KEY, clearCursorIfOwned);
21509
21976
  return ()=>{
21510
21977
  unsubscribeEnter?.();
@@ -21515,15 +21982,36 @@ const Cursor = ({ id, type })=>{
21515
21982
  id,
21516
21983
  globalID,
21517
21984
  show,
21985
+ type,
21518
21986
  clearCursorIfOwned
21519
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
+ ]);
21520
22007
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
21521
22008
  if (!show) return;
21522
22009
  const handleGlobalPointerMove = (event)=>{
21523
22010
  if (!isEnabledRef.current) return;
21524
- const currentEvent = cursorRef.current.event;
21525
- if (!currentEvent || currentEvent.sourceId !== id) return;
21526
- 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');
21527
22015
  };
21528
22016
  window.addEventListener('pointermove', handleGlobalPointerMove, true);
21529
22017
  return ()=>{
@@ -21534,18 +22022,28 @@ const Cursor = ({ id, type })=>{
21534
22022
  id,
21535
22023
  clearCursorIfOwned
21536
22024
  ]);
21537
- const dashedStyle = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>({
21538
- x: {
21539
- left: `${coord.left || -100}%`,
21540
- opacity: active ? 0.5 : 0
21541
- },
21542
- y: {
21543
- top: `${coord.top || -100}%`,
21544
- opacity: active ? 0.5 : 0
21545
- }
21546
- }), [
21547
- active,
21548
- 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
21549
22047
  ]);
21550
22048
  const popoverContent = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>resolveCursorPopover({
21551
22049
  id,
@@ -21556,19 +22054,20 @@ const Cursor = ({ id, type })=>{
21556
22054
  mode,
21557
22055
  type
21558
22056
  ]);
21559
- if (!show || !isEnabled || !active || event?.sourceId !== id) return null;
22057
+ if (!show || !isEnabled || !active) return null;
21560
22058
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)(Zoom_ZoomViewportLayer, {
21561
22059
  className: "z-[6]",
21562
22060
  children: [
21563
22061
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
21564
- className: "pointer-events-none absolute left-[-200%] top-0 h-full border-l border-dashed border-chart-highlight/80",
21565
- 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"
21566
22064
  }),
21567
22065
  type === constants_ModuleType.Heatmap && /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
21568
- className: "absolute left-0 top-[-200%] w-full border-t border-dashed border-chart-highlight/80",
21569
- 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"
21570
22068
  }),
21571
22069
  popoverContent && /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Overlay_Popover, {
22070
+ id: id,
21572
22071
  children: popoverContent
21573
22072
  }, `${mode ?? type}-${id}`)
21574
22073
  ]
@@ -21604,7 +22103,7 @@ function useEventBusCallback(id) {
21604
22103
  ]);
21605
22104
  }
21606
22105
  const EventBus_EventBus = ({ id })=>{
21607
- const globalID = useSelector((state)=>state.globalID);
22106
+ const globalID = useStore_useSelector((state)=>state.globalID);
21608
22107
  const EID = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>getEID(id), [
21609
22108
  id
21610
22109
  ]);
@@ -21934,7 +22433,6 @@ function useZoomEvent(id, name) {
21934
22433
  handleDrag
21935
22434
  ]);
21936
22435
  }
21937
- const PERCENTAGE = 100;
21938
22436
  const tools_PRECISION = 1e4;
21939
22437
  const defaultAreaInfoResult = {
21940
22438
  startIndex: 0,
@@ -21953,28 +22451,27 @@ const defaultAreaInfoResult = {
21953
22451
  };
21954
22452
  function calculateAreaInfo({ endLeft, startLeft, startTop, endTop, frequencyFormat, globalID }) {
21955
22453
  const { waterfallData } = withDatabase(globalID).getAllRawData();
21956
- if (!waterfallData?.length || !waterfallData[0]?.length) return defaultAreaInfoResult;
21957
- const rowCount = waterfallData.length;
21958
- const colCount = waterfallData[0].length;
21959
- const indices = {
21960
- top: Math.max(0, Math.min(rowCount - 1, Math.ceil(rowCount * (PERCENTAGE - startTop) / PERCENTAGE) - 1)),
21961
- bottom: Math.max(0, Math.min(rowCount - 1, Math.ceil(rowCount * (PERCENTAGE - endTop) / PERCENTAGE) - 1)),
21962
- start: Math.max(0, Math.min(colCount - 1, Math.ceil(colCount * startLeft / PERCENTAGE) - 1)),
21963
- end: Math.max(0, Math.min(colCount - 1, Math.ceil(colCount * endLeft / PERCENTAGE) - 1))
21964
- };
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;
21965
22462
  const formatFrequency = frequencyFormat;
21966
22463
  const frequencies = {
21967
- start: Math.round(Number(formatFrequency(startLeft)) * tools_PRECISION) / tools_PRECISION,
21968
- 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
21969
22466
  };
21970
22467
  const bandwidth = Math.abs(frequencies.end - frequencies.start);
21971
- const startTimestamp = waterfallData[indices.top]?.timestamp || '';
21972
- const endTimestamp = waterfallData[indices.bottom]?.timestamp || '';
22468
+ const startTimestamp = waterfallData[indices.startIndex]?.timestamp || '';
22469
+ const endTimestamp = waterfallData[indices.endIndex]?.timestamp || '';
21973
22470
  const result = {
21974
- startIndex: indices.top,
21975
- endIndex: indices.bottom,
21976
- startCol: indices.start,
21977
- endCol: indices.end,
22471
+ startIndex: indices.startIndex,
22472
+ endIndex: indices.endIndex,
22473
+ startCol: indices.startCol,
22474
+ endCol: indices.endCol,
21978
22475
  startTimestamp,
21979
22476
  endTimestamp,
21980
22477
  startFrequency: frequencies.start,
@@ -21983,30 +22480,32 @@ function calculateAreaInfo({ endLeft, startLeft, startTop, endTop, frequencyForm
21983
22480
  endFrequencyFormat: String(frequencies.end),
21984
22481
  bandwidth,
21985
22482
  bandwidthFormat: getFrequencyToFixed(bandwidth),
21986
- data: waterfallData.slice(indices.bottom, indices.top + 1).map((row)=>Array.from(row.slice(indices.start, indices.end + 1)))
22483
+ data: resolveHeatmapRangeData(waterfallData, indices)
21987
22484
  };
21988
22485
  return result;
21989
22486
  }
21990
22487
  const heatmapCaptureUpdate = (globalID, func)=>subscription_createSubscriptionManager(`heatmapCaptureUpdate-${globalID}`, '0', func, globalID);
21991
22488
  const Area_COMPONENT_KEY = constants_ToolType.HeatmapCapture;
21992
- const Area = (props)=>{
21993
- 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();
21994
22491
  const { id } = props;
21995
- const { type, show, sync, onChange } = heatmapCapture;
21996
- const canArea = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>type === heatmap_HeatmapCaptureType.Area && show, [
21997
- 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
21998
22497
  ]);
21999
22498
  const [info, setInfo] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(defaultAreaInfoResult);
22000
22499
  const [areaStyle, setAreaStyle] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)();
22001
22500
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
22002
22501
  if (canArea) {
22003
- createMouseUpEventManager(id, Area_COMPONENT_KEY, ()=>{
22502
+ const cleanupMouseUp = createMouseUpEventManager(id, Area_COMPONENT_KEY, ()=>{
22004
22503
  onChange(info);
22005
22504
  });
22006
- createMouseLeaveEventManager(id, Area_COMPONENT_KEY, ()=>{
22505
+ const cleanupMouseLeave = createMouseLeaveEventManager(id, Area_COMPONENT_KEY, ()=>{
22007
22506
  onChange(info);
22008
22507
  });
22009
- createDragEventManager(id, Area_COMPONENT_KEY, (start, end)=>{
22508
+ const cleanupDrag = createDragEventManager(id, Area_COMPONENT_KEY, (start, end)=>{
22010
22509
  if (compareEventPriority(id, Area_COMPONENT_KEY) && start && end) {
22011
22510
  const { left: startLeft, top: startTop } = start;
22012
22511
  const { left: endLeft, top: endTop } = end;
@@ -22037,16 +22536,19 @@ const Area = (props)=>{
22037
22536
  }));
22038
22537
  }
22039
22538
  });
22539
+ return ()=>{
22540
+ cleanupMouseUp?.();
22541
+ cleanupMouseLeave?.();
22542
+ cleanupDrag?.();
22543
+ };
22040
22544
  }
22041
22545
  }, [
22042
22546
  id,
22043
22547
  canArea,
22044
- sync,
22045
- areaStyle,
22046
22548
  info,
22047
- segments,
22048
22549
  frequencyFormat,
22049
- globalID
22550
+ globalID,
22551
+ onChange
22050
22552
  ]);
22051
22553
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
22052
22554
  if (!canArea) {
@@ -22127,13 +22629,15 @@ const Area = (props)=>{
22127
22629
  ]
22128
22630
  });
22129
22631
  };
22130
- const Capture_Area = Area;
22632
+ const Area = Area_Area;
22131
22633
  const RowIndex_COMPONENT_KEY = constants_ToolType.HeatmapCapture;
22132
22634
  const RowIndex_RowIndex = ({ id })=>{
22133
22635
  const { state: { heatmapCapture, globalID, publish } } = useStore_useStore();
22134
22636
  const { onChange: onRowIndexChange, show, type, display } = heatmapCapture;
22135
- const canRowindex = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>type === heatmap_HeatmapCaptureType.RowIndex, [
22136
- type
22637
+ const canRowindex = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>type === heatmap_HeatmapCaptureType.RowIndex && show && display, [
22638
+ type,
22639
+ show,
22640
+ display
22137
22641
  ]);
22138
22642
  const [info, setInfo] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(null);
22139
22643
  const [currentPosition, setCurrentPosition] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(null);
@@ -22162,7 +22666,7 @@ const RowIndex_RowIndex = ({ id })=>{
22162
22666
  publish
22163
22667
  ]);
22164
22668
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
22165
- const isInteractive = globalID && show && display && canRowindex;
22669
+ const isInteractive = globalID && canRowindex;
22166
22670
  if (!isInteractive) return;
22167
22671
  const handleMouseDown = ()=>{
22168
22672
  setIsDragging(true);
@@ -22188,12 +22692,10 @@ const RowIndex_RowIndex = ({ id })=>{
22188
22692
  }, [
22189
22693
  id,
22190
22694
  globalID,
22191
- show,
22192
22695
  canRowindex,
22193
- display,
22194
22696
  updateRowData
22195
22697
  ]);
22196
- if (!canRowindex || !show || !display) return null;
22698
+ if (!canRowindex) return null;
22197
22699
  const getMaskPosition = ()=>{
22198
22700
  if (!currentPosition) return {};
22199
22701
  const topPosition = currentPosition.top;
@@ -22973,16 +23475,18 @@ const Slider = ({ id })=>{
22973
23475
  const [heatmapData, len] = getHeatmapData();
22974
23476
  if (len <= 0) return null;
22975
23477
  const { position: pos, height: h, leftPosition: left, width: w } = r;
22976
- const endIndex = Math.round((100 - pos) / 100 * (len - 1));
22977
- 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;
22978
23482
  const startTimestamp = heatmapData[startIndex]?.timestamp ?? '';
22979
23483
  const endTimestamp = heatmapData[endIndex]?.timestamp ?? '';
22980
23484
  const startTs = dateTimeToTimestamp(startTimestamp);
22981
23485
  const endTs = dateTimeToTimestamp(endTimestamp);
22982
23486
  const duration = startTs > 0 && endTs > 0 ? Math.abs(endTs - startTs) : 0;
22983
- const colCount = heatmapData[0]?.length || 0;
22984
- const startCol = Math.max(0, Math.min(colCount - 1, Math.ceil(colCount * left / 100) - 1));
22985
- 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;
22986
23490
  const formatFn = frequencyFormatRef.current;
22987
23491
  const startFreqStr = formatFn?.(left);
22988
23492
  const endFreqStr = formatFn?.(left + w);
@@ -23054,7 +23558,7 @@ const Slider = ({ id })=>{
23054
23558
  const applyInterval = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((newInterval)=>{
23055
23559
  const { startIndex, endIndex, startFrequency, endFrequency } = newInterval;
23056
23560
  const [_, len] = getHeatmapData();
23057
- 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);
23058
23562
  let freqChanged = false;
23059
23563
  let newLeftPosition = currentRect.leftPosition;
23060
23564
  let newWidth = currentRect.width;
@@ -23164,7 +23668,7 @@ const HeatmapCapture = (props)=>{
23164
23668
  ...props
23165
23669
  }) : type === heatmap_HeatmapCaptureType.RowIndex ? /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(RowIndex, {
23166
23670
  ...props
23167
- }) : /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Capture_Area, {
23671
+ }) : /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Area, {
23168
23672
  ...props
23169
23673
  });
23170
23674
  };
@@ -23891,7 +24395,7 @@ const SegmentsDisplayControl_SegmentsDisplayControl = ()=>{
23891
24395
  });
23892
24396
  };
23893
24397
  const SegmentsDisplayControl = SegmentsDisplayControl_SegmentsDisplayControl;
23894
- const SeriesControl_SeriesControl = ({ type })=>{
24398
+ const SeriesControl = ({ type })=>{
23895
24399
  const { state: { globalID } } = useStore_useStore();
23896
24400
  const { mode: currentMode } = useSeriesManager(globalID);
23897
24401
  const handleSeriesControl = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)(()=>{
@@ -24013,7 +24517,7 @@ const SeriesControl_SeriesControl = ({ type })=>{
24013
24517
  children: renderIcon()
24014
24518
  });
24015
24519
  };
24016
- const SeriesControl = SeriesControl_SeriesControl;
24520
+ const controls_SeriesControl = SeriesControl;
24017
24521
  const SeriesDisplayControl = ()=>{
24018
24522
  const { state: { globalID, series: seriesConfig } } = useStore_useStore();
24019
24523
  const filteredSeries = useFilteredSeries_useFilteredSeries(globalID);
@@ -24399,10 +24903,50 @@ const FluorescenceSwitch = ()=>{
24399
24903
  });
24400
24904
  };
24401
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;
24402
24942
  const Switch_Switch = ()=>{
24403
24943
  const { state: { heatmapCapture }, dispatch } = useStore_useStore();
24404
- const { show, display, type } = heatmapCapture;
24405
- 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
+ };
24406
24950
  let title = "\u7011\u5E03\u56FE\u6355\u83B7-\u533A\u57DF\u6D4B\u91CF";
24407
24951
  let svg = /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)(__WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.Fragment, {
24408
24952
  children: [
@@ -24449,11 +24993,16 @@ const Switch_Switch = ()=>{
24449
24993
  }
24450
24994
  return {
24451
24995
  title,
24452
- 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
+ })
24453
25001
  };
24454
25002
  }, [
24455
25003
  type,
24456
- display
25004
+ display,
25005
+ toolbarVariant
24457
25006
  ]);
24458
25007
  const setActive = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((e)=>{
24459
25008
  dispatch({
@@ -24475,11 +25024,7 @@ const Switch_Switch = ()=>{
24475
25024
  setActive(!display);
24476
25025
  },
24477
25026
  title: title,
24478
- children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("svg", {
24479
- viewBox: "0 0 1024 1024",
24480
- xmlns: "http://www.w3.org/2000/svg",
24481
- children: svg
24482
- })
25027
+ children: icon
24483
25028
  });
24484
25029
  };
24485
25030
  const Capture_Switch = /*#__PURE__*/ __WEBPACK_EXTERNAL_MODULE_react__["default"].memo(Switch_Switch);
@@ -24529,50 +25074,13 @@ const DeltaMeasurementSwitch = ()=>{
24529
25074
  deltaMeasurement,
24530
25075
  dispatch
24531
25076
  ]);
24532
- const DeltaIcon = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)("svg", {
24533
- viewBox: "0 0 1024 1024",
24534
- xmlns: "http://www.w3.org/2000/svg",
24535
- width: "24",
24536
- height: "24",
24537
- style: {
24538
- transition: 'transform 0.2s ease'
24539
- },
24540
- children: [
24541
- /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("path", {
24542
- d: "M512 200 L812 824 L212 824 Z",
24543
- fill: "none",
24544
- stroke: "currentColor",
24545
- strokeWidth: "60",
24546
- strokeLinejoin: "miter"
24547
- }),
24548
- /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("line", {
24549
- x1: "350",
24550
- y1: "650",
24551
- x2: "674",
24552
- y2: "650",
24553
- stroke: "currentColor",
24554
- strokeWidth: "40",
24555
- strokeDasharray: "10,10"
24556
- }),
24557
- /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("path", {
24558
- d: "M 360 650 L 390 630 L 390 670 Z",
24559
- fill: "currentColor"
24560
- }),
24561
- /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("path", {
24562
- d: "M 664 650 L 634 630 L 634 670 Z",
24563
- fill: "currentColor"
24564
- })
24565
- ]
24566
- }), [
24567
- display
24568
- ]);
24569
25077
  if (!show) return null;
24570
25078
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(primitives_IconBox, {
24571
25079
  active: display,
24572
25080
  tone: "primary",
24573
25081
  onClick: ()=>setDisplay(!display),
24574
25082
  title: display ? "\u9000\u51FA\u0394\u6D4B\u91CF\u6A21\u5F0F" : "\u8FDB\u5165\u0394\u6D4B\u91CF\u6A21\u5F0F",
24575
- children: DeltaIcon
25083
+ children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(DeltaMeasurementIcon, {})
24576
25084
  });
24577
25085
  };
24578
25086
  const DeltaMeasurement_Switch = DeltaMeasurementSwitch;
@@ -25088,7 +25596,7 @@ const TOOLBAR_ITEM_CONFIGS = [
25088
25596
  ]
25089
25597
  },
25090
25598
  {
25091
- component: SeriesControl,
25599
+ component: controls_SeriesControl,
25092
25600
  toolType: constants_ToolbarItemType.SeriesControl,
25093
25601
  supportedCharts: [
25094
25602
  constants_ChartType.SingleFrequency,
@@ -25200,8 +25708,8 @@ const resolveToolbarItemProps = (config, chartType)=>{
25200
25708
  return config.props;
25201
25709
  };
25202
25710
  const Toolbar = ({ type })=>{
25203
- const show = useSelector((state)=>state.toolbar.show);
25204
- 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 ?? []);
25205
25713
  const { width, pluginBoxWidth } = useAxisYWidth_useAxisYWidth();
25206
25714
  const axisStyle = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>({
25207
25715
  marginLeft: width,
@@ -25357,7 +25865,7 @@ class Occupancy extends BaseRenderer {
25357
25865
  });
25358
25866
  }
25359
25867
  }
25360
- const Level_Level = (props)=>{
25868
+ const Level = (props)=>{
25361
25869
  const { opacity } = props;
25362
25870
  const { chart, Chart } = hooks_useChart({
25363
25871
  Render: Occupancy,
@@ -25380,7 +25888,7 @@ const Level_Level = (props)=>{
25380
25888
  style: style
25381
25889
  });
25382
25890
  };
25383
- const Level = Level_Level;
25891
+ const modules_Level = Level;
25384
25892
  const LINE_WIDTH_BASE = 0.5;
25385
25893
  const MAJOR_TICK_LENGTH = 6;
25386
25894
  const MINOR_TICK_LENGTH = 4;
@@ -25395,7 +25903,7 @@ const MINOR_TICK_LINE_WIDTH = LINE_WIDTH_BASE;
25395
25903
  const AXIS_LINE_WIDTH = LINE_WIDTH_BASE;
25396
25904
  function useCanvasAxisY(options) {
25397
25905
  const { ranging } = options;
25398
- const axisY = useSelector((state)=>state.axisY);
25906
+ const axisY = useStore_useSelector((state)=>state.axisY);
25399
25907
  const { range: axisYRange, disabled } = axisY;
25400
25908
  const canvasRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
25401
25909
  const containerRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
@@ -26006,6 +26514,17 @@ const DragFrame = ({ id })=>{
26006
26514
  });
26007
26515
  };
26008
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
+ };
26009
26528
  const originalColors = [
26010
26529
  '#B22222',
26011
26530
  '#CD5C5C',
@@ -26577,19 +27096,65 @@ const FrequencyAllocation_data = [
26577
27096
  }
26578
27097
  ];
26579
27098
  const STORAGE_KEY = 'rfkit-charts-frequency-allocation';
26580
- 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 = ()=>{
26581
27105
  const cached = localStorage.getItem(STORAGE_KEY);
26582
27106
  if (!cached) return null;
26583
27107
  const data = JSON.parse(cached);
26584
- 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;
26585
27119
  };
26586
27120
  const setFrequencyAllocationToCache = (data)=>{
26587
27121
  localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
26588
27122
  };
26589
- function resolveFrequencyAllocationData(data) {
26590
- 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);
26591
27145
  const inputData = data ?? [];
26592
- 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
+ });
26593
27158
  }
26594
27159
  const resolveFrequencyAllocationRange = (band)=>{
26595
27160
  if (null != band.startFrequency && null != band.stopFrequency) {
@@ -26605,7 +27170,7 @@ const resolveFrequencyAllocationRange = (band)=>{
26605
27170
  }
26606
27171
  return null;
26607
27172
  };
26608
- const resolveFrequencyAllocationSegments = ({ segments, allocations })=>{
27173
+ const resolveFrequencyAllocationSegments = ({ segments, allocations, channelIndex, channelTitle })=>{
26609
27174
  if (!segments.length || !allocations.length) return [];
26610
27175
  const totalSegmentPoints = segments.reduce((sum, segment)=>sum + segment.point, 0);
26611
27176
  return segments.map((segment, segmentIndex)=>{
@@ -26619,6 +27184,8 @@ const resolveFrequencyAllocationSegments = ({ segments, allocations })=>{
26619
27184
  return {
26620
27185
  band,
26621
27186
  range,
27187
+ channelIndex: channelIndex ?? 0,
27188
+ channelTitle,
26622
27189
  position: {
26623
27190
  left: `${left}%`,
26624
27191
  width: `${width}%`
@@ -26638,15 +27205,30 @@ const resolveFrequencyAllocationSegments = ({ segments, allocations })=>{
26638
27205
  };
26639
27206
  });
26640
27207
  };
26641
- function useFrequencyAllocationData_useFrequencyAllocationData() {
26642
- const { state: { frequencyAllocation: { data } } } = useStore_useStore();
26643
- return (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>resolveFrequencyAllocationData(data), [
26644
- 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
26645
27227
  ]);
26646
27228
  }
26647
27229
  const AllocationInfo_AllocationInfo = ({ allocationInfo, variant = 'default' })=>{
26648
27230
  if (!allocationInfo) return null;
26649
- const { title, description, startFrequency, stopFrequency, centerFrequency, stepFrequency, bandwidth, modulation } = allocationInfo;
27231
+ const { title, description, startFrequency, stopFrequency, centerFrequency, stepFrequency, bandwidth, modulation, channelTitle } = allocationInfo;
26650
27232
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)("div", {
26651
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)]'),
26652
27234
  children: [
@@ -26657,6 +27239,12 @@ const AllocationInfo_AllocationInfo = ({ allocationInfo, variant = 'default' })=
26657
27239
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)("div", {
26658
27240
  className: "mb-1 text-primary",
26659
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,
26660
27248
  startFrequency && stopFrequency && /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)("div", {
26661
27249
  children: [
26662
27250
  "\u9891\u7387\u8303\u56F4\uFF1A",
@@ -26702,57 +27290,91 @@ const AllocationInfo_AllocationInfo = ({ allocationInfo, variant = 'default' })=
26702
27290
  });
26703
27291
  };
26704
27292
  const AllocationInfo = /*#__PURE__*/ __WEBPACK_EXTERNAL_MODULE_react__["default"].memo(AllocationInfo_AllocationInfo);
26705
- 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", {
26706
27294
  className: "absolute top-0 h-full [contain:layout]",
26707
27295
  style: style,
26708
- children: bandPositions.map(({ band, range, position })=>{
27296
+ children: bandPositions.map((bandPosition)=>{
27297
+ const { band, channelIndex, range, position } = bandPosition;
26709
27298
  const backgroundStyle = band.gradientColors ? {
26710
27299
  backgroundImage: `linear-gradient(to right, ${band.gradientColors[0]}, ${band.gradientColors[1]})`
26711
27300
  } : {
26712
27301
  backgroundColor: band.color || 'var(--primary)'
26713
27302
  };
26714
27303
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
26715
- 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",
26716
27305
  style: {
26717
27306
  ...backgroundStyle,
26718
27307
  left: position.left,
26719
27308
  width: position.width
26720
27309
  },
26721
- onMouseEnter: onMouseEnter(band, range),
27310
+ onMouseEnter: onMouseEnter(bandPosition),
26722
27311
  onMouseMove: onMouseMove,
26723
27312
  onMouseLeave: onMouseLeave,
26724
- 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", {
26725
27314
  className: "truncate",
26726
27315
  children: band.title
26727
- })
26728
- }, `band-${band.title}-${range.start}-${range.stop}-${position.left}`);
27316
+ }) : null
27317
+ }, `band-${channelIndex ?? 0}-${band.title}-${range.start}-${range.stop}-${position.left}`);
26729
27318
  })
26730
27319
  }));
26731
- const AllocationSegments = AllocationSegments_AllocationSegments;
26732
- 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 })=>{
26733
27322
  const tooltipRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
26734
- 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,
26735
27346
  x,
26736
27347
  y
26737
- });
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
+ ]);
26738
27359
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
26739
- if (visible && tooltipRef.current) {
26740
- const viewportPadding = 12;
26741
- const tooltip = tooltipRef.current;
26742
- const tooltipWidth = tooltip.offsetWidth;
26743
- const tooltipHeight = tooltip.offsetHeight;
26744
- const windowWidth = window.innerWidth;
26745
- const windowHeight = window.innerHeight;
26746
- const nextX = x + tooltipWidth > windowWidth - viewportPadding ? x - tooltipWidth - 10 : x;
26747
- const nextY = y + tooltipHeight > windowHeight - viewportPadding ? y - tooltipHeight - 10 : y;
26748
- setPosition({
26749
- x: Math.max(viewportPadding, Math.min(nextX, windowWidth - tooltipWidth - viewportPadding)),
26750
- y: Math.max(viewportPadding, Math.min(nextY, windowHeight - tooltipHeight - viewportPadding))
26751
- });
26752
- }
27360
+ scheduleRef.current = schedulePositionUpdate;
27361
+ return ()=>{
27362
+ if (scheduleRef.current === schedulePositionUpdate) scheduleRef.current = null;
27363
+ };
26753
27364
  }, [
26754
- x,
26755
- 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,
26756
27378
  visible
26757
27379
  ]);
26758
27380
  if (!visible) return null;
@@ -26760,8 +27382,9 @@ const overlays_Tooltip_Tooltip = ({ title, description, visible, x, y, startFreq
26760
27382
  ref: tooltipRef,
26761
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",
26762
27384
  style: {
26763
- left: position.x,
26764
- top: position.y
27385
+ left: 0,
27386
+ top: 0,
27387
+ transform: `translate3d(${x}px, ${y}px, 0)`
26765
27388
  },
26766
27389
  children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(AllocationInfo, {
26767
27390
  allocationInfo: {
@@ -26772,43 +27395,64 @@ const overlays_Tooltip_Tooltip = ({ title, description, visible, x, y, startFreq
26772
27395
  centerFrequency,
26773
27396
  stepFrequency,
26774
27397
  bandwidth,
26775
- modulation
27398
+ modulation,
27399
+ channelTitle
26776
27400
  }
26777
27401
  })
26778
27402
  });
26779
27403
  };
26780
27404
  const overlays_Tooltip = overlays_Tooltip_Tooltip;
26781
- const FrequencyAllocation = ()=>{
26782
- const unit = useSelector((state)=>state.axisX.unit);
26783
- const segments = useSelector((state)=>state.segments);
26784
- const display = useSelector((state)=>state.frequencyAllocation.display);
26785
- const show = useSelector((state)=>state.frequencyAllocation.show);
26786
- const zoomOffStyle = useSelector((state)=>state.zoom.style);
26787
- 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();
26788
27413
  const [tooltipInfo, setTooltipInfo] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)({
26789
27414
  visible: false,
26790
27415
  x: 0,
26791
27416
  y: 0
26792
27417
  });
26793
- 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({
26794
27431
  segments,
26795
- allocations: frequencyAllocationData
27432
+ channels: frequencyAllocationChannels
26796
27433
  }), [
26797
27434
  segments,
26798
- frequencyAllocationData
27435
+ frequencyAllocationChannels
26799
27436
  ]);
27437
+ const { laneHeight, showLabels } = resolveFrequencyAllocationDensity({
27438
+ density,
27439
+ channelCount: laneData.length
27440
+ });
27441
+ const containerHeight = Math.max(laneHeight, laneData.length * laneHeight);
26800
27442
  const handleTooltipUpdate = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((tooltipData)=>{
26801
27443
  setTooltipInfo((prev)=>({
26802
27444
  ...prev,
26803
27445
  ...tooltipData
26804
27446
  }));
26805
27447
  }, []);
26806
- 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);
26807
27450
  const tooltipData = {
26808
27451
  ...band,
26809
27452
  visible: true,
26810
- x: e.clientX + 10,
26811
- y: e.clientY + 10,
27453
+ x: tooltipPositionRef.current.x,
27454
+ y: tooltipPositionRef.current.y,
27455
+ channelTitle,
26812
27456
  startFrequency: `${range.start}${unit}`,
26813
27457
  stopFrequency: `${range.stop}${unit}`
26814
27458
  };
@@ -26819,15 +27463,13 @@ const FrequencyAllocation = ()=>{
26819
27463
  handleTooltipUpdate(tooltipData);
26820
27464
  }, [
26821
27465
  unit,
26822
- handleTooltipUpdate
27466
+ handleTooltipUpdate,
27467
+ updateTooltipPosition
26823
27468
  ]);
26824
27469
  const handleMouseMove = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((e)=>{
26825
- handleTooltipUpdate({
26826
- x: e.clientX + 10,
26827
- y: e.clientY + 10
26828
- });
27470
+ updateTooltipPosition(e);
26829
27471
  }, [
26830
- handleTooltipUpdate
27472
+ updateTooltipPosition
26831
27473
  ]);
26832
27474
  const handleMouseLeave = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)(()=>{
26833
27475
  handleTooltipUpdate({
@@ -26836,28 +27478,42 @@ const FrequencyAllocation = ()=>{
26836
27478
  }, [
26837
27479
  handleTooltipUpdate
26838
27480
  ]);
26839
- if (!show || !display) return null;
27481
+ if (!show || !display || 0 === laneData.length) return null;
26840
27482
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsxs)("div", {
26841
- 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
+ },
26842
27488
  children: [
26843
27489
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
26844
- 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",
26845
27491
  style: zoomOffStyle ?? void 0,
26846
- children: segmentData.map(({ segmentIndex, bandPositions, style })=>/*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(AllocationSegments, {
26847
- style: style,
26848
- bandPositions: bandPositions,
26849
- onMouseEnter: handleMouseEnter,
26850
- onMouseMove: handleMouseMove,
26851
- onMouseLeave: handleMouseLeave
26852
- }, `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}`))
26853
27507
  }),
26854
27508
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(overlays_Tooltip, {
26855
- ...tooltipInfo
27509
+ ...tooltipInfo,
27510
+ positionRef: tooltipPositionRef,
27511
+ scheduleRef: scheduleTooltipPositionRef
26856
27512
  })
26857
27513
  ]
26858
27514
  });
26859
27515
  };
26860
- const Spectrum_FrequencyAllocation = FrequencyAllocation;
27516
+ const FrequencyAllocation = FrequencyAllocation_FrequencyAllocation;
26861
27517
  const useUpdateKey = (id)=>{
26862
27518
  const [updateKey, setUpdateKey] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(0);
26863
27519
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
@@ -27236,7 +27892,8 @@ const useMarkerEvents = (props)=>{
27236
27892
  const stateRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)({
27237
27893
  isDown: null,
27238
27894
  dragStart: null,
27239
- isHover: ''
27895
+ isHover: '',
27896
+ hoverId: null
27240
27897
  });
27241
27898
  const getEventContainer = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)(()=>document.getElementById(getEID(id)) ?? document.getElementById(id), [
27242
27899
  id
@@ -27289,47 +27946,56 @@ const useMarkerEvents = (props)=>{
27289
27946
  ]);
27290
27947
  (0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
27291
27948
  const isShow = display;
27292
- createMoveEventManager(id, useMarkerEvents_COMPONENT_KEY, (_, e)=>{
27949
+ const cleanupMove = createMoveEventManager(id, useMarkerEvents_COMPONENT_KEY, (_, e)=>{
27293
27950
  if (!isShow) return;
27294
27951
  if (void 0 !== e.left) {
27295
- stateRef.current.isHover = checkHover({
27952
+ const nextHover = checkHover({
27296
27953
  left: e.left
27297
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;
27298
27962
  onHover({
27299
27963
  left: e.left
27300
27964
  });
27301
27965
  }
27302
27966
  });
27303
- createDragEventManager(id, useMarkerEvents_COMPONENT_KEY, (_, e)=>{
27967
+ const cleanupDrag = createDragEventManager(id, useMarkerEvents_COMPONENT_KEY, (_, e)=>{
27304
27968
  const { isDown } = stateRef.current;
27305
27969
  if (isShow && isDown && compareEventPriority(id, useMarkerEvents_COMPONENT_KEY) && !fixed) onUpdateMarker(isDown.id, {
27306
27970
  left: e.left,
27307
27971
  top: e.top
27308
27972
  });
27309
27973
  });
27310
- createMouseDownEventManager(id, useMarkerEvents_COMPONENT_KEY, (e)=>{
27974
+ const cleanupMouseDown = createMouseDownEventManager(id, useMarkerEvents_COMPONENT_KEY, (e)=>{
27311
27975
  if (!isShow) return;
27312
27976
  const marker = findMarkerByPosition(e) || ('object' == typeof stateRef.current.isHover ? stateRef.current.isHover : null);
27313
27977
  if (marker && !fixed) stateRef.current.isDown = marker;
27314
27978
  });
27315
- createMouseUpEventManager(id, useMarkerEvents_COMPONENT_KEY, ()=>{
27979
+ const cleanupMouseUp = createMouseUpEventManager(id, useMarkerEvents_COMPONENT_KEY, ()=>{
27316
27980
  if (!isShow) return;
27317
27981
  stateRef.current.isDown = null;
27318
27982
  resetEventLevel(id, useMarkerEvents_COMPONENT_KEY);
27319
27983
  });
27320
- createMouseLeaveEventManager(id, useMarkerEvents_COMPONENT_KEY, ()=>{
27984
+ const cleanupMouseLeave = createMouseLeaveEventManager(id, useMarkerEvents_COMPONENT_KEY, ()=>{
27321
27985
  if (!isShow) return;
27986
+ const hadHover = null !== stateRef.current.hoverId;
27322
27987
  stateRef.current.isDown = null;
27323
27988
  stateRef.current.isHover = '';
27989
+ stateRef.current.hoverId = null;
27324
27990
  resetEventLevel(id, useMarkerEvents_COMPONENT_KEY);
27325
- onResetHover();
27991
+ if (hadHover) onResetHover();
27326
27992
  });
27327
- createLongPressEventManager(id, useMarkerEvents_COMPONENT_KEY, (_, e)=>{
27993
+ const cleanupLongPress = createLongPressEventManager(id, useMarkerEvents_COMPONENT_KEY, (_, e)=>{
27328
27994
  if (!isShow || !compareEventPriority(id, useMarkerEvents_COMPONENT_KEY)) return;
27329
27995
  const marker = findMarkerByPosition(e) || ('object' == typeof stateRef.current.isHover ? stateRef.current.isHover : null);
27330
27996
  if (marker?.id) onToggleSelect(marker.id);
27331
27997
  });
27332
- createDoubleClickEventManager(id, useMarkerEvents_COMPONENT_KEY, (_, e)=>{
27998
+ const cleanupDoubleClick = createDoubleClickEventManager(id, useMarkerEvents_COMPONENT_KEY, (_, e)=>{
27333
27999
  if (!isShow || !compareEventPriority(id, useMarkerEvents_COMPONENT_KEY)) return;
27334
28000
  if (void 0 !== e.left) {
27335
28001
  const nearbyMarker = checkHover({
@@ -27341,6 +28007,15 @@ const useMarkerEvents = (props)=>{
27341
28007
  });
27342
28008
  }
27343
28009
  });
28010
+ return ()=>{
28011
+ cleanupMove?.();
28012
+ cleanupDrag?.();
28013
+ cleanupMouseDown?.();
28014
+ cleanupMouseUp?.();
28015
+ cleanupMouseLeave?.();
28016
+ cleanupLongPress?.();
28017
+ cleanupDoubleClick?.();
28018
+ };
27344
28019
  }, [
27345
28020
  id,
27346
28021
  display,
@@ -28731,19 +29406,17 @@ function useSignalDataManager() {
28731
29406
  updateSignalData
28732
29407
  };
28733
29408
  }
28734
- const Signal = ({ show = true, display = true })=>{
28735
- const segments = useSelector((state)=>state.segments);
28736
- const zoomOffStyle = useSelector((state)=>state.zoom.style);
28737
- const cursor = useSelector((state)=>state.cursor);
28738
- const signal = useSelector((state)=>state.signal);
28739
- 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;
28740
29415
  const signalItems = useUnifiedSignals({
28741
29416
  respectVisibility: true
28742
29417
  });
28743
29418
  const shouldDisplay = signal.show && signal.display && display;
28744
- const isCursorActive = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>cursor_hasActiveSpectrumCursor(cursor), [
28745
- cursor
28746
- ]);
29419
+ const isCursorActive = !!cursorSample;
28747
29420
  const currentPosition = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>isCursorActive && 'number' == typeof left ? frequencyCalculation_calculateCursorPosition(left, segments) : {
28748
29421
  segmentIndex: -1,
28749
29422
  pointIndex: -1
@@ -28757,18 +29430,23 @@ const Signal = ({ show = true, display = true })=>{
28757
29430
  isCursorActive,
28758
29431
  segments
28759
29432
  ]);
28760
- const segmentData = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>resolveSignalSegments({
29433
+ const segmentData = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>resolveStaticSignalSegments({
28761
29434
  segments,
28762
- signalItems,
29435
+ signalItems
29436
+ }), [
29437
+ segments,
29438
+ signalItems
29439
+ ]);
29440
+ const activeSignalKey = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>resolveActiveSignalKey({
29441
+ segmentData,
28763
29442
  isCursorActive,
28764
29443
  currentFrequency,
28765
29444
  currentPosition
28766
29445
  }), [
28767
- segments,
28768
- signalItems,
28769
- isCursorActive,
28770
29446
  currentFrequency,
28771
- currentPosition
29447
+ currentPosition,
29448
+ isCursorActive,
29449
+ segmentData
28772
29450
  ]);
28773
29451
  if (!show || !shouldDisplay) return null;
28774
29452
  return /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
@@ -28776,10 +29454,10 @@ const Signal = ({ show = true, display = true })=>{
28776
29454
  children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)("div", {
28777
29455
  className: "absolute right-0 top-0 flex h-full w-full",
28778
29456
  style: zoomOffStyle ?? void 0,
28779
- 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, {
28780
29458
  style: style,
28781
29459
  signalPositions: signalPositions,
28782
- activeSignalKey: activeSignalKey,
29460
+ activeSignalKey: currentPosition.segmentIndex === segmentIndex ? activeSignalKey : void 0,
28783
29461
  segmentIndex: segmentIndex
28784
29462
  }, `segment-${segmentIndex}`))
28785
29463
  })
@@ -28788,7 +29466,7 @@ const Signal = ({ show = true, display = true })=>{
28788
29466
  const Spectrum_Signal = Signal;
28789
29467
  const Stripe_COMPONENT_KEY = constants_ToolType.Stripe;
28790
29468
  const EDGE_HIT_SLOP = 1.5;
28791
- const clampPercent = (value1)=>Math.max(0, Math.min(100, value1));
29469
+ const Stripe_clampPercent = (value1)=>Math.max(0, Math.min(100, value1));
28792
29470
  const resolveDragMode = ({ cursor, left, right })=>{
28793
29471
  const leftDistance = Math.abs(cursor - left);
28794
29472
  const rightDistance = Math.abs(cursor - right);
@@ -28833,7 +29511,7 @@ const Stripe_Stripe = ({ id })=>{
28833
29511
  const updateStripe = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((e)=>{
28834
29512
  const dragState = dragStateRef.current;
28835
29513
  if (!dragState || !Number.isFinite(e?.left)) return;
28836
- const coordinateCursor = clampPercent(e.left);
29514
+ const coordinateCursor = Stripe_clampPercent(e.left);
28837
29515
  const currentStripe = stripeRef.current;
28838
29516
  const { mode, startCursor, startLeft, startRight } = dragState;
28839
29517
  let nextLeft = startLeft;
@@ -28841,7 +29519,7 @@ const Stripe_Stripe = ({ id })=>{
28841
29519
  if ('move' === mode) {
28842
29520
  const delta = coordinateCursor - startCursor;
28843
29521
  const width = startRight - startLeft;
28844
- nextLeft = clampPercent(startLeft + delta);
29522
+ nextLeft = Stripe_clampPercent(startLeft + delta);
28845
29523
  nextRight = nextLeft + width;
28846
29524
  if (nextRight > 100) {
28847
29525
  nextRight = 100;
@@ -28885,7 +29563,7 @@ const Stripe_Stripe = ({ id })=>{
28885
29563
  createMouseDownEventManager(id, Stripe_COMPONENT_KEY, (e)=>{
28886
29564
  if (!show || !display || !Number.isFinite(e?.left)) return;
28887
29565
  const currentStripe = stripeRef.current;
28888
- const cursor = clampPercent(e.left);
29566
+ const cursor = Stripe_clampPercent(e.left);
28889
29567
  dragStateRef.current = {
28890
29568
  mode: resolveDragMode({
28891
29569
  cursor,
@@ -29047,7 +29725,9 @@ const Spectrum_Spectrum = (props)=>{
29047
29725
  id: id,
29048
29726
  type: constants_ModuleType.Spectrum
29049
29727
  }),
29050
- /*#__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
+ }),
29051
29731
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Spectrum_DragFrame, {
29052
29732
  id: id
29053
29733
  }),
@@ -29059,7 +29739,7 @@ const Spectrum_Spectrum = (props)=>{
29059
29739
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(FrequencyTagLine, {
29060
29740
  id: id
29061
29741
  }),
29062
- /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Spectrum_FrequencyAllocation, {}),
29742
+ /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(FrequencyAllocation, {}),
29063
29743
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(DeltaMeasurement, {})
29064
29744
  ]
29065
29745
  })
@@ -29101,7 +29781,7 @@ const LevelStream_Chart_Chart = (props)=>{
29101
29781
  /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(components_FlexBox, {
29102
29782
  children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(modules_Spectrum, {
29103
29783
  children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(PluginBox, {
29104
- 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, {
29105
29785
  opacity: 0.5
29106
29786
  })
29107
29787
  })
@@ -29352,9 +30032,9 @@ const charts_Occupancy_Occupancy = withChartPublisher(OccupancyChart, 'Occupancy
29352
30032
  const charts_Occupancy = charts_Occupancy_Occupancy;
29353
30033
  const Zoom_Zoom = ()=>{
29354
30034
  const dispatch = useStoreDispatch();
29355
- const zoom = useSelector((state)=>state.zoom);
29356
- const totalPoints = useSelector((state)=>state.segments.totalPoints) ?? 0;
29357
- 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);
29358
30038
  const { interval: { start, end }, onChange } = zoom;
29359
30039
  const ticks = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
29360
30040
  if (!totalPoints || !frequencyFormat) return [
@@ -29981,12 +30661,31 @@ const Spectrum_Chart_Chart = (props)=>{
29981
30661
  });
29982
30662
  };
29983
30663
  const Spectrum_Chart = Spectrum_Chart_Chart;
29984
- 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 {
29985
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,
29986
30684
  children: /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(Spectrum_Chart, {
29987
- ...props
30685
+ ...normalizedProps
29988
30686
  })
29989
30687
  });
30688
+ };
29990
30689
  const charts_Spectrum_Spectrum = withChartPublisher(SpectrumChart, 'Spectrum');
29991
30690
  const charts_Spectrum = charts_Spectrum_Spectrum;
29992
30691
  function initChartsTheme(options = {}) {
@@ -30003,4 +30702,4 @@ function initChartsTheme(options = {}) {
30003
30702
  };
30004
30703
  }
30005
30704
  initializeChartsThemeEnvironment();
30006
- 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 };