Files
grafana/packages/grafana-ui/src/components/NodeGraph/usePanning.ts

136 lines
4.6 KiB
TypeScript
Raw Normal View History

NodeGraph: Add node graph visualization (#29706) * Add GraphView component * Add service map panel * Add more metadata visuals * Add context menu on click * Add context menu for services * Fix service map in dashboard * Add field proxy in explore linkSupplier * Refactor the link creation * Remove test file * Fix scale change when view is panned * Fix node centering * Don't show context menu if no links * Fix service map containers * Add collapsible around the service map * Fix stats computation * Remove debug log * Fix time stats * Allow string timestamp * Make panning bounded * Add zooming by mouse wheel * Clean up the colors * Fix stats for single trace graph * Don't show debug config * Add more complex layout * Update layout with better fixing of the root nodes * Code cleanup * Change how we pass in link creation function and some more cleanup * Refactor the panel section into separate render methods * Make the edge hover more readable * Move stats computation to data source * Put edge labels to front * Simplify layout for better multi graph layout * Update for dark theme * Move function to utils * Visual improvements * Improve context menu detail * Allow custom details * Rename to NodeGraph * Remove unused dependencies * Use named color palette and add some fallbacks for missing data * Add test data scenario * Rename plugin * Switch scroll zoom direction to align with google maps * Do some perf optimisations and rise the node limit * Update alert styling * Rename function * Add tests * Add more tests * Change data frame column mapping to use column names * Fix test * Fix type errors * Don't show context menu without links * Add beta status to panel * Fix tests * Changed function to standard methods * Fix typing * Clean up yarn.lock * Add some UI improvements - better styling of the zoom buttons - disable buttons when max reached * Fix panel references after rename * Add panel icon
2021-01-19 16:34:43 +01:00
import { useEffect, useRef, RefObject, useState } from 'react';
import useMountedState from 'react-use/lib/useMountedState';
export interface State {
isPanning: boolean;
position: {
x: number;
y: number;
};
}
interface Options {
scale?: number;
bounds?: { top: number; bottom: number; right: number; left: number };
}
/**
* Based on https://github.com/streamich/react-use/blob/master/src/useSlider.ts
* Returns position x/y coordinates which can be directly used in transform: translate().
* @param scale Can be used when we want to scale the movement if we are moving a scaled element. We need to do it
* here because we don't wont to change the pos when scale changes.
* @param bounds If set the panning cannot go outside of those bounds.
*/
export function usePanning<T extends Element>(
{ scale = 1, bounds }: Options = { scale: 1 }
): { state: State; ref: RefObject<T> } {
const isMounted = useMountedState();
const isPanning = useRef(false);
const frame = useRef(0);
const panRef = useRef<T>(null);
// We need to keep some state so we can compute the position diff and add that to the previous position.
const startMousePosition = useRef({ x: 0, y: 0 });
const prevPosition = useRef({ x: 0, y: 0 });
// We cannot use the state as that would rerun the effect on each state change which we don't want so we have to keep
// separate variable for the state that won't cause useEffect eval
const currentPosition = useRef({ x: 0, y: 0 });
const [state, setState] = useState<State>({
isPanning: false,
position: { x: 0, y: 0 },
});
useEffect(() => {
const startPanning = (event: Event) => {
if (!isPanning.current && isMounted()) {
isPanning.current = true;
// Snapshot the current position of both mouse pointer and the element
startMousePosition.current = getEventXY(event);
prevPosition.current = { ...currentPosition.current };
setState((state) => ({ ...state, isPanning: true }));
NodeGraph: Add node graph visualization (#29706) * Add GraphView component * Add service map panel * Add more metadata visuals * Add context menu on click * Add context menu for services * Fix service map in dashboard * Add field proxy in explore linkSupplier * Refactor the link creation * Remove test file * Fix scale change when view is panned * Fix node centering * Don't show context menu if no links * Fix service map containers * Add collapsible around the service map * Fix stats computation * Remove debug log * Fix time stats * Allow string timestamp * Make panning bounded * Add zooming by mouse wheel * Clean up the colors * Fix stats for single trace graph * Don't show debug config * Add more complex layout * Update layout with better fixing of the root nodes * Code cleanup * Change how we pass in link creation function and some more cleanup * Refactor the panel section into separate render methods * Make the edge hover more readable * Move stats computation to data source * Put edge labels to front * Simplify layout for better multi graph layout * Update for dark theme * Move function to utils * Visual improvements * Improve context menu detail * Allow custom details * Rename to NodeGraph * Remove unused dependencies * Use named color palette and add some fallbacks for missing data * Add test data scenario * Rename plugin * Switch scroll zoom direction to align with google maps * Do some perf optimisations and rise the node limit * Update alert styling * Rename function * Add tests * Add more tests * Change data frame column mapping to use column names * Fix test * Fix type errors * Don't show context menu without links * Add beta status to panel * Fix tests * Changed function to standard methods * Fix typing * Clean up yarn.lock * Add some UI improvements - better styling of the zoom buttons - disable buttons when max reached * Fix panel references after rename * Add panel icon
2021-01-19 16:34:43 +01:00
bindEvents();
}
};
const stopPanning = () => {
if (isPanning.current && isMounted()) {
isPanning.current = false;
setState((state) => ({ ...state, isPanning: false }));
NodeGraph: Add node graph visualization (#29706) * Add GraphView component * Add service map panel * Add more metadata visuals * Add context menu on click * Add context menu for services * Fix service map in dashboard * Add field proxy in explore linkSupplier * Refactor the link creation * Remove test file * Fix scale change when view is panned * Fix node centering * Don't show context menu if no links * Fix service map containers * Add collapsible around the service map * Fix stats computation * Remove debug log * Fix time stats * Allow string timestamp * Make panning bounded * Add zooming by mouse wheel * Clean up the colors * Fix stats for single trace graph * Don't show debug config * Add more complex layout * Update layout with better fixing of the root nodes * Code cleanup * Change how we pass in link creation function and some more cleanup * Refactor the panel section into separate render methods * Make the edge hover more readable * Move stats computation to data source * Put edge labels to front * Simplify layout for better multi graph layout * Update for dark theme * Move function to utils * Visual improvements * Improve context menu detail * Allow custom details * Rename to NodeGraph * Remove unused dependencies * Use named color palette and add some fallbacks for missing data * Add test data scenario * Rename plugin * Switch scroll zoom direction to align with google maps * Do some perf optimisations and rise the node limit * Update alert styling * Rename function * Add tests * Add more tests * Change data frame column mapping to use column names * Fix test * Fix type errors * Don't show context menu without links * Add beta status to panel * Fix tests * Changed function to standard methods * Fix typing * Clean up yarn.lock * Add some UI improvements - better styling of the zoom buttons - disable buttons when max reached * Fix panel references after rename * Add panel icon
2021-01-19 16:34:43 +01:00
unbindEvents();
}
};
const onPanStart = (event: Event) => {
startPanning(event);
onPan(event);
};
const bindEvents = () => {
document.addEventListener('mousemove', onPan);
document.addEventListener('mouseup', stopPanning);
document.addEventListener('touchmove', onPan);
document.addEventListener('touchend', stopPanning);
};
const unbindEvents = () => {
document.removeEventListener('mousemove', onPan);
document.removeEventListener('mouseup', stopPanning);
document.removeEventListener('touchmove', onPan);
document.removeEventListener('touchend', stopPanning);
};
const onPan = (event: Event) => {
cancelAnimationFrame(frame.current);
const pos = getEventXY(event);
frame.current = requestAnimationFrame(() => {
if (isMounted() && panRef.current) {
// Get the diff by which we moved the mouse.
let xDiff = pos.x - startMousePosition.current.x;
let yDiff = pos.y - startMousePosition.current.y;
// Add the diff to the position from the moment we started panning.
currentPosition.current = {
x: inBounds(prevPosition.current.x + xDiff / scale, bounds?.left, bounds?.right),
y: inBounds(prevPosition.current.y + yDiff / scale, bounds?.top, bounds?.bottom),
};
setState((state) => ({
NodeGraph: Add node graph visualization (#29706) * Add GraphView component * Add service map panel * Add more metadata visuals * Add context menu on click * Add context menu for services * Fix service map in dashboard * Add field proxy in explore linkSupplier * Refactor the link creation * Remove test file * Fix scale change when view is panned * Fix node centering * Don't show context menu if no links * Fix service map containers * Add collapsible around the service map * Fix stats computation * Remove debug log * Fix time stats * Allow string timestamp * Make panning bounded * Add zooming by mouse wheel * Clean up the colors * Fix stats for single trace graph * Don't show debug config * Add more complex layout * Update layout with better fixing of the root nodes * Code cleanup * Change how we pass in link creation function and some more cleanup * Refactor the panel section into separate render methods * Make the edge hover more readable * Move stats computation to data source * Put edge labels to front * Simplify layout for better multi graph layout * Update for dark theme * Move function to utils * Visual improvements * Improve context menu detail * Allow custom details * Rename to NodeGraph * Remove unused dependencies * Use named color palette and add some fallbacks for missing data * Add test data scenario * Rename plugin * Switch scroll zoom direction to align with google maps * Do some perf optimisations and rise the node limit * Update alert styling * Rename function * Add tests * Add more tests * Change data frame column mapping to use column names * Fix test * Fix type errors * Don't show context menu without links * Add beta status to panel * Fix tests * Changed function to standard methods * Fix typing * Clean up yarn.lock * Add some UI improvements - better styling of the zoom buttons - disable buttons when max reached * Fix panel references after rename * Add panel icon
2021-01-19 16:34:43 +01:00
...state,
position: {
...currentPosition.current,
},
}));
}
});
};
if (panRef.current) {
panRef.current.addEventListener('mousedown', onPanStart);
panRef.current.addEventListener('touchstart', onPanStart);
}
return () => {
if (panRef.current) {
panRef.current.removeEventListener('mousedown', onPanStart);
panRef.current.removeEventListener('touchstart', onPanStart);
}
};
}, [scale, bounds?.left, bounds?.right, bounds?.top, bounds?.bottom]);
return { state, ref: panRef };
}
function inBounds(value: number, min: number | undefined, max: number | undefined) {
return Math.min(Math.max(value, min ?? -Infinity), max ?? Infinity);
}
function getEventXY(event: Event): { x: number; y: number } {
if ((event as any).changedTouches) {
const e = event as TouchEvent;
return { x: e.changedTouches[0].clientX, y: e.changedTouches[0].clientY };
} else {
const e = event as MouseEvent;
return { x: e.clientX, y: e.clientY };
}
}