@lobehub/ui
Version:
Lobe UI is an open-source UI component library for building AIGC web apps
97 lines (96 loc) • 3.84 kB
JavaScript
const DEFAULT_RUBBER_BAND_FACTOR = .15;
const WHEEL_ZOOM_SENSITIVITY = .002;
const normalizeRotation = (degrees) => (degrees % 360 + 360) % 360;
const effectiveSize = (natural, rotate) => rotate === 90 || rotate === 270 ? {
height: natural.width,
width: natural.height
} : natural;
const computeFit = (natural, viewport, rotate, fillViewport = false) => {
const effective = effectiveSize(natural, rotate);
const availableWidth = Math.max(viewport.width - 48, 0);
const availableHeight = Math.max(viewport.height - 48, 0);
const containScale = Math.min(availableWidth / effective.width, availableHeight / effective.height, ...fillViewport ? [] : [1]);
const width = effective.width * containScale;
const height = effective.height * containScale;
return {
height,
width,
x: (viewport.width - width) / 2,
y: (viewport.height - height) / 2
};
};
const unrotatedRect = (fit, rotate) => {
if (rotate !== 90 && rotate !== 270) return fit;
const centerX = fit.x + fit.width / 2;
const centerY = fit.y + fit.height / 2;
return {
height: fit.width,
width: fit.height,
x: centerX - fit.height / 2,
y: centerY - fit.width / 2
};
};
const anchoredZoom = (current, targetScale, anchor, fitRect) => {
const centerX = fitRect.x + fitRect.width / 2;
const centerY = fitRect.y + fitRect.height / 2;
const ratio = targetScale / current.scale;
return {
scale: targetScale,
x: anchor.x - centerX - ratio * (anchor.x - centerX - current.x),
y: anchor.y - centerY - ratio * (anchor.y - centerY - current.y)
};
};
const panBounds = (state, fitRect, viewport) => {
const centerX = fitRect.x + fitRect.width / 2;
const centerY = fitRect.y + fitRect.height / 2;
const scaledWidth = fitRect.width * state.scale;
const scaledHeight = fitRect.height * state.scale;
const axis = (center, scaledSize, viewportSize) => {
if (scaledSize - viewportSize <= 0) return {
max: 0,
min: 0
};
return {
max: scaledSize / 2 - center,
min: viewportSize - center - scaledSize / 2
};
};
return {
x: axis(centerX, scaledWidth, viewport.width),
y: axis(centerY, scaledHeight, viewport.height)
};
};
const clampPan = (state, fitRect, viewport) => {
const bounds = panBounds(state, fitRect, viewport);
return {
x: Math.min(Math.max(state.x, bounds.x.min), bounds.x.max),
y: Math.min(Math.max(state.y, bounds.y.min), bounds.y.max)
};
};
const rubberBand = (value, min, max, factor = DEFAULT_RUBBER_BAND_FACTOR) => {
if (value < min) return min - (min - value) * factor;
if (value > max) return max + (value - max) * factor;
return value;
};
const clampScale = (scale, maxScale = 8) => Math.min(Math.max(scale, 1), maxScale);
const wheelZoomFactor = (deltaY) => Math.exp(-deltaY * WHEEL_ZOOM_SENSITIVITY);
const normalizeWheelDelta = (deltaY, deltaMode = 0, viewportHeight = 0) => {
if (deltaMode === 1) return deltaY * 16;
if (deltaMode === 2) return deltaY * (viewportHeight || 640);
return deltaY;
};
const naturalScale = (natural, fitRect, rotate) => effectiveSize(natural, rotate).width / fitRect.width;
const resolveInitialScale = (policy, natural, fitRect, rotate, threshold = 2) => {
if (policy === "fit") return 1;
const target = naturalScale(natural, fitRect, rotate);
if (!Number.isFinite(target) || target <= 0) return 1;
if (policy === "auto" && target > threshold) return 1;
return Math.max(1, target);
};
const doubleClickTarget = (currentScale, natural, fitRect, rotate) => {
if (currentScale > 1) return 1;
return Math.max(2, naturalScale(natural, fitRect, rotate));
};
//#endregion
export { DEFAULT_RUBBER_BAND_FACTOR, WHEEL_ZOOM_SENSITIVITY, anchoredZoom, clampPan, clampScale, computeFit, doubleClickTarget, naturalScale, normalizeRotation, normalizeWheelDelta, panBounds, resolveInitialScale, rubberBand, unrotatedRect, wheelZoomFactor };
//# sourceMappingURL=geometry.mjs.map