From a102d3aa0027d74df45924eb543745f57387e6a5 Mon Sep 17 00:00:00 2001 From: Peyton Lee Date: Wed, 20 Nov 2024 14:20:20 -0800 Subject: [PATCH 1/5] refactor: Added vector magnitude/components to tooltip --- src/Viewer.tsx | 46 +++++++++++++++++++++++++++++++----------- src/colorizer/types.ts | 7 +++++++ 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/Viewer.tsx b/src/Viewer.tsx index 9bd7075c7..80fbd773c 100644 --- a/src/Viewer.tsx +++ b/src/Viewer.tsx @@ -27,6 +27,8 @@ import { ReportWarningCallback, ScatterPlotConfig, TabType, + VECTOR_KEY_MOTION_DELTA, + VectorTooltipMode, ViewerConfig, } from "./colorizer/types"; import { AnalyticsEvent, triggerAnalyticsEvent } from "./colorizer/utils/analytics"; @@ -852,6 +854,37 @@ function Viewer(): ReactElement { } } + const hoverTooltipContent = [ +

Track ID: {lastHoveredId && dataset?.getTrackId(lastHoveredId)}

, +

+ {dataset?.getFeatureName(featureKey) || "Feature"}:{" "} + {hoveredFeatureValue} +

, + ]; + + if (config.vectorConfig.visible && lastHoveredId !== null && motionDeltas) { + const vectorKey = config.vectorConfig.key; + const vectorName = vectorKey === VECTOR_KEY_MOTION_DELTA ? "Avg. motion delta" : vectorKey; + const motionDelta = [motionDeltas[2 * lastHoveredId], motionDeltas[2 * lastHoveredId + 1]]; + if (config.vectorConfig.tooltipMode === VectorTooltipMode.MAGNITUDE) { + const magnitude = Math.sqrt(motionDelta[0] ** 2 + motionDelta[1] ** 2); + const angleDegrees = (Math.atan2(-motionDelta[1], motionDelta[0]) * (180 / Math.PI)) % 360; + + hoverTooltipContent.push( +

+ {vectorName}: {numberToStringDecimal(magnitude, 3)} px, {numberToStringDecimal(angleDegrees, 3)}° +

+ ); + } else { + hoverTooltipContent.push( +

+ {vectorName}: ({numberToStringDecimal(motionDelta[0], 3, false)},{" "} + {numberToStringDecimal(motionDelta[1], 3, false)}) px +

+ ); + } + } + return (
{notificationContextHolder}
@@ -1002,18 +1035,7 @@ function Viewer(): ReactElement {
- -

Track ID: {lastHoveredId && dataset?.getTrackId(lastHoveredId)}

-

- {dataset?.getFeatureName(featureKey) || "Feature"}:{" "} - {hoveredFeatureValue} -

- - } - disabled={!showHoveredId} - > + ({ timeIntervals: 5, color: new Color(0x000000), scaleFactor: 4, + tooltipMode: VectorTooltipMode.COMPONENTS, }); // CHANGING THESE VALUES CAN POTENTIALLY BREAK URLs. See `url_utils.parseDrawSettings` for parsing logic. From bbd9364356824d75404cd4192282b4a69d4cd6c8 Mon Sep 17 00:00:00 2001 From: Peyton Lee Date: Wed, 20 Nov 2024 14:21:04 -0800 Subject: [PATCH 2/5] feature: Added settings for vector tooltip mode --- src/colorizer/types.ts | 2 +- .../Tabs/Settings/VectorFieldSettings.tsx | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/colorizer/types.ts b/src/colorizer/types.ts index a314acce5..2a36e57e3 100644 --- a/src/colorizer/types.ts +++ b/src/colorizer/types.ts @@ -159,7 +159,7 @@ export const getDefaultVectorConfig = (): VectorConfig => ({ timeIntervals: 5, color: new Color(0x000000), scaleFactor: 4, - tooltipMode: VectorTooltipMode.COMPONENTS, + tooltipMode: VectorTooltipMode.MAGNITUDE, }); // CHANGING THESE VALUES CAN POTENTIALLY BREAK URLs. See `url_utils.parseDrawSettings` for parsing logic. diff --git a/src/components/Tabs/Settings/VectorFieldSettings.tsx b/src/components/Tabs/Settings/VectorFieldSettings.tsx index 927b57e24..1af519c1f 100644 --- a/src/components/Tabs/Settings/VectorFieldSettings.tsx +++ b/src/components/Tabs/Settings/VectorFieldSettings.tsx @@ -1,9 +1,9 @@ import { Color as AntdColor } from "@rc-component/color-picker"; -import { Card, Checkbox, ColorPicker } from "antd"; +import { Card, Checkbox, ColorPicker, Radio } from "antd"; import React, { ReactElement } from "react"; import { Color, ColorRepresentation } from "three"; -import { VECTOR_KEY_MOTION_DELTA, VectorConfig, ViewerConfig } from "../../../colorizer/types"; +import { VECTOR_KEY_MOTION_DELTA, VectorConfig, VectorTooltipMode, ViewerConfig } from "../../../colorizer/types"; import { DEFAULT_OUTLINE_COLOR_PRESETS } from "./constants"; import SelectionDropdown from "../../Dropdowns/SelectionDropdown"; @@ -106,6 +106,18 @@ export default function VectorFieldSettings(props: VectorFieldSettingsProps): Re > + +
+ updateVectorConfig({ tooltipMode: e.target.value })} + disabled={!props.config.vectorConfig.visible} + > + Magnitude and angle + XY components + +
+
); } From a7e12e30cd94c8faf21133207868c914649e8e13 Mon Sep 17 00:00:00 2001 From: Peyton Lee Date: Wed, 20 Nov 2024 14:21:11 -0800 Subject: [PATCH 3/5] feat: Adjusted settings spacing --- src/components/Tabs/SettingsTab.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/Tabs/SettingsTab.tsx b/src/components/Tabs/SettingsTab.tsx index ebf05303d..465534035 100644 --- a/src/components/Tabs/SettingsTab.tsx +++ b/src/components/Tabs/SettingsTab.tsx @@ -21,6 +21,7 @@ const NO_BACKDROP = { }; export const SETTINGS_INDENT_PX = 24; +const SETTINGS_GAP_PX = 8; export const MAX_SLIDER_WIDTH = "250px"; type SettingsTabProps = { @@ -46,7 +47,7 @@ export default function SettingsTab(props: SettingsTabProps): ReactElement { return ( - + - +
- + From 38ea05e6372e8137b57ab25083158af8ea28a2fe Mon Sep 17 00:00:00 2001 From: Peyton Lee Date: Wed, 20 Nov 2024 16:29:37 -0800 Subject: [PATCH 4/5] feat: Add handling for NaN vectors, integer formatting --- src/Viewer.tsx | 17 ++++++++++++----- .../Tabs/Settings/VectorFieldSettings.tsx | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Viewer.tsx b/src/Viewer.tsx index 80fbd773c..fd22b3e7a 100644 --- a/src/Viewer.tsx +++ b/src/Viewer.tsx @@ -854,6 +854,7 @@ function Viewer(): ReactElement { } } + // TODO: Move to a separate component? const hoverTooltipContent = [

Track ID: {lastHoveredId && dataset?.getTrackId(lastHoveredId)}

,

@@ -866,20 +867,26 @@ function Viewer(): ReactElement { const vectorKey = config.vectorConfig.key; const vectorName = vectorKey === VECTOR_KEY_MOTION_DELTA ? "Avg. motion delta" : vectorKey; const motionDelta = [motionDeltas[2 * lastHoveredId], motionDeltas[2 * lastHoveredId + 1]]; - if (config.vectorConfig.tooltipMode === VectorTooltipMode.MAGNITUDE) { + if (Number.isNaN(motionDelta[0]) || Number.isNaN(motionDelta[1])) { + // {vector}: + hoverTooltipContent.push(

{vectorName}:

); + } else if (config.vectorConfig.tooltipMode === VectorTooltipMode.MAGNITUDE) { const magnitude = Math.sqrt(motionDelta[0] ** 2 + motionDelta[1] ** 2); - const angleDegrees = (Math.atan2(-motionDelta[1], motionDelta[0]) * (180 / Math.PI)) % 360; + const angleDegrees = (360 + Math.atan2(-motionDelta[1], motionDelta[0]) * (180 / Math.PI)) % 360; + // {vector}: {magnitude} {unit}, {angle}° hoverTooltipContent.push(

- {vectorName}: {numberToStringDecimal(magnitude, 3)} px, {numberToStringDecimal(angleDegrees, 3)}° + {vectorName}: {numberToStringDecimal(magnitude, 3)} px, {numberToStringDecimal(angleDegrees, 1)}°

); } else { + // {vector}: ({x}, {y}) {unit} + const allowIntegerTruncation = Number.isInteger(motionDelta[0]) && Number.isInteger(motionDelta[1]); hoverTooltipContent.push(

- {vectorName}: ({numberToStringDecimal(motionDelta[0], 3, false)},{" "} - {numberToStringDecimal(motionDelta[1], 3, false)}) px + {vectorName}: ({numberToStringDecimal(motionDelta[0], 3, allowIntegerTruncation)},{" "} + {numberToStringDecimal(motionDelta[1], 3, allowIntegerTruncation)}) px

); } diff --git a/src/components/Tabs/Settings/VectorFieldSettings.tsx b/src/components/Tabs/Settings/VectorFieldSettings.tsx index 1af519c1f..8694575c9 100644 --- a/src/components/Tabs/Settings/VectorFieldSettings.tsx +++ b/src/components/Tabs/Settings/VectorFieldSettings.tsx @@ -106,7 +106,7 @@ export default function VectorFieldSettings(props: VectorFieldSettingsProps): Re >
- +
Date: Tue, 3 Dec 2024 14:30:23 -0800 Subject: [PATCH 5/5] refactor: Moved vector tooltip rendering to helper method --- src/Viewer.tsx | 58 +++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/Viewer.tsx b/src/Viewer.tsx index 34bfa8f3e..1b1bb3a2a 100644 --- a/src/Viewer.tsx +++ b/src/Viewer.tsx @@ -855,43 +855,43 @@ function Viewer(): ReactElement { } } - // TODO: Move to a separate component? - const hoverTooltipContent = [ -

Track ID: {lastHoveredId && dataset?.getTrackId(lastHoveredId)}

, -

- {dataset?.getFeatureName(featureKey) || "Feature"}:{" "} - {hoveredFeatureValue} -

, - ]; + const getVectorTooltipText = (): string | null => { + if (!config.vectorConfig.visible || lastHoveredId === null || !motionDeltas) { + return null; + } + const motionDelta = [motionDeltas[2 * lastHoveredId], motionDeltas[2 * lastHoveredId + 1]]; + + if (Number.isNaN(motionDelta[0]) || Number.isNaN(motionDelta[1])) { + return null; + } - if (config.vectorConfig.visible && lastHoveredId !== null && motionDeltas) { const vectorKey = config.vectorConfig.key; const vectorName = vectorKey === VECTOR_KEY_MOTION_DELTA ? "Avg. motion delta" : vectorKey; - const motionDelta = [motionDeltas[2 * lastHoveredId], motionDeltas[2 * lastHoveredId + 1]]; - if (Number.isNaN(motionDelta[0]) || Number.isNaN(motionDelta[1])) { - // {vector}: - hoverTooltipContent.push(

{vectorName}:

); - } else if (config.vectorConfig.tooltipMode === VectorTooltipMode.MAGNITUDE) { + if (config.vectorConfig.tooltipMode === VectorTooltipMode.MAGNITUDE) { const magnitude = Math.sqrt(motionDelta[0] ** 2 + motionDelta[1] ** 2); const angleDegrees = (360 + Math.atan2(-motionDelta[1], motionDelta[0]) * (180 / Math.PI)) % 360; - - // {vector}: {magnitude} {unit}, {angle}° - hoverTooltipContent.push( -

- {vectorName}: {numberToStringDecimal(magnitude, 3)} px, {numberToStringDecimal(angleDegrees, 1)}° -

- ); + const magnitudeText = numberToStringDecimal(magnitude, 3); + const angleText = numberToStringDecimal(angleDegrees, 1); + return `${vectorName}: ${magnitudeText} px, ${angleText}°`; } else { - // {vector}: ({x}, {y}) {unit} const allowIntegerTruncation = Number.isInteger(motionDelta[0]) && Number.isInteger(motionDelta[1]); - hoverTooltipContent.push( -

- {vectorName}: ({numberToStringDecimal(motionDelta[0], 3, allowIntegerTruncation)},{" "} - {numberToStringDecimal(motionDelta[1], 3, allowIntegerTruncation)}) px -

- ); + const x = numberToStringDecimal(motionDelta[0], 3, allowIntegerTruncation); + const y = numberToStringDecimal(motionDelta[1], 3, allowIntegerTruncation); + return `${vectorName}: (${x}, ${y}) px + `; } - } + }; + + // TODO: Move to a separate component? + const vectorTooltipText = getVectorTooltipText(); + const hoverTooltipContent = [ +

Track ID: {lastHoveredId && dataset?.getTrackId(lastHoveredId)}

, +

+ {dataset?.getFeatureName(featureKey) || "Feature"}:{" "} + {hoveredFeatureValue} +

, + vectorTooltipText ?

{vectorTooltipText}

: null, + ]; return (