@rfkit/charts 1.10.3 → 1.10.4
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.
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type React from 'react';
|
|
6
6
|
import { type ReactNode } from 'react';
|
|
7
|
-
import { type RectBounds, type RectPosition } from '../../hooks/useDragSelect';
|
|
7
|
+
import { type DragType, type RectBounds, type RectPosition } from '../../hooks/useDragSelect';
|
|
8
8
|
type DragSelectBoxVariant = 'contained' | 'projected';
|
|
9
9
|
export interface DragSelectBoxProps {
|
|
10
10
|
enabled: boolean;
|
|
@@ -15,7 +15,7 @@ export interface DragSelectBoxProps {
|
|
|
15
15
|
maxSize?: number;
|
|
16
16
|
snapThreshold?: number;
|
|
17
17
|
onChange?: (rect: RectPosition) => void;
|
|
18
|
-
onDragStart?: () => boolean | undefined;
|
|
18
|
+
onDragStart?: (dragType: Exclude<DragType, null>) => boolean | undefined;
|
|
19
19
|
onDragEnd?: (rect: RectPosition) => void;
|
|
20
20
|
children?: ReactNode;
|
|
21
21
|
labels?: {
|
package/index.js
CHANGED
|
@@ -22519,16 +22519,26 @@ const resolveHeatmapSourceRange = (snapshot, bounds)=>{
|
|
|
22519
22519
|
};
|
|
22520
22520
|
};
|
|
22521
22521
|
const resolveHeatmapSnapshotRangeData = (snapshot, range)=>snapshot.rawData.slice(range.startIndex, range.endIndex + 1).map((row)=>Array.from(row.slice(range.startCol, range.endCol + 1)));
|
|
22522
|
-
const resolveHeatmapSourceRangeScreenRect = (snapshot, range)=>{
|
|
22522
|
+
const resolveHeatmapSourceRangeScreenRect = (snapshot, range)=>resolveHeatmapContinuousSourceRangeScreenRect(snapshot, {
|
|
22523
|
+
x: [
|
|
22524
|
+
Math.min(range.startCol, range.endCol),
|
|
22525
|
+
Math.max(range.startCol, range.endCol) + 1
|
|
22526
|
+
],
|
|
22527
|
+
y: [
|
|
22528
|
+
Math.min(range.startIndex, range.endIndex),
|
|
22529
|
+
Math.max(range.startIndex, range.endIndex) + 1
|
|
22530
|
+
]
|
|
22531
|
+
});
|
|
22532
|
+
const resolveHeatmapContinuousSourceRangeScreenRect = (snapshot, range)=>{
|
|
22523
22533
|
const [viewportXStart, viewportXEnd] = snapshot.range.x;
|
|
22524
22534
|
const [viewportYStart, viewportYEnd] = snapshot.range.y;
|
|
22525
22535
|
const viewportXSpan = viewportXEnd - viewportXStart;
|
|
22526
22536
|
const viewportYSpan = viewportYEnd - viewportYStart;
|
|
22527
22537
|
if (viewportXSpan <= 0 || viewportYSpan <= 0) return null;
|
|
22528
|
-
const sourceXStart = Math.min(range.
|
|
22529
|
-
const sourceXEnd = Math.max(range.
|
|
22530
|
-
const sourceYStart = Math.min(range.
|
|
22531
|
-
const sourceYEnd = Math.max(range.
|
|
22538
|
+
const sourceXStart = Math.min(range.x[0], range.x[1]);
|
|
22539
|
+
const sourceXEnd = Math.max(range.x[0], range.x[1]);
|
|
22540
|
+
const sourceYStart = Math.min(range.y[0], range.y[1]);
|
|
22541
|
+
const sourceYEnd = Math.max(range.y[0], range.y[1]);
|
|
22532
22542
|
return {
|
|
22533
22543
|
leftPosition: (sourceXStart - viewportXStart) * 100 / viewportXSpan,
|
|
22534
22544
|
width: (sourceXEnd - sourceXStart) * 100 / viewportXSpan,
|
|
@@ -22537,19 +22547,40 @@ const resolveHeatmapSourceRangeScreenRect = (snapshot, range)=>{
|
|
|
22537
22547
|
};
|
|
22538
22548
|
};
|
|
22539
22549
|
const SOURCE_EDGE_EPSILON = 1e-7;
|
|
22540
|
-
const
|
|
22550
|
+
const resolveHeatmapProjectedContinuousSourceRange = (snapshot, bounds)=>{
|
|
22541
22551
|
const { sourceSize } = snapshot;
|
|
22542
22552
|
const [viewportXStart, viewportXEnd] = snapshot.range.x;
|
|
22543
22553
|
const [viewportYStart, viewportYEnd] = snapshot.range.y;
|
|
22544
22554
|
const viewportXSpan = viewportXEnd - viewportXStart;
|
|
22545
22555
|
const viewportYSpan = viewportYEnd - viewportYStart;
|
|
22546
22556
|
if (sourceSize.width <= 0 || sourceSize.height <= 0 || viewportXSpan <= 0 || viewportYSpan <= 0) return null;
|
|
22547
|
-
const sourceXStart = viewportXStart + Math.min(bounds.startLeft, bounds.endLeft) * viewportXSpan / 100;
|
|
22548
|
-
const sourceXEnd = viewportXStart + Math.max(bounds.startLeft, bounds.endLeft) * viewportXSpan / 100;
|
|
22557
|
+
const sourceXStart = viewport_clamp(viewportXStart + Math.min(bounds.startLeft, bounds.endLeft) * viewportXSpan / 100, 0, sourceSize.width);
|
|
22558
|
+
const sourceXEnd = viewport_clamp(viewportXStart + Math.max(bounds.startLeft, bounds.endLeft) * viewportXSpan / 100, 0, sourceSize.width);
|
|
22549
22559
|
const sourceYAtStart = viewportYStart + (100 - bounds.startTop) * viewportYSpan / 100;
|
|
22550
22560
|
const sourceYAtEnd = viewportYStart + (100 - bounds.endTop) * viewportYSpan / 100;
|
|
22551
|
-
const sourceYStart = Math.min(sourceYAtStart, sourceYAtEnd);
|
|
22552
|
-
const sourceYEnd = Math.max(sourceYAtStart, sourceYAtEnd);
|
|
22561
|
+
const sourceYStart = viewport_clamp(Math.min(sourceYAtStart, sourceYAtEnd), 0, sourceSize.height);
|
|
22562
|
+
const sourceYEnd = viewport_clamp(Math.max(sourceYAtStart, sourceYAtEnd), 0, sourceSize.height);
|
|
22563
|
+
return {
|
|
22564
|
+
x: [
|
|
22565
|
+
sourceXStart,
|
|
22566
|
+
sourceXEnd
|
|
22567
|
+
],
|
|
22568
|
+
y: [
|
|
22569
|
+
sourceYStart,
|
|
22570
|
+
sourceYEnd
|
|
22571
|
+
]
|
|
22572
|
+
};
|
|
22573
|
+
};
|
|
22574
|
+
const resolveHeatmapProjectedSourceRange = (snapshot, bounds)=>{
|
|
22575
|
+
const sourceRange = resolveHeatmapProjectedContinuousSourceRange(snapshot, bounds);
|
|
22576
|
+
if (!sourceRange) return null;
|
|
22577
|
+
return quantizeHeatmapContinuousSourceRange(snapshot, sourceRange);
|
|
22578
|
+
};
|
|
22579
|
+
const quantizeHeatmapContinuousSourceRange = (snapshot, sourceRange)=>{
|
|
22580
|
+
const { sourceSize } = snapshot;
|
|
22581
|
+
if (sourceSize.width <= 0 || sourceSize.height <= 0) return null;
|
|
22582
|
+
const [sourceXStart, sourceXEnd] = sourceRange.x;
|
|
22583
|
+
const [sourceYStart, sourceYEnd] = sourceRange.y;
|
|
22553
22584
|
const startCol = viewport_clamp(Math.floor(sourceXStart + SOURCE_EDGE_EPSILON), 0, sourceSize.width - 1);
|
|
22554
22585
|
const endCol = viewport_clamp(Math.max(startCol, Math.ceil(sourceXEnd - SOURCE_EDGE_EPSILON) - 1), startCol, sourceSize.width - 1);
|
|
22555
22586
|
const startIndex = viewport_clamp(Math.floor(sourceYStart + SOURCE_EDGE_EPSILON), 0, sourceSize.height - 1);
|
|
@@ -22618,7 +22649,7 @@ const resolveHeatmapOverviewViewportRect = (snapshot)=>{
|
|
|
22618
22649
|
height: (range.y[1] - range.y[0]) / sourceSize.height
|
|
22619
22650
|
};
|
|
22620
22651
|
};
|
|
22621
|
-
const
|
|
22652
|
+
const resolveHeatmapOverviewContinuousSourceRangeRect = (snapshot, range)=>{
|
|
22622
22653
|
const { sourceSize } = snapshot;
|
|
22623
22654
|
if (sourceSize.width <= 0 || sourceSize.height <= 0) return {
|
|
22624
22655
|
height: 0,
|
|
@@ -22626,22 +22657,22 @@ const resolveHeatmapOverviewSourceRangeRect = (snapshot, range)=>{
|
|
|
22626
22657
|
top: 0,
|
|
22627
22658
|
width: 0
|
|
22628
22659
|
};
|
|
22629
|
-
const
|
|
22630
|
-
const
|
|
22631
|
-
const
|
|
22632
|
-
const
|
|
22660
|
+
const xStart = viewport_clamp(Math.min(range.x[0], range.x[1]), 0, sourceSize.width);
|
|
22661
|
+
const xEnd = viewport_clamp(Math.max(range.x[0], range.x[1]), xStart, sourceSize.width);
|
|
22662
|
+
const yStart = viewport_clamp(Math.min(range.y[0], range.y[1]), 0, sourceSize.height);
|
|
22663
|
+
const yEnd = viewport_clamp(Math.max(range.y[0], range.y[1]), yStart, sourceSize.height);
|
|
22633
22664
|
return {
|
|
22634
|
-
left:
|
|
22635
|
-
top: 1 -
|
|
22636
|
-
width: (
|
|
22637
|
-
height: (
|
|
22665
|
+
left: xStart / sourceSize.width,
|
|
22666
|
+
top: 1 - yEnd / sourceSize.height,
|
|
22667
|
+
width: (xEnd - xStart) / sourceSize.width,
|
|
22668
|
+
height: (yEnd - yStart) / sourceSize.height
|
|
22638
22669
|
};
|
|
22639
22670
|
};
|
|
22640
|
-
const
|
|
22641
|
-
const
|
|
22671
|
+
const isHeatmapContinuousSourceRangeVisibleInViewport = (snapshot, range)=>Math.min(range.x[0], range.x[1]) < snapshot.range.x[1] && Math.max(range.x[0], range.x[1]) > snapshot.range.x[0] && Math.min(range.y[0], range.y[1]) < snapshot.range.y[1] && Math.max(range.y[0], range.y[1]) > snapshot.range.y[0];
|
|
22672
|
+
const isHeatmapOverviewSourcePointInContinuousRange = (range, point, tolerance = {
|
|
22642
22673
|
x: 0,
|
|
22643
22674
|
y: 0
|
|
22644
|
-
})=>point.x >= Math.min(range.
|
|
22675
|
+
})=>point.x >= Math.min(range.x[0], range.x[1]) - tolerance.x && point.x <= Math.max(range.x[0], range.x[1]) + tolerance.x && point.y >= Math.min(range.y[0], range.y[1]) - tolerance.y && point.y <= Math.max(range.y[0], range.y[1]) + tolerance.y;
|
|
22645
22676
|
const isHeatmapViewportFullRange = (snapshot)=>{
|
|
22646
22677
|
const { range, sourceSize } = snapshot;
|
|
22647
22678
|
if (sourceSize.width <= 0 || sourceSize.height <= 0) return true;
|
|
@@ -22654,9 +22685,9 @@ const calculateHeatmapOverviewCenteredRange = (snapshot, point)=>{
|
|
|
22654
22685
|
y: centerRange(snapshot.range.y, snapshot.sourceSize.height, sourcePoint.y)
|
|
22655
22686
|
};
|
|
22656
22687
|
};
|
|
22657
|
-
const
|
|
22658
|
-
x: centerRange(snapshot.range.x, snapshot.sourceSize.width, (Math.min(range.
|
|
22659
|
-
y: centerRange(snapshot.range.y, snapshot.sourceSize.height, (Math.min(range.
|
|
22688
|
+
const calculateHeatmapOverviewContinuousSourceRangeCenteredRange = (snapshot, range)=>({
|
|
22689
|
+
x: centerRange(snapshot.range.x, snapshot.sourceSize.width, (Math.min(range.x[0], range.x[1]) + Math.max(range.x[0], range.x[1])) / 2),
|
|
22690
|
+
y: centerRange(snapshot.range.y, snapshot.sourceSize.height, (Math.min(range.y[0], range.y[1]) + Math.max(range.y[0], range.y[1])) / 2)
|
|
22660
22691
|
});
|
|
22661
22692
|
const calculateHeatmapOverviewDragRange = (snapshot, point, grabOffset)=>{
|
|
22662
22693
|
const sourcePoint = resolveHeatmapOverviewSourcePoint(snapshot, point);
|
|
@@ -24376,16 +24407,16 @@ function calculateAreaInfo({ endLeft, startLeft, startTop, endTop, frequencyForm
|
|
|
24376
24407
|
return result;
|
|
24377
24408
|
}
|
|
24378
24409
|
const heatmapCaptureUpdate = (globalID, func)=>subscription_createSubscriptionManager(`heatmapCaptureUpdate-${globalID}`, '0', func, globalID);
|
|
24379
|
-
const
|
|
24380
|
-
const
|
|
24381
|
-
const
|
|
24382
|
-
const
|
|
24383
|
-
const
|
|
24384
|
-
if (!globalID ||
|
|
24385
|
-
subscription_openData(
|
|
24386
|
-
subscription_createSubscriptionManager(
|
|
24387
|
-
};
|
|
24388
|
-
const
|
|
24410
|
+
const getHeatmapCaptureSelectionKey = (globalID)=>`heatmapCaptureSelection-${globalID}`;
|
|
24411
|
+
const getHeatmapCaptureSelectionSubscriptionKey = (globalID)=>`${getHeatmapCaptureSelectionKey(globalID)}-update`;
|
|
24412
|
+
const isSelectionEqual = (left, right)=>left === right || null !== left && null !== right && Math.abs(left.x[0] - right.x[0]) <= 1e-7 && Math.abs(left.x[1] - right.x[1]) <= 1e-7 && Math.abs(left.y[0] - right.y[0]) <= 1e-7 && Math.abs(left.y[1] - right.y[1]) <= 1e-7;
|
|
24413
|
+
const getHeatmapCaptureSelection = (globalID)=>subscription_openData(getHeatmapCaptureSelectionKey(globalID), void 0, null, globalID);
|
|
24414
|
+
const setHeatmapCaptureSelection = (globalID, selection)=>{
|
|
24415
|
+
if (!globalID || isSelectionEqual(getHeatmapCaptureSelection(globalID), selection)) return;
|
|
24416
|
+
subscription_openData(getHeatmapCaptureSelectionKey(globalID), selection, null, globalID);
|
|
24417
|
+
subscription_createSubscriptionManager(getHeatmapCaptureSelectionSubscriptionKey(globalID))(selection);
|
|
24418
|
+
};
|
|
24419
|
+
const subscribeHeatmapCaptureSelection = (globalID, func)=>subscription_createSubscriptionManager(getHeatmapCaptureSelectionSubscriptionKey(globalID), 'HeatmapOverview', func, globalID);
|
|
24389
24420
|
const Area_COMPONENT_KEY = constants_ToolType.HeatmapCapture;
|
|
24390
24421
|
const Area_Area = (props)=>{
|
|
24391
24422
|
const { state: { heatmapCapture, axisX: { frequencyFormat, unit }, system, globalID } } = useStore_useStore();
|
|
@@ -25491,7 +25522,7 @@ const DragSelectBox = ({ enabled, defaultRect, minSize = 0, minWidth, minHeight,
|
|
|
25491
25522
|
return nextRect;
|
|
25492
25523
|
};
|
|
25493
25524
|
const handleBoxMouseDown = (event, type, startRect)=>{
|
|
25494
|
-
if (onDragStart?.() === false) return;
|
|
25525
|
+
if (onDragStart?.(type) === false) return;
|
|
25495
25526
|
event.preventDefault();
|
|
25496
25527
|
event.stopPropagation();
|
|
25497
25528
|
handleMouseDown(event, type, startRect);
|
|
@@ -25686,12 +25717,191 @@ const DragSelectBox = ({ enabled, defaultRect, minSize = 0, minWidth, minHeight,
|
|
|
25686
25717
|
});
|
|
25687
25718
|
};
|
|
25688
25719
|
const components_DragSelectBox = DragSelectBox;
|
|
25689
|
-
const sliderInfo_PRECISION =
|
|
25690
|
-
const
|
|
25720
|
+
const sliderInfo_PRECISION = 1e6;
|
|
25721
|
+
const sliderInfo_clamp = (value1, min, max)=>Math.min(max, Math.max(min, value1));
|
|
25722
|
+
const resolveFrequencyExtent = (frequencyFormat)=>{
|
|
25723
|
+
if (!frequencyFormat) return null;
|
|
25724
|
+
const start = Number(frequencyFormat(0));
|
|
25725
|
+
const end = Number(frequencyFormat(100));
|
|
25726
|
+
if (!Number.isFinite(start) || !Number.isFinite(end) || start === end) return null;
|
|
25727
|
+
return [
|
|
25728
|
+
start,
|
|
25729
|
+
end
|
|
25730
|
+
];
|
|
25731
|
+
};
|
|
25732
|
+
const resolveContinuousFrequencyFromSegments = (ratio, segments, edge)=>{
|
|
25733
|
+
if (!segments?.length) return null;
|
|
25734
|
+
const percent = 100 * sliderInfo_clamp(ratio, 0, 1);
|
|
25735
|
+
const lastIndex = segments.length - 1;
|
|
25736
|
+
for(let index = 0; index < segments.length; index += 1){
|
|
25737
|
+
const segment = segments[index];
|
|
25738
|
+
const progressStart = Math.min(segment.progress[0], segment.progress[1]);
|
|
25739
|
+
const progressEnd = Math.max(segment.progress[0], segment.progress[1]);
|
|
25740
|
+
const contains = 'start' === edge ? percent >= progressStart && (percent < progressEnd || index === lastIndex && percent <= progressEnd) : (percent > progressStart || 0 === index) && percent <= progressEnd;
|
|
25741
|
+
if (!contains) continue;
|
|
25742
|
+
const progressSpan = progressEnd - progressStart;
|
|
25743
|
+
const localRatio = progressSpan ? (percent - progressStart) / progressSpan : 0;
|
|
25744
|
+
return segment.start + (segment.stop - segment.start) * localRatio;
|
|
25745
|
+
}
|
|
25746
|
+
return null;
|
|
25747
|
+
};
|
|
25748
|
+
const resolveFrequencyFromRatio = (ratio, segments, frequencyFormat, edge)=>{
|
|
25749
|
+
const value1 = frequencyFormat?.(100 * sliderInfo_clamp(ratio, 0, 1));
|
|
25750
|
+
const frequency = void 0 === value1 ? Number.NaN : Number(value1);
|
|
25751
|
+
if (Number.isFinite(frequency)) return frequency;
|
|
25752
|
+
return resolveContinuousFrequencyFromSegments(ratio, segments, edge);
|
|
25753
|
+
};
|
|
25754
|
+
const resolveRatioFromFrequency = (frequency, segments, frequencyFormat)=>{
|
|
25755
|
+
if (segments?.length) {
|
|
25756
|
+
let nearest = null;
|
|
25757
|
+
for (const segment of segments){
|
|
25758
|
+
const frequencyStart = segment.start;
|
|
25759
|
+
const frequencyEnd = segment.stop;
|
|
25760
|
+
const frequencyMin = Math.min(frequencyStart, frequencyEnd);
|
|
25761
|
+
const frequencyMax = Math.max(frequencyStart, frequencyEnd);
|
|
25762
|
+
const progressStart = segment.progress[0] / 100;
|
|
25763
|
+
const progressEnd = segment.progress[1] / 100;
|
|
25764
|
+
if (frequency >= frequencyMin && frequency <= frequencyMax) {
|
|
25765
|
+
const frequencySpan = frequencyEnd - frequencyStart;
|
|
25766
|
+
const localRatio = frequencySpan ? (frequency - frequencyStart) / frequencySpan : 0;
|
|
25767
|
+
return sliderInfo_clamp(progressStart + (progressEnd - progressStart) * localRatio, 0, 1);
|
|
25768
|
+
}
|
|
25769
|
+
const candidates = [
|
|
25770
|
+
{
|
|
25771
|
+
distance: Math.abs(frequency - frequencyStart),
|
|
25772
|
+
ratio: progressStart
|
|
25773
|
+
},
|
|
25774
|
+
{
|
|
25775
|
+
distance: Math.abs(frequency - frequencyEnd),
|
|
25776
|
+
ratio: progressEnd
|
|
25777
|
+
}
|
|
25778
|
+
];
|
|
25779
|
+
for (const candidate of candidates)if (!nearest || candidate.distance < nearest.distance) nearest = candidate;
|
|
25780
|
+
}
|
|
25781
|
+
if (nearest) return sliderInfo_clamp(nearest.ratio, 0, 1);
|
|
25782
|
+
}
|
|
25783
|
+
const extent = resolveFrequencyExtent(frequencyFormat);
|
|
25784
|
+
if (!extent) return null;
|
|
25785
|
+
return sliderInfo_clamp((frequency - extent[0]) / (extent[1] - extent[0]), 0, 1);
|
|
25786
|
+
};
|
|
25787
|
+
const resolveHeatmapSliderFrequencyRatioRange = ({ frequencyFormat, frequencyRange, segments })=>{
|
|
25788
|
+
const start = resolveRatioFromFrequency(frequencyRange[0], segments, frequencyFormat);
|
|
25789
|
+
const end = resolveRatioFromFrequency(frequencyRange[1], segments, frequencyFormat);
|
|
25790
|
+
if (null === start || null === end) return null;
|
|
25791
|
+
return [
|
|
25792
|
+
Math.min(start, end),
|
|
25793
|
+
Math.max(start, end)
|
|
25794
|
+
];
|
|
25795
|
+
};
|
|
25796
|
+
const resolveFrequencyRangeFromRatios = (ratios, segments, frequencyFormat)=>{
|
|
25797
|
+
const start = resolveFrequencyFromRatio(ratios[0], segments, frequencyFormat, 'start');
|
|
25798
|
+
const end = resolveFrequencyFromRatio(ratios[1], segments, frequencyFormat, 'end');
|
|
25799
|
+
if (null === start || null === end) return null;
|
|
25800
|
+
return [
|
|
25801
|
+
Math.min(start, end),
|
|
25802
|
+
Math.max(start, end)
|
|
25803
|
+
];
|
|
25804
|
+
};
|
|
25805
|
+
const resolveHeatmapSliderSelectionFromRect = ({ frequencyFormat, rect, segments, waterfallSnapshot })=>{
|
|
25806
|
+
const continuousRange = resolveHeatmapProjectedContinuousSourceRange(waterfallSnapshot, {
|
|
25807
|
+
startLeft: rect.leftPosition,
|
|
25808
|
+
endLeft: rect.leftPosition + rect.width,
|
|
25809
|
+
startTop: rect.position + rect.height,
|
|
25810
|
+
endTop: rect.position
|
|
25811
|
+
});
|
|
25812
|
+
if (!continuousRange || waterfallSnapshot.sourceSize.width <= 0) return null;
|
|
25813
|
+
const x = [
|
|
25814
|
+
continuousRange.x[0] / waterfallSnapshot.sourceSize.width,
|
|
25815
|
+
continuousRange.x[1] / waterfallSnapshot.sourceSize.width
|
|
25816
|
+
];
|
|
25817
|
+
return {
|
|
25818
|
+
frequency: resolveFrequencyRangeFromRatios(x, segments, frequencyFormat),
|
|
25819
|
+
x,
|
|
25820
|
+
y: continuousRange.y
|
|
25821
|
+
};
|
|
25822
|
+
};
|
|
25823
|
+
const resolveHeatmapSliderSelectionFromInteraction = ({ dragType, frequencyFormat, rect, segments, startSelection, waterfallSnapshot })=>{
|
|
25824
|
+
const current = resolveHeatmapSliderSelectionFromRect({
|
|
25825
|
+
frequencyFormat,
|
|
25826
|
+
rect,
|
|
25827
|
+
segments,
|
|
25828
|
+
waterfallSnapshot
|
|
25829
|
+
});
|
|
25830
|
+
if (!current || !startSelection) return current;
|
|
25831
|
+
switch(dragType){
|
|
25832
|
+
case 'left':
|
|
25833
|
+
return {
|
|
25834
|
+
frequency: current.frequency && startSelection.frequency ? [
|
|
25835
|
+
current.frequency[0],
|
|
25836
|
+
startSelection.frequency[1]
|
|
25837
|
+
] : current.frequency,
|
|
25838
|
+
x: [
|
|
25839
|
+
current.x[0],
|
|
25840
|
+
startSelection.x[1]
|
|
25841
|
+
],
|
|
25842
|
+
y: startSelection.y
|
|
25843
|
+
};
|
|
25844
|
+
case 'right':
|
|
25845
|
+
return {
|
|
25846
|
+
frequency: current.frequency && startSelection.frequency ? [
|
|
25847
|
+
startSelection.frequency[0],
|
|
25848
|
+
current.frequency[1]
|
|
25849
|
+
] : current.frequency,
|
|
25850
|
+
x: [
|
|
25851
|
+
startSelection.x[0],
|
|
25852
|
+
current.x[1]
|
|
25853
|
+
],
|
|
25854
|
+
y: startSelection.y
|
|
25855
|
+
};
|
|
25856
|
+
case 'top':
|
|
25857
|
+
return {
|
|
25858
|
+
frequency: startSelection.frequency,
|
|
25859
|
+
x: startSelection.x,
|
|
25860
|
+
y: [
|
|
25861
|
+
startSelection.y[0],
|
|
25862
|
+
current.y[1]
|
|
25863
|
+
]
|
|
25864
|
+
};
|
|
25865
|
+
case 'bottom':
|
|
25866
|
+
return {
|
|
25867
|
+
frequency: startSelection.frequency,
|
|
25868
|
+
x: startSelection.x,
|
|
25869
|
+
y: [
|
|
25870
|
+
current.y[0],
|
|
25871
|
+
startSelection.y[1]
|
|
25872
|
+
]
|
|
25873
|
+
};
|
|
25874
|
+
case 'middle':
|
|
25875
|
+
return current;
|
|
25876
|
+
}
|
|
25877
|
+
};
|
|
25878
|
+
const resolveHeatmapSliderSelectionSourceRange = ({ selection, waterfallSnapshot })=>{
|
|
25879
|
+
const { sourceSize } = waterfallSnapshot;
|
|
25880
|
+
if (sourceSize.width <= 0 || sourceSize.height <= 0) return null;
|
|
25881
|
+
const xStart = sliderInfo_clamp(Math.min(selection.x[0], selection.x[1]), 0, 1);
|
|
25882
|
+
const xEnd = sliderInfo_clamp(Math.max(selection.x[0], selection.x[1]), xStart, 1);
|
|
25883
|
+
const yStart = sliderInfo_clamp(Math.min(selection.y[0], selection.y[1]), 0, sourceSize.height);
|
|
25884
|
+
const yEnd = sliderInfo_clamp(Math.max(selection.y[0], selection.y[1]), yStart, sourceSize.height);
|
|
25885
|
+
return {
|
|
25886
|
+
x: [
|
|
25887
|
+
xStart * sourceSize.width,
|
|
25888
|
+
xEnd * sourceSize.width
|
|
25889
|
+
],
|
|
25890
|
+
y: [
|
|
25891
|
+
yStart,
|
|
25892
|
+
yEnd
|
|
25893
|
+
]
|
|
25894
|
+
};
|
|
25895
|
+
};
|
|
25896
|
+
const calculateHeatmapSliderInfo = ({ formatBandwidth, frequencyFormat, heatmapData, rect, segments, selectionOverride, sourceRangeOverride, waterfallSnapshot })=>{
|
|
25691
25897
|
const len = heatmapData.length;
|
|
25692
25898
|
if (len <= 0) return null;
|
|
25693
25899
|
const { position, height, leftPosition: left, width } = rect;
|
|
25694
|
-
const
|
|
25900
|
+
const continuousSourceRangeOverride = waterfallSnapshot && selectionOverride ? resolveHeatmapSliderSelectionSourceRange({
|
|
25901
|
+
selection: selectionOverride,
|
|
25902
|
+
waterfallSnapshot
|
|
25903
|
+
}) : null;
|
|
25904
|
+
const sourceRange = sourceRangeOverride ?? (waterfallSnapshot && continuousSourceRangeOverride ? quantizeHeatmapContinuousSourceRange(waterfallSnapshot, continuousSourceRangeOverride) : null) ?? (waterfallSnapshot ? resolveHeatmapProjectedSourceRange(waterfallSnapshot, {
|
|
25695
25905
|
startLeft: left,
|
|
25696
25906
|
endLeft: left + width,
|
|
25697
25907
|
startTop: position + height,
|
|
@@ -25709,12 +25919,16 @@ const calculateHeatmapSliderInfo = ({ formatBandwidth, frequencyFormat, heatmapD
|
|
|
25709
25919
|
if (!columnRange) return null;
|
|
25710
25920
|
const { startCol, endCol } = columnRange;
|
|
25711
25921
|
const sourceWidth = waterfallSnapshot?.sourceSize.width ?? 0;
|
|
25712
|
-
const startLeft = sourceRangeOverride && sourceWidth > 0 ? 100 * startCol / sourceWidth : waterfallSnapshot ? resolveHeatmapSourceLeft(left, waterfallSnapshot) : left;
|
|
25713
|
-
const endLeft = sourceRangeOverride && sourceWidth > 0 ? (endCol + 1) * 100 / sourceWidth : waterfallSnapshot ? resolveHeatmapSourceLeft(left + width, waterfallSnapshot) : left + width;
|
|
25714
|
-
const
|
|
25715
|
-
|
|
25716
|
-
|
|
25717
|
-
|
|
25922
|
+
const startLeft = selectionOverride ? 100 * selectionOverride.x[0] : sourceRangeOverride && sourceWidth > 0 ? 100 * startCol / sourceWidth : waterfallSnapshot ? resolveHeatmapSourceLeft(left, waterfallSnapshot) : left;
|
|
25923
|
+
const endLeft = selectionOverride ? 100 * selectionOverride.x[1] : sourceRangeOverride && sourceWidth > 0 ? (endCol + 1) * 100 / sourceWidth : waterfallSnapshot ? resolveHeatmapSourceLeft(left + width, waterfallSnapshot) : left + width;
|
|
25924
|
+
const fallbackFrequencyRange = resolveFrequencyRangeFromRatios([
|
|
25925
|
+
startLeft / 100,
|
|
25926
|
+
endLeft / 100
|
|
25927
|
+
], segments, frequencyFormat);
|
|
25928
|
+
const startFrequencyValue = selectionOverride?.frequency?.[0] ?? fallbackFrequencyRange?.[0];
|
|
25929
|
+
const endFrequencyValue = selectionOverride?.frequency?.[1] ?? fallbackFrequencyRange?.[1];
|
|
25930
|
+
const startFrequency = Number.isFinite(startFrequencyValue) ? Math.round(Number(startFrequencyValue) * sliderInfo_PRECISION) / sliderInfo_PRECISION : 0;
|
|
25931
|
+
const endFrequency = Number.isFinite(endFrequencyValue) ? Math.round(Number(endFrequencyValue) * sliderInfo_PRECISION) / sliderInfo_PRECISION : 0;
|
|
25718
25932
|
const bandwidth = Math.abs(endFrequency - startFrequency);
|
|
25719
25933
|
return {
|
|
25720
25934
|
startIndex,
|
|
@@ -25747,7 +25961,7 @@ const isRectEqual = (left, right)=>Math.abs(left.position - right.position) <= 0
|
|
|
25747
25961
|
const isBoundsEqual = (left, right)=>Math.abs(left.top - right.top) <= 0.01 && Math.abs(left.bottom - right.bottom) <= 0.01 && Math.abs(left.left - right.left) <= 0.01 && Math.abs(left.right - right.right) <= 0.01;
|
|
25748
25962
|
const isSliderInfoEqual = (left, right)=>left.startIndex === right.startIndex && left.endIndex === right.endIndex && left.startTimestamp === right.startTimestamp && left.endTimestamp === right.endTimestamp && left.duration === right.duration && left.startCol === right.startCol && left.endCol === right.endCol && left.startFrequency === right.startFrequency && left.startFrequencyFormat === right.startFrequencyFormat && left.endFrequency === right.endFrequency && left.endFrequencyFormat === right.endFrequencyFormat && left.bandwidth === right.bandwidth && left.bandwidthFormat === right.bandwidthFormat;
|
|
25749
25963
|
const Slider = ({ id })=>{
|
|
25750
|
-
const { state: { globalID, heatmapCapture: { type, show, display, interval, onChange }, axisX: { frequencyFormat, unit } } } = useStore_useStore();
|
|
25964
|
+
const { state: { globalID, heatmapCapture: { type, show, display, interval, onChange }, axisX: { frequencyFormat, unit }, segments } } = useStore_useStore();
|
|
25751
25965
|
const canSlider = (0, __WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>type === heatmap_HeatmapCaptureType.Slider && show && display, [
|
|
25752
25966
|
type,
|
|
25753
25967
|
show,
|
|
@@ -25759,8 +25973,14 @@ const Slider = ({ id })=>{
|
|
|
25759
25973
|
const [currentRect, setCurrentRect] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(DEFAULT_RECT);
|
|
25760
25974
|
const [interactionBounds, setInteractionBounds] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)();
|
|
25761
25975
|
const currentRectRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(currentRect);
|
|
25976
|
+
const selectionRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
|
|
25977
|
+
const dragStartSelectionRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
|
|
25978
|
+
const dragStartRectRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
|
|
25979
|
+
const activeDragTypeRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(null);
|
|
25762
25980
|
const frequencyFormatRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(frequencyFormat);
|
|
25981
|
+
const segmentsRef = (0, __WEBPACK_EXTERNAL_MODULE_react__.useRef)(segments);
|
|
25763
25982
|
frequencyFormatRef.current = frequencyFormat;
|
|
25983
|
+
segmentsRef.current = segments;
|
|
25764
25984
|
const updateCurrentRect = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((rect)=>{
|
|
25765
25985
|
currentRectRef.current = rect;
|
|
25766
25986
|
setCurrentRect((current)=>isRectEqual(current, rect) ? current : rect);
|
|
@@ -25771,40 +25991,39 @@ const Slider = ({ id })=>{
|
|
|
25771
25991
|
return isBoundsEqual(current, bounds) ? current : bounds;
|
|
25772
25992
|
});
|
|
25773
25993
|
}, []);
|
|
25994
|
+
const updateSelectionSnapshot = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((nextInfo)=>{
|
|
25995
|
+
const waterfallSnapshot = getHeatmapWaterfallSnapshot(globalID);
|
|
25996
|
+
const selection = selectionRef.current;
|
|
25997
|
+
const continuousRange = waterfallSnapshot && selection ? resolveHeatmapSliderSelectionSourceRange({
|
|
25998
|
+
selection,
|
|
25999
|
+
waterfallSnapshot
|
|
26000
|
+
}) : null;
|
|
26001
|
+
setHeatmapCaptureSelection(globalID, canSlider && nextInfo && continuousRange ? continuousRange : null);
|
|
26002
|
+
}, [
|
|
26003
|
+
canSlider,
|
|
26004
|
+
globalID
|
|
26005
|
+
]);
|
|
25774
26006
|
const updateInfo = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((nextInfo, notify)=>{
|
|
25775
26007
|
infoRef.current = nextInfo;
|
|
25776
26008
|
setInfo(nextInfo);
|
|
25777
|
-
|
|
25778
|
-
endCol: nextInfo.endCol,
|
|
25779
|
-
endIndex: nextInfo.endIndex,
|
|
25780
|
-
startCol: nextInfo.startCol,
|
|
25781
|
-
startIndex: nextInfo.startIndex
|
|
25782
|
-
});
|
|
26009
|
+
updateSelectionSnapshot(nextInfo);
|
|
25783
26010
|
if (notify) {
|
|
25784
26011
|
notifiedRawDataRef.current = getHeatmapWaterfallSnapshot(globalID)?.rawData ?? null;
|
|
25785
26012
|
onChange?.(nextInfo);
|
|
25786
26013
|
}
|
|
25787
26014
|
}, [
|
|
25788
|
-
canSlider,
|
|
25789
26015
|
globalID,
|
|
25790
|
-
onChange
|
|
26016
|
+
onChange,
|
|
26017
|
+
updateSelectionSnapshot
|
|
25791
26018
|
]);
|
|
25792
26019
|
(0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
|
|
25793
|
-
if (!globalID
|
|
25794
|
-
|
|
25795
|
-
|
|
25796
|
-
}
|
|
25797
|
-
const currentInfo = infoRef.current;
|
|
25798
|
-
if (currentInfo) setHeatmapCaptureSourceRange(globalID, {
|
|
25799
|
-
endCol: currentInfo.endCol,
|
|
25800
|
-
endIndex: currentInfo.endIndex,
|
|
25801
|
-
startCol: currentInfo.startCol,
|
|
25802
|
-
startIndex: currentInfo.startIndex
|
|
25803
|
-
});
|
|
25804
|
-
return ()=>setHeatmapCaptureSourceRange(globalID, null);
|
|
26020
|
+
if (!globalID) return;
|
|
26021
|
+
updateSelectionSnapshot(canSlider ? infoRef.current ?? null : null);
|
|
26022
|
+
return ()=>setHeatmapCaptureSelection(globalID, null);
|
|
25805
26023
|
}, [
|
|
25806
26024
|
canSlider,
|
|
25807
|
-
globalID
|
|
26025
|
+
globalID,
|
|
26026
|
+
updateSelectionSnapshot
|
|
25808
26027
|
]);
|
|
25809
26028
|
const getHeatmapData = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)(()=>{
|
|
25810
26029
|
const waterfallData = withDatabase(globalID).getAllRawData().waterfallData ?? [];
|
|
@@ -25815,20 +26034,42 @@ const Slider = ({ id })=>{
|
|
|
25815
26034
|
}, [
|
|
25816
26035
|
globalID
|
|
25817
26036
|
]);
|
|
25818
|
-
const calculateSliderInfo = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((r,
|
|
26037
|
+
const calculateSliderInfo = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((r, selectionOverride)=>{
|
|
25819
26038
|
const [heatmapData] = getHeatmapData();
|
|
25820
26039
|
return calculateHeatmapSliderInfo({
|
|
25821
26040
|
formatBandwidth: getFrequencyToFixed,
|
|
25822
26041
|
frequencyFormat: frequencyFormatRef.current,
|
|
25823
26042
|
heatmapData,
|
|
25824
26043
|
rect: r,
|
|
25825
|
-
|
|
26044
|
+
segments: segmentsRef.current,
|
|
26045
|
+
selectionOverride,
|
|
25826
26046
|
waterfallSnapshot: getHeatmapWaterfallSnapshot(globalID)
|
|
25827
26047
|
});
|
|
25828
26048
|
}, [
|
|
25829
26049
|
getHeatmapData,
|
|
25830
26050
|
globalID
|
|
25831
26051
|
]);
|
|
26052
|
+
const updateSelection = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((rect, dragType)=>{
|
|
26053
|
+
const waterfallSnapshot = getHeatmapWaterfallSnapshot(globalID);
|
|
26054
|
+
if (!waterfallSnapshot) return null;
|
|
26055
|
+
const nextSelection = dragType ? resolveHeatmapSliderSelectionFromInteraction({
|
|
26056
|
+
dragType,
|
|
26057
|
+
frequencyFormat: frequencyFormatRef.current,
|
|
26058
|
+
rect,
|
|
26059
|
+
segments: segmentsRef.current,
|
|
26060
|
+
startSelection: dragStartSelectionRef.current,
|
|
26061
|
+
waterfallSnapshot
|
|
26062
|
+
}) : resolveHeatmapSliderSelectionFromRect({
|
|
26063
|
+
frequencyFormat: frequencyFormatRef.current,
|
|
26064
|
+
rect,
|
|
26065
|
+
segments: segmentsRef.current,
|
|
26066
|
+
waterfallSnapshot
|
|
26067
|
+
});
|
|
26068
|
+
if (nextSelection) selectionRef.current = nextSelection;
|
|
26069
|
+
return nextSelection;
|
|
26070
|
+
}, [
|
|
26071
|
+
globalID
|
|
26072
|
+
]);
|
|
25832
26073
|
const [updateKey, setUpdateKey] = (0, __WEBPACK_EXTERNAL_MODULE_react__.useState)(0);
|
|
25833
26074
|
(0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
|
|
25834
26075
|
if (!id || !globalID) return;
|
|
@@ -25838,18 +26079,32 @@ const Slider = ({ id })=>{
|
|
|
25838
26079
|
globalID
|
|
25839
26080
|
]);
|
|
25840
26081
|
const handleChange = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((rect)=>{
|
|
26082
|
+
const startRect = dragStartRectRef.current;
|
|
26083
|
+
if (startRect && isRectEqual(startRect, rect)) return;
|
|
25841
26084
|
updateCurrentRect(rect);
|
|
25842
|
-
const
|
|
26085
|
+
const selection = updateSelection(rect, activeDragTypeRef.current);
|
|
26086
|
+
const newInfo = calculateSliderInfo(rect, selection ?? void 0);
|
|
25843
26087
|
if (newInfo) updateInfo(newInfo, false);
|
|
25844
26088
|
}, [
|
|
25845
26089
|
calculateSliderInfo,
|
|
25846
26090
|
updateCurrentRect,
|
|
25847
|
-
updateInfo
|
|
26091
|
+
updateInfo,
|
|
26092
|
+
updateSelection
|
|
25848
26093
|
]);
|
|
25849
|
-
const claimCaptureInteraction = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)(()=>
|
|
26094
|
+
const claimCaptureInteraction = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((dragType)=>{
|
|
26095
|
+
const claimed = compareEventPriority(id, constants_ToolType.HeatmapCapture);
|
|
26096
|
+
if (false === claimed) return false;
|
|
26097
|
+
activeDragTypeRef.current = dragType;
|
|
26098
|
+
dragStartSelectionRef.current = selectionRef.current;
|
|
26099
|
+
dragStartRectRef.current = currentRectRef.current;
|
|
26100
|
+
return claimed;
|
|
26101
|
+
}, [
|
|
25850
26102
|
id
|
|
25851
26103
|
]);
|
|
25852
26104
|
const releaseCaptureInteraction = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)(()=>{
|
|
26105
|
+
activeDragTypeRef.current = null;
|
|
26106
|
+
dragStartSelectionRef.current = null;
|
|
26107
|
+
dragStartRectRef.current = null;
|
|
25853
26108
|
createMouseUpEventManager(getEID(id))();
|
|
25854
26109
|
resetEventLevel(id, constants_ToolType.HeatmapCapture);
|
|
25855
26110
|
}, [
|
|
@@ -25857,8 +26112,8 @@ const Slider = ({ id })=>{
|
|
|
25857
26112
|
]);
|
|
25858
26113
|
const handleDragEnd = (0, __WEBPACK_EXTERNAL_MODULE_react__.useCallback)((rect)=>{
|
|
25859
26114
|
try {
|
|
25860
|
-
|
|
25861
|
-
const newInfo = calculateSliderInfo(rect);
|
|
26115
|
+
const selection = selectionRef.current ?? updateSelection(rect, null);
|
|
26116
|
+
const newInfo = calculateSliderInfo(rect, selection ?? void 0);
|
|
25862
26117
|
if (newInfo) updateInfo(newInfo, true);
|
|
25863
26118
|
} finally{
|
|
25864
26119
|
releaseCaptureInteraction();
|
|
@@ -25866,8 +26121,8 @@ const Slider = ({ id })=>{
|
|
|
25866
26121
|
}, [
|
|
25867
26122
|
calculateSliderInfo,
|
|
25868
26123
|
releaseCaptureInteraction,
|
|
25869
|
-
|
|
25870
|
-
|
|
26124
|
+
updateInfo,
|
|
26125
|
+
updateSelection
|
|
25871
26126
|
]);
|
|
25872
26127
|
(0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>releaseCaptureInteraction, [
|
|
25873
26128
|
canSlider,
|
|
@@ -25879,34 +26134,54 @@ const Slider = ({ id })=>{
|
|
|
25879
26134
|
const waterfallSnapshot = getHeatmapWaterfallSnapshot(globalID);
|
|
25880
26135
|
const currentInfo = infoRef.current;
|
|
25881
26136
|
const rowsUnchanged = startIndex === currentInfo?.startIndex && endIndex === currentInfo.endIndex;
|
|
25882
|
-
const
|
|
26137
|
+
const currentFrequencyRange = selectionRef.current?.frequency;
|
|
26138
|
+
const frequenciesUnchanged = void 0 === startFrequency || void 0 === endFrequency ? true : Math.abs(Math.min(startFrequency, endFrequency) - (currentFrequencyRange?.[0] ?? Number.NaN)) <= 1e-7 && Math.abs(Math.max(startFrequency, endFrequency) - (currentFrequencyRange?.[1] ?? Number.NaN)) <= 1e-7;
|
|
25883
26139
|
if (rowsUnchanged && frequenciesUnchanged) return;
|
|
25884
26140
|
const activeRect = currentRectRef.current;
|
|
25885
26141
|
if (waterfallSnapshot) {
|
|
26142
|
+
const { sourceSize } = waterfallSnapshot;
|
|
26143
|
+
if (sourceSize.width <= 0 || sourceSize.height <= 0) return;
|
|
25886
26144
|
const validRows = len > 0 && startIndex >= 0 && endIndex < len && endIndex - startIndex >= Math.ceil(MIN_SIZE * len / 100);
|
|
25887
|
-
const
|
|
25888
|
-
|
|
25889
|
-
|
|
25890
|
-
|
|
25891
|
-
|
|
26145
|
+
const currentSelection = selectionRef.current ?? resolveHeatmapSliderSelectionFromRect({
|
|
26146
|
+
frequencyFormat: frequencyFormatRef.current,
|
|
26147
|
+
rect: activeRect,
|
|
26148
|
+
segments: segmentsRef.current,
|
|
26149
|
+
waterfallSnapshot
|
|
26150
|
+
});
|
|
26151
|
+
const externalFrequencyRange = void 0 !== startFrequency && void 0 !== endFrequency ? [
|
|
26152
|
+
Math.min(startFrequency, endFrequency),
|
|
26153
|
+
Math.max(startFrequency, endFrequency)
|
|
26154
|
+
] : null;
|
|
26155
|
+
const externalFrequencyRatios = externalFrequencyRange ? resolveHeatmapSliderFrequencyRatioRange({
|
|
26156
|
+
frequencyFormat: frequencyFormatRef.current,
|
|
26157
|
+
frequencyRange: externalFrequencyRange,
|
|
26158
|
+
segments: segmentsRef.current
|
|
26159
|
+
}) : null;
|
|
26160
|
+
if (externalFrequencyRange && !externalFrequencyRatios) return;
|
|
26161
|
+
const targetSelection = {
|
|
26162
|
+
frequency: externalFrequencyRange ?? currentSelection?.frequency ?? null,
|
|
26163
|
+
x: externalFrequencyRatios ?? currentSelection?.x ?? [
|
|
26164
|
+
waterfallSnapshot.range.x[0] / sourceSize.width,
|
|
26165
|
+
waterfallSnapshot.range.x[1] / sourceSize.width
|
|
26166
|
+
],
|
|
26167
|
+
y: validRows ? [
|
|
26168
|
+
Math.min(startIndex, endIndex),
|
|
26169
|
+
Math.max(startIndex, endIndex) + 1
|
|
26170
|
+
] : currentSelection?.y ?? [
|
|
26171
|
+
currentInfo?.startIndex ?? waterfallSnapshot.range.y[0],
|
|
26172
|
+
(currentInfo?.endIndex ?? waterfallSnapshot.range.y[1] - 1) + 1
|
|
26173
|
+
]
|
|
25892
26174
|
};
|
|
25893
|
-
|
|
25894
|
-
|
|
25895
|
-
|
|
25896
|
-
|
|
25897
|
-
|
|
25898
|
-
|
|
25899
|
-
const endPercent = Math.max(startPercent, Math.min(100, (Math.max(startFrequency, endFrequency) - minFrequency) / frequencySpan * 100));
|
|
25900
|
-
const sourceWidth = waterfallSnapshot.sourceSize.width;
|
|
25901
|
-
targetRange.startCol = Math.max(0, Math.min(sourceWidth - 1, Math.floor(startPercent * sourceWidth / 100)));
|
|
25902
|
-
targetRange.endCol = Math.max(targetRange.startCol, Math.min(sourceWidth - 1, Math.ceil(endPercent * sourceWidth / 100) - 1));
|
|
25903
|
-
}
|
|
25904
|
-
}
|
|
25905
|
-
if (currentInfo?.startIndex === targetRange.startIndex && currentInfo.endIndex === targetRange.endIndex && currentInfo.startCol === targetRange.startCol && currentInfo.endCol === targetRange.endCol) return;
|
|
25906
|
-
const nextRect = resolveHeatmapSourceRangeScreenRect(waterfallSnapshot, targetRange);
|
|
26175
|
+
const continuousRange = resolveHeatmapSliderSelectionSourceRange({
|
|
26176
|
+
selection: targetSelection,
|
|
26177
|
+
waterfallSnapshot
|
|
26178
|
+
});
|
|
26179
|
+
if (!continuousRange) return;
|
|
26180
|
+
const nextRect = resolveHeatmapContinuousSourceRangeScreenRect(waterfallSnapshot, continuousRange);
|
|
25907
26181
|
if (!nextRect) return;
|
|
26182
|
+
selectionRef.current = targetSelection;
|
|
25908
26183
|
updateCurrentRect(nextRect);
|
|
25909
|
-
const newInfo = calculateSliderInfo(nextRect,
|
|
26184
|
+
const newInfo = calculateSliderInfo(nextRect, targetSelection);
|
|
25910
26185
|
if (newInfo) updateInfo(newInfo, true);
|
|
25911
26186
|
return;
|
|
25912
26187
|
}
|
|
@@ -25983,21 +26258,46 @@ const Slider = ({ id })=>{
|
|
|
25983
26258
|
top: sourceRect.position
|
|
25984
26259
|
} : void 0);
|
|
25985
26260
|
} else updateInteractionBounds(void 0);
|
|
25986
|
-
if (!waterfallSnapshot
|
|
26261
|
+
if (!waterfallSnapshot) {
|
|
25987
26262
|
const newInfo = calculateSliderInfo(currentRectRef.current);
|
|
25988
26263
|
if (newInfo) updateInfo(newInfo, true);
|
|
25989
26264
|
return;
|
|
25990
26265
|
}
|
|
25991
|
-
|
|
26266
|
+
let selection = selectionRef.current ?? resolveHeatmapSliderSelectionFromRect({
|
|
26267
|
+
frequencyFormat: frequencyFormatRef.current,
|
|
26268
|
+
rect: currentRectRef.current,
|
|
26269
|
+
segments: segmentsRef.current,
|
|
26270
|
+
waterfallSnapshot
|
|
26271
|
+
});
|
|
26272
|
+
if (!selection) return;
|
|
26273
|
+
if (selection.frequency) {
|
|
26274
|
+
const x = resolveHeatmapSliderFrequencyRatioRange({
|
|
26275
|
+
frequencyFormat: frequencyFormatRef.current,
|
|
26276
|
+
frequencyRange: selection.frequency,
|
|
26277
|
+
segments: segmentsRef.current
|
|
26278
|
+
});
|
|
26279
|
+
if (x) selection = {
|
|
26280
|
+
...selection,
|
|
26281
|
+
x
|
|
26282
|
+
};
|
|
26283
|
+
}
|
|
26284
|
+
selectionRef.current = selection;
|
|
26285
|
+
const continuousSourceRange = resolveHeatmapSliderSelectionSourceRange({
|
|
26286
|
+
selection,
|
|
26287
|
+
waterfallSnapshot
|
|
26288
|
+
});
|
|
26289
|
+
if (!continuousSourceRange) return;
|
|
26290
|
+
const nextRect = resolveHeatmapContinuousSourceRangeScreenRect(waterfallSnapshot, continuousSourceRange);
|
|
25992
26291
|
if (nextRect) updateCurrentRect(nextRect);
|
|
25993
|
-
const refreshedInfo = calculateSliderInfo(nextRect ?? currentRectRef.current,
|
|
26292
|
+
const refreshedInfo = calculateSliderInfo(nextRect ?? currentRectRef.current, selection);
|
|
25994
26293
|
if (!refreshedInfo) return;
|
|
25995
|
-
const infoChanged = !isSliderInfoEqual(refreshedInfo, sourceInfo);
|
|
26294
|
+
const infoChanged = !sourceInfo || !isSliderInfoEqual(refreshedInfo, sourceInfo);
|
|
25996
26295
|
const rawDataChanged = notifiedRawDataRef.current !== waterfallSnapshot.rawData;
|
|
25997
26296
|
if (infoChanged || rawDataChanged) updateInfo(refreshedInfo, true);
|
|
25998
26297
|
}, [
|
|
25999
26298
|
updateKey,
|
|
26000
26299
|
frequencyFormat,
|
|
26300
|
+
segments,
|
|
26001
26301
|
canSlider,
|
|
26002
26302
|
globalID,
|
|
26003
26303
|
calculateSliderInfo,
|
|
@@ -26463,7 +26763,7 @@ const HeatmapOverview = /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react__.forw
|
|
|
26463
26763
|
context.restore();
|
|
26464
26764
|
const selectionRange = selectionRangeRef.current;
|
|
26465
26765
|
if (!selectionRange) return;
|
|
26466
|
-
const selectionRect =
|
|
26766
|
+
const selectionRect = resolveHeatmapOverviewContinuousSourceRangeRect(snapshot, selectionRange);
|
|
26467
26767
|
const selectionLeft = selectionRect.left * canvas.width;
|
|
26468
26768
|
const selectionTop = selectionRect.top * canvas.height;
|
|
26469
26769
|
const selectionWidth = Math.max(selectionRect.width * canvas.width, 2 * lineWidth);
|
|
@@ -26572,12 +26872,12 @@ const HeatmapOverview = /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react__.forw
|
|
|
26572
26872
|
updateOverlayColors
|
|
26573
26873
|
]);
|
|
26574
26874
|
(0, __WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
|
|
26575
|
-
const updateSelection = (
|
|
26576
|
-
selectionRangeRef.current =
|
|
26875
|
+
const updateSelection = (selection)=>{
|
|
26876
|
+
selectionRangeRef.current = selection;
|
|
26577
26877
|
scheduleDraw(false);
|
|
26578
26878
|
};
|
|
26579
|
-
const unsubscribe =
|
|
26580
|
-
updateSelection(
|
|
26879
|
+
const unsubscribe = subscribeHeatmapCaptureSelection(globalID, updateSelection);
|
|
26880
|
+
updateSelection(getHeatmapCaptureSelection(globalID));
|
|
26581
26881
|
return unsubscribe;
|
|
26582
26882
|
}, [
|
|
26583
26883
|
globalID,
|
|
@@ -26644,13 +26944,13 @@ const HeatmapOverview = /*#__PURE__*/ (0, __WEBPACK_EXTERNAL_MODULE_react__.forw
|
|
|
26644
26944
|
const sourcePoint = resolveHeatmapOverviewSourcePoint(snapshot, point);
|
|
26645
26945
|
const pointInViewport = isHeatmapOverviewSourcePointInViewport(snapshot, sourcePoint);
|
|
26646
26946
|
const selectionRange = selectionRangeRef.current;
|
|
26647
|
-
if (!pointInViewport && selectionRange && !
|
|
26947
|
+
if (!pointInViewport && selectionRange && !isHeatmapContinuousSourceRangeVisibleInViewport(snapshot, selectionRange)) {
|
|
26648
26948
|
const bounds = event.currentTarget.getBoundingClientRect();
|
|
26649
26949
|
const tolerance = {
|
|
26650
26950
|
x: bounds.width ? 6 * snapshot.sourceSize.width / bounds.width : 0,
|
|
26651
26951
|
y: bounds.height ? 6 * snapshot.sourceSize.height / bounds.height : 0
|
|
26652
26952
|
};
|
|
26653
|
-
if (
|
|
26953
|
+
if (isHeatmapOverviewSourcePointInContinuousRange(selectionRange, sourcePoint, tolerance)) return void scheduleRange(calculateHeatmapOverviewContinuousSourceRangeCenteredRange(snapshot, selectionRange));
|
|
26654
26954
|
}
|
|
26655
26955
|
if (!pointInViewport) return void scheduleRange(calculateHeatmapOverviewCenteredRange(snapshot, point));
|
|
26656
26956
|
dragRef.current = {
|
|
@@ -1,18 +1,53 @@
|
|
|
1
1
|
import type { TimestampedFloat32Array, WaterfallSnapshot } from '@rfkit/spectrum-analyzer';
|
|
2
|
-
import type { AxisXProps, HeatmapSlider2DData } from '../../../types';
|
|
3
|
-
import { type HeatmapSourceRange } from '../viewport.ts';
|
|
2
|
+
import type { AxisXProps, HeatmapSlider2DData, SegmentsType } from '../../../types';
|
|
3
|
+
import { type HeatmapContinuousSourceRange, type HeatmapSourceRange } from '../viewport.ts';
|
|
4
|
+
export interface HeatmapSliderSelection {
|
|
5
|
+
/** 业务频率。外部输入保持原值,指针交互按 axisX.frequencyFormat 解析。 */
|
|
6
|
+
frequency: readonly [start: number, end: number] | null;
|
|
7
|
+
/** 相对完整频率域的连续位置,不受瀑布矩阵列密度影响。 */
|
|
8
|
+
x: readonly [start: number, end: number];
|
|
9
|
+
/** 完整瀑布源数据中的连续行边界。 */
|
|
10
|
+
y: readonly [start: number, end: number];
|
|
11
|
+
}
|
|
12
|
+
export type HeatmapSliderDragType = 'top' | 'bottom' | 'left' | 'right' | 'middle';
|
|
13
|
+
interface HeatmapSliderRect {
|
|
14
|
+
height: number;
|
|
15
|
+
leftPosition: number;
|
|
16
|
+
position: number;
|
|
17
|
+
width: number;
|
|
18
|
+
}
|
|
4
19
|
interface SliderInfoParams {
|
|
5
20
|
formatBandwidth: (bandwidth: number) => string;
|
|
6
21
|
frequencyFormat: AxisXProps['frequencyFormat'];
|
|
7
22
|
heatmapData: readonly TimestampedFloat32Array[];
|
|
8
|
-
rect:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
position: number;
|
|
12
|
-
width: number;
|
|
13
|
-
};
|
|
23
|
+
rect: HeatmapSliderRect;
|
|
24
|
+
segments?: SegmentsType;
|
|
25
|
+
selectionOverride?: Readonly<HeatmapSliderSelection>;
|
|
14
26
|
sourceRangeOverride?: HeatmapSourceRange;
|
|
15
27
|
waterfallSnapshot: Readonly<WaterfallSnapshot> | null;
|
|
16
28
|
}
|
|
17
|
-
export declare const
|
|
29
|
+
export declare const resolveHeatmapSliderFrequencyRatioRange: ({ frequencyFormat, frequencyRange, segments }: {
|
|
30
|
+
frequencyFormat: AxisXProps["frequencyFormat"];
|
|
31
|
+
frequencyRange: readonly [start: number, end: number];
|
|
32
|
+
segments?: SegmentsType;
|
|
33
|
+
}) => readonly [start: number, end: number] | null;
|
|
34
|
+
export declare const resolveHeatmapSliderSelectionFromRect: ({ frequencyFormat, rect, segments, waterfallSnapshot }: {
|
|
35
|
+
frequencyFormat: AxisXProps["frequencyFormat"];
|
|
36
|
+
rect: HeatmapSliderRect;
|
|
37
|
+
segments?: SegmentsType;
|
|
38
|
+
waterfallSnapshot: Readonly<WaterfallSnapshot>;
|
|
39
|
+
}) => HeatmapSliderSelection | null;
|
|
40
|
+
export declare const resolveHeatmapSliderSelectionFromInteraction: ({ dragType, frequencyFormat, rect, segments, startSelection, waterfallSnapshot }: {
|
|
41
|
+
dragType: HeatmapSliderDragType;
|
|
42
|
+
frequencyFormat: AxisXProps["frequencyFormat"];
|
|
43
|
+
rect: HeatmapSliderRect;
|
|
44
|
+
segments?: SegmentsType;
|
|
45
|
+
startSelection: Readonly<HeatmapSliderSelection> | null;
|
|
46
|
+
waterfallSnapshot: Readonly<WaterfallSnapshot>;
|
|
47
|
+
}) => HeatmapSliderSelection | null;
|
|
48
|
+
export declare const resolveHeatmapSliderSelectionSourceRange: ({ selection, waterfallSnapshot }: {
|
|
49
|
+
selection: Readonly<HeatmapSliderSelection>;
|
|
50
|
+
waterfallSnapshot: Readonly<WaterfallSnapshot>;
|
|
51
|
+
}) => HeatmapContinuousSourceRange | null;
|
|
52
|
+
export declare const calculateHeatmapSliderInfo: ({ formatBandwidth, frequencyFormat, heatmapData, rect, segments, selectionOverride, sourceRangeOverride, waterfallSnapshot }: SliderInfoParams) => HeatmapSlider2DData | null;
|
|
18
53
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AxisXProps, HeatmapAreaData, HeatmapCaptureProps } from '../../../types';
|
|
2
|
-
import { type
|
|
2
|
+
import { type HeatmapContinuousSourceRange } from '../viewport';
|
|
3
3
|
interface Coordinates {
|
|
4
4
|
startLeft: number;
|
|
5
5
|
endLeft: number;
|
|
@@ -27,7 +27,7 @@ export declare const defaultAreaInfoResult: {
|
|
|
27
27
|
};
|
|
28
28
|
export default function calculateAreaInfo({ endLeft, startLeft, startTop, endTop, frequencyFormat, globalID }: AreaInfoParams): HeatmapAreaData;
|
|
29
29
|
export declare const heatmapCaptureUpdate: (globalID: string, func?: (props: Partial<HeatmapCaptureProps>) => void) => (...args: any[]) => void;
|
|
30
|
-
export declare const
|
|
31
|
-
export declare const
|
|
32
|
-
export declare const
|
|
30
|
+
export declare const getHeatmapCaptureSelection: (globalID: string) => Readonly<HeatmapContinuousSourceRange> | null;
|
|
31
|
+
export declare const setHeatmapCaptureSelection: (globalID: string, selection: Readonly<HeatmapContinuousSourceRange> | null) => void;
|
|
32
|
+
export declare const subscribeHeatmapCaptureSelection: (globalID: string, func: (selection: Readonly<HeatmapContinuousSourceRange> | null) => void) => (...args: any[]) => void;
|
|
33
33
|
export {};
|
|
@@ -12,6 +12,10 @@ export interface HeatmapSourceRange {
|
|
|
12
12
|
startCol: number;
|
|
13
13
|
startIndex: number;
|
|
14
14
|
}
|
|
15
|
+
export interface HeatmapContinuousSourceRange {
|
|
16
|
+
x: readonly [start: number, end: number];
|
|
17
|
+
y: readonly [start: number, end: number];
|
|
18
|
+
}
|
|
15
19
|
export interface HeatmapSourceRangeScreenRect {
|
|
16
20
|
height: number;
|
|
17
21
|
leftPosition: number;
|
|
@@ -50,12 +54,20 @@ export declare const resolveHeatmapSourceRange: (snapshot: Readonly<WaterfallSna
|
|
|
50
54
|
}) => HeatmapSourceRange | null;
|
|
51
55
|
export declare const resolveHeatmapSnapshotRangeData: (snapshot: Readonly<WaterfallSnapshot>, range: HeatmapSourceRange) => number[][];
|
|
52
56
|
export declare const resolveHeatmapSourceRangeScreenRect: (snapshot: Readonly<HeatmapViewportSnapshot>, range: HeatmapSourceRange) => HeatmapSourceRangeScreenRect | null;
|
|
57
|
+
export declare const resolveHeatmapContinuousSourceRangeScreenRect: (snapshot: Readonly<HeatmapViewportSnapshot>, range: Readonly<HeatmapContinuousSourceRange>) => HeatmapSourceRangeScreenRect | null;
|
|
58
|
+
export declare const resolveHeatmapProjectedContinuousSourceRange: (snapshot: Readonly<HeatmapViewportSnapshot>, bounds: {
|
|
59
|
+
endLeft: number;
|
|
60
|
+
endTop: number;
|
|
61
|
+
startLeft: number;
|
|
62
|
+
startTop: number;
|
|
63
|
+
}) => HeatmapContinuousSourceRange | null;
|
|
53
64
|
export declare const resolveHeatmapProjectedSourceRange: (snapshot: Readonly<HeatmapViewportSnapshot>, bounds: {
|
|
54
65
|
endLeft: number;
|
|
55
66
|
endTop: number;
|
|
56
67
|
startLeft: number;
|
|
57
68
|
startTop: number;
|
|
58
69
|
}) => HeatmapSourceRange | null;
|
|
70
|
+
export declare const quantizeHeatmapContinuousSourceRange: (snapshot: Readonly<HeatmapViewportSnapshot>, sourceRange: Readonly<HeatmapContinuousSourceRange>) => HeatmapSourceRange | null;
|
|
59
71
|
export declare const calculateHeatmapWheelRange: (snapshot: Readonly<WaterfallSnapshot>, wheel: number, coord: {
|
|
60
72
|
left: number;
|
|
61
73
|
top: number;
|
|
@@ -65,14 +77,18 @@ export declare const resolveHeatmapOverviewSourcePoint: (snapshot: Readonly<Heat
|
|
|
65
77
|
top: number;
|
|
66
78
|
}) => HeatmapOverviewSourcePoint;
|
|
67
79
|
export declare const resolveHeatmapOverviewViewportRect: (snapshot: Readonly<HeatmapViewportSnapshot>) => HeatmapOverviewViewportRect;
|
|
80
|
+
export declare const resolveHeatmapOverviewContinuousSourceRangeRect: (snapshot: Readonly<HeatmapViewportSnapshot>, range: Readonly<HeatmapContinuousSourceRange>) => HeatmapOverviewViewportRect;
|
|
68
81
|
export declare const resolveHeatmapOverviewSourceRangeRect: (snapshot: Readonly<HeatmapViewportSnapshot>, range: HeatmapSourceRange) => HeatmapOverviewViewportRect;
|
|
82
|
+
export declare const isHeatmapContinuousSourceRangeVisibleInViewport: (snapshot: Readonly<HeatmapViewportSnapshot>, range: Readonly<HeatmapContinuousSourceRange>) => boolean;
|
|
69
83
|
export declare const isHeatmapSourceRangeVisibleInViewport: (snapshot: Readonly<HeatmapViewportSnapshot>, range: HeatmapSourceRange) => boolean;
|
|
84
|
+
export declare const isHeatmapOverviewSourcePointInContinuousRange: (range: Readonly<HeatmapContinuousSourceRange>, point: HeatmapOverviewSourcePoint, tolerance?: HeatmapOverviewSourcePoint) => boolean;
|
|
70
85
|
export declare const isHeatmapOverviewSourcePointInRange: (range: HeatmapSourceRange, point: HeatmapOverviewSourcePoint, tolerance?: HeatmapOverviewSourcePoint) => boolean;
|
|
71
86
|
export declare const isHeatmapViewportFullRange: (snapshot: Readonly<HeatmapViewportSnapshot>) => boolean;
|
|
72
87
|
export declare const calculateHeatmapOverviewCenteredRange: (snapshot: Readonly<HeatmapViewportSnapshot>, point: {
|
|
73
88
|
left: number;
|
|
74
89
|
top: number;
|
|
75
90
|
}) => HeatmapViewportRange;
|
|
91
|
+
export declare const calculateHeatmapOverviewContinuousSourceRangeCenteredRange: (snapshot: Readonly<HeatmapViewportSnapshot>, range: Readonly<HeatmapContinuousSourceRange>) => HeatmapViewportRange;
|
|
76
92
|
export declare const calculateHeatmapOverviewSourceRangeCenteredRange: (snapshot: Readonly<HeatmapViewportSnapshot>, range: HeatmapSourceRange) => HeatmapViewportRange;
|
|
77
93
|
export declare const calculateHeatmapOverviewDragRange: (snapshot: Readonly<HeatmapViewportSnapshot>, point: {
|
|
78
94
|
left: number;
|