@kinvolk/headlamp-plugin
Version:
The needed infrastructure for building Headlamp plugins.
64 lines (63 loc) • 2.93 kB
JavaScript
/*
* Copyright 2025 The Kubernetes Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { getNodesBounds, getViewportForBounds, useReactFlow, useStore } from '@xyflow/react';
import { useCallback, useMemo } from 'react';
import { useLocalStorageState } from '../globalSearch/useLocalStorageState';
import { maxZoom, minZoom, viewportPaddingPx } from './graphConstants';
/** Helper hook to deal with viewport zooming */
export const useGraphViewport = () => {
const [zoomMode, setZoomMode] = useLocalStorageState('map-zoom-mode', '100%');
const reactFlowWidth = useStore(it => it.width);
const reactFlowHeight = useStore(it => it.height);
const aspectRatio = useStore(it => it.width / it.height);
const flow = useReactFlow();
const updateViewport = useCallback(({ nodes = flow.getNodes(), mode = zoomMode, }) => {
if (mode !== zoomMode) {
setZoomMode(() => mode);
}
const bounds = getNodesBounds(nodes);
if (mode === 'fit') {
const viewport = getViewportForBounds({
x: bounds.x - viewportPaddingPx,
y: bounds.y - viewportPaddingPx,
width: bounds.width + viewportPaddingPx * 2,
height: bounds.height + viewportPaddingPx * 2,
}, reactFlowWidth, reactFlowHeight, minZoom, maxZoom, 0);
flow.setViewport(viewport);
return;
}
if (mode === '100%') {
const topLeftOrigin = { x: viewportPaddingPx, y: viewportPaddingPx };
const centerOrigin = {
x: reactFlowWidth / 2 - bounds.width / 2,
y: reactFlowHeight / 2 - bounds.height / 2,
};
const xFits = bounds.width + viewportPaddingPx * 2 <= reactFlowWidth;
const yFits = bounds.height + viewportPaddingPx * 2 <= reactFlowHeight;
const defaultZoomViewport = {
x: xFits ? centerOrigin.x : topLeftOrigin.x,
y: yFits ? centerOrigin.y : topLeftOrigin.y,
zoom: 1,
};
flow.setViewport(defaultZoomViewport);
return;
}
console.error('Unknown zoom mode', mode);
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[flow, zoomMode, reactFlowWidth, reactFlowHeight]);
return useMemo(() => ({ updateViewport, aspectRatio }), [updateViewport, aspectRatio]);
};