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<
{
rootId: Id;
width: number;
nodes: Map<Id, UINode>;
selectedNode?: Id;
onSelectNode: (id?: Id) => void;
modifierPressed: boolean;
} & React.HTMLAttributes<HTMLDivElement>
> = ({rootId, nodes, selectedNode, onSelectNode, modifierPressed}) => {
> = ({rootId, width, nodes, selectedNode, onSelectNode, modifierPressed}) => {
const rootNodeRef = useRef<HTMLDivElement>();
const instance = usePlugin(plugin);
const snapshot = useValue(instance.snapshot);
const snapshotNode = snapshot && nodes.get(snapshot.nodeId);
const focusedNodeId = useValue(instance.uiState.focusedNode);
const focusState = useMemo(() => {
@@ -40,7 +42,12 @@ export const Visualization2D: React.FC<
const mouseListener = throttle((ev: MouseEvent) => {
const domRect = rootNodeRef.current?.getBoundingClientRect();
if (!focusState || !domRect || instance.uiState.isContextMenuOpen.get()) {
if (
!focusState ||
!domRect ||
instance.uiState.isContextMenuOpen.get() ||
!snapshotNode
) {
return;
}
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
const pxScaleFactor = calcPxScaleFactor(snapshotNode.bounds, width);
const offsetMouse = offsetCoordinate(rawMouse, domRect);
const scaledMouse = {
x: offsetMouse.x * pxScaleFactor,
@@ -78,22 +87,27 @@ export const Visualization2D: React.FC<
focusState,
nodes,
instance.uiState.isContextMenuOpen,
width,
snapshotNode,
]);
if (!focusState) {
if (!focusState || !snapshotNode) {
return null;
}
const snapshotNode = snapshot && nodes.get(snapshot.nodeId);
const pxScaleFactor = calcPxScaleFactor(snapshotNode.bounds, width);
return (
<ContextMenu nodes={nodes}>
<div
//this div is to ensure that the size of the visualiser doesnt change when focusings on a subtree
style={{
width: toPx(focusState.actualRoot.bounds.width),
height: toPx(focusState.actualRoot.bounds.height),
}}>
style={
{
[pxScaleFactorCssVar]: pxScaleFactor,
width: toPx(focusState.actualRoot.bounds.width),
height: toPx(focusState.actualRoot.bounds.height),
} as React.CSSProperties
}>
<div
ref={rootNodeRef as any}
onMouseLeave={(e) => {
@@ -342,6 +356,8 @@ const NodeBorder = styled.div<{tags: Tag[]; hovered: boolean}>((props) => ({
const longHoverDelay = 200;
const outerBorderWidth = '10px';
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
//hence the top,left,right,botton being negative to increase its size
@@ -358,11 +374,8 @@ const OuterBorder = styled.div({
borderRadius: '10px',
});
const pxScaleFactor = 2;
const MouseThrottle = 32;
function toPx(n: number) {
return `${n / pxScaleFactor}px`;
return `calc(${n}px / var(${pxScaleFactorCssVar})`;
}
function toNestedNode(
@@ -506,3 +519,7 @@ function offsetCoordinate(
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 {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 {Id, Metadata, MetadataId, UINode} from '../types';
import {PerfStats} from './PerfStats';
@@ -30,6 +36,8 @@ export function Component() {
const [showPerfStats, setShowPerfStats] = useState(false);
const [selectedNode, setSelectedNode] = useState<Id | undefined>(undefined);
const [visualiserWidth, setVisualiserWidth] = useState(500);
useHotkeys('ctrl+i', () => setShowPerfStats((show) => !show));
const {ctrlPressed} = useKeyboardModifiers();
@@ -53,13 +61,24 @@ export function Component() {
</Layout.ScrollContainer>
</Layout.Container>
<Visualization2D
rootId={rootId}
nodes={nodes}
selectedNode={selectedNode}
onSelectNode={setSelectedNode}
modifierPressed={ctrlPressed}
/>
<ResizablePanel
position="right"
minWidth={200}
width={visualiserWidth}
maxWidth={800}
onResize={(width) => {
setVisualiserWidth(width);
}}
gutter>
<Visualization2D
rootId={rootId}
width={visualiserWidth}
nodes={nodes}
selectedNode={selectedNode}
onSelectNode={setSelectedNode}
modifierPressed={ctrlPressed}
/>
</ResizablePanel>
<DetailSidebar width={350}>
<Inspector
metadata={metadata}