123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- import {FlamegraphFrame} from '../flamegraphFrame';
- export type DirectionX = 'left' | 'right';
- export type DirectionY = 'up' | 'down';
- export type Direction = DirectionY | DirectionX;
- export function selectNearestFrame(frame: FlamegraphFrame, direction: Direction) {
- if (direction === 'up') {
- const parent = frame.parent;
-
- if (parent?.frame.isRoot) {
- return frame;
- }
-
- if (parent) {
- return parent;
- }
-
- const leftSibling = getSibling(frame, 'left');
- if (leftSibling) {
- return leftSibling;
- }
- return frame;
- }
- if (direction === 'down') {
-
- const child = frame.children?.[0];
- if (child) {
- return child;
- }
-
- const sibling = scanForNearestSibling(frame, 'right');
- if (sibling) {
- return sibling;
- }
- return frame;
- }
-
-
- const sibling = scanForNearestSibling(frame, direction);
-
-
- if (sibling) {
- const targetDepth = frame.depth;
- const nodeWithDepth = scanForNearestFrameWithDepth(sibling, targetDepth, direction);
- if (nodeWithDepth) {
- return nodeWithDepth;
- }
- }
- return frame;
- }
- function scanForNearestSibling(frame: FlamegraphFrame, directionX: DirectionX) {
- let node = frame;
- while (node) {
- const sibling = getSibling(node, directionX);
- if (sibling) {
- return sibling;
- }
- if (!node.parent) {
- break;
- }
- node = node.parent;
- }
- return frame;
- }
- function scanForNearestFrameWithDepth(
- frame: FlamegraphFrame,
- depth: number,
- directionX: DirectionX
- ) {
- let node = frame;
- let nextNode = node.children[directionX === 'right' ? 0 : node.children.length - 1];
- while (node && nextNode) {
- if (node.depth === depth) {
- return node;
- }
- nextNode = node.children[directionX === 'right' ? 0 : node.children.length - 1];
- if (nextNode) {
- node = nextNode;
- }
- }
- return node;
- }
- function getSibling(frame: FlamegraphFrame, directionX: DirectionX) {
- const parent = frame.parent;
- if (!parent) {
- return null;
- }
-
- const indexOfFrame = parent.children.indexOf(frame);
-
- if (indexOfFrame === -1) {
- throw Error('frame.parent.children does not include current frame');
- }
- if (directionX === 'right') {
- const hasRightSiblings = indexOfFrame < parent.children.length - 1;
- if (hasRightSiblings) {
- return parent.children[indexOfFrame + 1];
- }
- return null;
- }
- const hasLeftSiblings = indexOfFrame > 0;
- if (hasLeftSiblings) {
- return parent.children[indexOfFrame - 1];
- }
- return null;
- }
- const keyDirectionMap: Record<string, Direction> = {
- ArrowUp: 'up',
- ArrowDown: 'down',
- ArrowLeft: 'left',
- ArrowRight: 'right',
- Tab: 'down',
- 'Shift+Tab': 'up',
- } as const;
- export function handleFlamegraphKeyboardNavigation(
- evt: KeyboardEvent,
- currentFrame: FlamegraphFrame | undefined,
- inverted: boolean = false
- ) {
- if (!currentFrame) {
- return null;
- }
- const key = evt.shiftKey ? `Shift+${evt.key}` : evt.key;
- let direction = keyDirectionMap[key];
-
- if (!direction) {
- return null;
- }
- if (inverted && (direction === 'up' || direction === 'down')) {
- direction = direction === 'up' ? 'down' : 'up';
- }
- const nextSelection = selectNearestFrame(currentFrame, direction);
- if (nextSelection === currentFrame) {
- return null;
- }
- evt.preventDefault();
- return nextSelection;
- }
|