Dynamic scaling of visualizer and resizable window

Summary: Fixes https://fb.workplace.com/groups/443457641253219/permalink/480446154221034/

Reviewed By: mweststrate

Differential Revision: D42095625

fbshipit-source-id: 364577141f2819dd22b0b499b11770d0bb88b1f5
This commit is contained in:
Luke De Feo
2022-12-16 03:47:58 -08:00
committed by Facebook GitHub Bot
parent e65c190136
commit 989797a225
2 changed files with 56 additions and 20 deletions

View File

@@ -19,16 +19,18 @@ import {UIDebuggerMenuItem} from './util/UIDebuggerMenuItem';
export const Visualization2D: React.FC< export const Visualization2D: React.FC<
{ {
rootId: Id; rootId: Id;
width: number;
nodes: Map<Id, UINode>; nodes: Map<Id, UINode>;
selectedNode?: Id; selectedNode?: Id;
onSelectNode: (id?: Id) => void; onSelectNode: (id?: Id) => void;
modifierPressed: boolean; modifierPressed: boolean;
} & React.HTMLAttributes<HTMLDivElement> } & React.HTMLAttributes<HTMLDivElement>
> = ({rootId, nodes, selectedNode, onSelectNode, modifierPressed}) => { > = ({rootId, width, nodes, selectedNode, onSelectNode, modifierPressed}) => {
const rootNodeRef = useRef<HTMLDivElement>(); const rootNodeRef = useRef<HTMLDivElement>();
const instance = usePlugin(plugin); const instance = usePlugin(plugin);
const snapshot = useValue(instance.snapshot); const snapshot = useValue(instance.snapshot);
const snapshotNode = snapshot && nodes.get(snapshot.nodeId);
const focusedNodeId = useValue(instance.uiState.focusedNode); const focusedNodeId = useValue(instance.uiState.focusedNode);
const focusState = useMemo(() => { const focusState = useMemo(() => {
@@ -40,7 +42,12 @@ export const Visualization2D: React.FC<
const mouseListener = throttle((ev: MouseEvent) => { const mouseListener = throttle((ev: MouseEvent) => {
const domRect = rootNodeRef.current?.getBoundingClientRect(); const domRect = rootNodeRef.current?.getBoundingClientRect();
if (!focusState || !domRect || instance.uiState.isContextMenuOpen.get()) { if (
!focusState ||
!domRect ||
instance.uiState.isContextMenuOpen.get() ||
!snapshotNode
) {
return; return;
} }
const rawMouse = {x: ev.clientX, y: ev.clientY}; const rawMouse = {x: ev.clientX, y: ev.clientY};
@@ -51,6 +58,8 @@ export const Visualization2D: React.FC<
//make the mouse coord relative to the dom rect of the visualizer //make the mouse coord relative to the dom rect of the visualizer
const pxScaleFactor = calcPxScaleFactor(snapshotNode.bounds, width);
const offsetMouse = offsetCoordinate(rawMouse, domRect); const offsetMouse = offsetCoordinate(rawMouse, domRect);
const scaledMouse = { const scaledMouse = {
x: offsetMouse.x * pxScaleFactor, x: offsetMouse.x * pxScaleFactor,
@@ -78,22 +87,27 @@ export const Visualization2D: React.FC<
focusState, focusState,
nodes, nodes,
instance.uiState.isContextMenuOpen, instance.uiState.isContextMenuOpen,
width,
snapshotNode,
]); ]);
if (!focusState) { if (!focusState || !snapshotNode) {
return null; return null;
} }
const snapshotNode = snapshot && nodes.get(snapshot.nodeId); const pxScaleFactor = calcPxScaleFactor(snapshotNode.bounds, width);
return ( return (
<ContextMenu nodes={nodes}> <ContextMenu nodes={nodes}>
<div <div
//this div is to ensure that the size of the visualiser doesnt change when focusings on a subtree //this div is to ensure that the size of the visualiser doesnt change when focusings on a subtree
style={{ style={
{
[pxScaleFactorCssVar]: pxScaleFactor,
width: toPx(focusState.actualRoot.bounds.width), width: toPx(focusState.actualRoot.bounds.width),
height: toPx(focusState.actualRoot.bounds.height), height: toPx(focusState.actualRoot.bounds.height),
}}> } as React.CSSProperties
}>
<div <div
ref={rootNodeRef as any} ref={rootNodeRef as any}
onMouseLeave={(e) => { onMouseLeave={(e) => {
@@ -342,6 +356,8 @@ const NodeBorder = styled.div<{tags: Tag[]; hovered: boolean}>((props) => ({
const longHoverDelay = 200; const longHoverDelay = 200;
const outerBorderWidth = '10px'; const outerBorderWidth = '10px';
const outerBorderOffset = `-${outerBorderWidth}`; const outerBorderOffset = `-${outerBorderWidth}`;
const pxScaleFactorCssVar = '--pxScaleFactor';
const MouseThrottle = 32;
//this is the thick black border around the whole vizualization, the border goes around the content //this is the thick black border around the whole vizualization, the border goes around the content
//hence the top,left,right,botton being negative to increase its size //hence the top,left,right,botton being negative to increase its size
@@ -358,11 +374,8 @@ const OuterBorder = styled.div({
borderRadius: '10px', borderRadius: '10px',
}); });
const pxScaleFactor = 2;
const MouseThrottle = 32;
function toPx(n: number) { function toPx(n: number) {
return `${n / pxScaleFactor}px`; return `calc(${n}px / var(${pxScaleFactorCssVar})`;
} }
function toNestedNode( function toNestedNode(
@@ -506,3 +519,7 @@ function offsetCoordinate(
y: coordinate.y - offset.y, y: coordinate.y - offset.y,
}; };
} }
function calcPxScaleFactor(snapshotBounds: Bounds, availableWidth: number) {
return snapshotBounds.width / availableWidth;
}

View File

@@ -9,7 +9,13 @@
import React, {useState} from 'react'; import React, {useState} from 'react';
import {plugin} from '../index'; import {plugin} from '../index';
import {DetailSidebar, Layout, usePlugin, useValue} from 'flipper-plugin'; import {
DetailSidebar,
Layout,
usePlugin,
useValue,
_Sidebar as ResizablePanel,
} from 'flipper-plugin';
import {useHotkeys} from 'react-hotkeys-hook'; import {useHotkeys} from 'react-hotkeys-hook';
import {Id, Metadata, MetadataId, UINode} from '../types'; import {Id, Metadata, MetadataId, UINode} from '../types';
import {PerfStats} from './PerfStats'; import {PerfStats} from './PerfStats';
@@ -30,6 +36,8 @@ export function Component() {
const [showPerfStats, setShowPerfStats] = useState(false); const [showPerfStats, setShowPerfStats] = useState(false);
const [selectedNode, setSelectedNode] = useState<Id | undefined>(undefined); const [selectedNode, setSelectedNode] = useState<Id | undefined>(undefined);
const [visualiserWidth, setVisualiserWidth] = useState(500);
useHotkeys('ctrl+i', () => setShowPerfStats((show) => !show)); useHotkeys('ctrl+i', () => setShowPerfStats((show) => !show));
const {ctrlPressed} = useKeyboardModifiers(); const {ctrlPressed} = useKeyboardModifiers();
@@ -53,13 +61,24 @@ export function Component() {
</Layout.ScrollContainer> </Layout.ScrollContainer>
</Layout.Container> </Layout.Container>
<ResizablePanel
position="right"
minWidth={200}
width={visualiserWidth}
maxWidth={800}
onResize={(width) => {
setVisualiserWidth(width);
}}
gutter>
<Visualization2D <Visualization2D
rootId={rootId} rootId={rootId}
width={visualiserWidth}
nodes={nodes} nodes={nodes}
selectedNode={selectedNode} selectedNode={selectedNode}
onSelectNode={setSelectedNode} onSelectNode={setSelectedNode}
modifierPressed={ctrlPressed} modifierPressed={ctrlPressed}
/> />
</ResizablePanel>
<DetailSidebar width={350}> <DetailSidebar width={350}>
<Inspector <Inspector
metadata={metadata} metadata={metadata}