This commit is contained in:
2026-09-24 16:25:22 +08:00
commit 7428184f01
1198 changed files with 314515 additions and 0 deletions
@@ -0,0 +1,333 @@
export type xSIZE = {
width : number,
height : number,
top : number,
left : number
}
export type xImageInfo = {
width : number,
height : number,
top : number,
left : number,
src : string,
}
export type xSIZEiMage = {
width : number,
height : number,
top : number,
left : number,
scale : number
}
export type xPOINT = {
x : number,
y : number
}
export type xCalculatePinchZoomOpts = {
initialPoints : xPOINT[],
currentPoints : xPOINT[],
originWidth : number, // 原始图片宽度
originHeight : number, // 原始图片高度
cropWidth : number, // 裁剪框宽度
cropHeight : number,
initialScale : number,
width : number,
height : number,
top : number,
left : number,
scale : number
}
export function alignImageToFrame(imageParams : xSIZEiMage, frameParams : xSIZE) : xSIZE {
const {
width: imgWidth,
height: imgHeight,
top: imgTop,
left: imgLeft
} = imageParams;
const {
width: frameWidth,
height: frameHeight,
top: frameTop,
left: frameLeft
} = frameParams;
// 图片是否完全覆盖框(修改为严格大于)
const isWidthCovered = imgWidth > frameWidth;
const isHeightCovered = imgHeight > frameHeight;
// 当图片宽高都大于框时,保持自由拖动
// 同时图片确保覆盖住裁剪框.
if (isWidthCovered
&& isHeightCovered
&& imgLeft < frameLeft
&& imgTop < frameTop
&& (imgLeft + imgWidth) > (frameLeft + frameWidth)
&& (imgTop + imgHeight) > (frameTop + frameHeight)
) {
return {
width: imgWidth,
height: imgHeight,
top: imgTop,
left: imgLeft
};
}
let newTop = imgTop;
let newLeft = imgLeft;
// 图片的左侧是不是小于框的右侧
let isMinLeft = imgLeft < frameLeft
let isMaxRight = imgLeft + imgWidth > frameLeft + frameWidth
let isMinTop = imgTop < frameTop
let isMaxTop = imgTop + imgHeight > frameTop + frameHeight
// 水平对齐逻辑(反向对齐),如果越过左边了要左对齐,
if (imgLeft < frameLeft && !isMaxRight) {
// 图片左侧越界,靠右对齐
newLeft = frameLeft + frameWidth - imgWidth;
} else if (imgLeft + imgWidth > frameLeft + frameWidth && !isMinLeft) {
// 图片右侧越界,靠左对齐
newLeft = frameLeft;
}
// 垂直对齐逻辑(反向对齐)
if (imgTop < frameTop && !isMaxTop) {
// 图片顶部越界,靠底对齐
newTop = frameTop + frameHeight - imgHeight;
} else if (imgTop + imgHeight > frameTop + frameHeight && !isMinTop) {
// 图片底部越界,靠顶对齐
newTop = frameTop;
}
return {
width: imgWidth,
height: imgHeight,
top: newTop,
left: newLeft
};
}
function scaleImageToFitFrame(imageParams : xImageInfo, frameParams : xSIZE) : xSIZEiMage {
// 解构图片和裁剪框的参数
const {
width: imgWidth,
height: imgHeight,
top: imgTop = 0,
left: imgLeft = 0
} = imageParams;
const {
width: frameWidth,
height: frameHeight,
top: frameTop = 0,
left: frameLeft = 0
} = frameParams;
// 计算宽高比
const imgRatio = imgWidth / imgHeight;
const frameRatio = frameWidth / frameHeight;
let newWidth = 0
let newHeight = 0
let scale = 1
// 确保填充整个裁剪框
if (imgRatio > frameRatio) {
// 以高度为基准缩放
newHeight = frameHeight;
newWidth = newHeight * imgRatio;
scale = newHeight / imgHeight;
// 如果宽度不够,再次调整
if (newWidth < frameWidth) {
newWidth = frameWidth;
newHeight = newWidth / imgRatio;
scale = newWidth / imgWidth;
}
} else {
// 以宽度为基准缩放
newWidth = frameWidth;
newHeight = newWidth / imgRatio;
scale = newWidth / imgWidth;
// 如果高度不够,再次调整
if (newHeight < frameHeight) {
newHeight = frameHeight;
newWidth = newHeight * imgRatio;
scale = newHeight / imgHeight;
}
}
// 计算最终定位(考虑裁剪框和图片的初始偏移)
const top = frameTop + (frameHeight - newHeight) / 2 - imgTop * scale;
const left = frameLeft + (frameWidth - newWidth) / 2 - imgLeft * scale;
return {
width: newWidth, // 新的图片宽度
height: newHeight, // 新的图片高度
top, // 垂直方向偏移
left, // 水平方向偏移
scale // 缩放比例
} as xSIZEiMage;
}
export function translateScalePosition(orimg : xImageInfo, img : xSIZEiMage, mask : xSIZE, parent : xSIZE) {
let scaleinfo = scaleImageToFitFrame(orimg, mask)
img.width = scaleinfo.width
img.height = scaleinfo.height
img.top = scaleinfo.top
img.left = scaleinfo.left
img.scale = scaleinfo.scale
}
export function calculatePinchZoom(options : xCalculatePinchZoomOpts) : xSIZEiMage {
const {
initialPoints, // 初始双指坐标 [{x, y}, {x, y}]
currentPoints, // 当前双指坐标 [{x, y}, {x, y}]
originWidth, // 原始图片宽度
originHeight, // 原始图片高度
cropWidth, // 裁剪框宽度
cropHeight, // 裁剪框高度
width, // 当前图片宽度
height, // 当前图片高度
top, // 图片当前顶部位置
left, // 图片当前左侧位置
scale, // 当前缩放比例
initialScale // 初始缩放比例
} = options;
// 阻尼系数,0-1之间,越大越快,越小缩放越慢.
const DAMPING_FACTOR = 0.45;
// 计算初始和当前双指距离
const getDistance = (points : xPOINT[]) : number => {
const p1 = points[0];
const p2 = points[1];
return Math.sqrt(
Math.pow(p2.x - p1.x, 2) +
Math.pow(p2.y - p1.y, 2)
);
};
// 计算双指中心点
const getCenter = (points : xPOINT[]) : xPOINT => {
const p1 = points[0];
const p2 = points[1];
return {
x: (p1.x + p2.x) / 2,
y: (p1.y + p2.y) / 2
} as xPOINT;
};
const initialDistance = getDistance(initialPoints);
const currentDistance = getDistance(currentPoints);
if (initialDistance == currentDistance) return {
width,
height,
left,
top,
scale
} as xSIZEiMage;
// 计算缩放比例(加入阻尼)
const rawScaleChange = currentDistance / initialDistance;
const dampedScaleChange = 1 + (rawScaleChange - 1) * DAMPING_FACTOR;
let newScale = scale * dampedScaleChange;
// 计算最小宽高(确保至少覆盖裁剪框)
const minWidth = Math.max(cropWidth, originWidth * initialScale);
const minHeight = Math.max(cropHeight, originHeight * initialScale);
// 计算最大宽高
const maxWidth = originWidth * 3;
const maxHeight = originHeight * 3;
// 限制缩放范围
const MIN_SCALE = initialScale;
const MAX_SCALE = 3;
// 判断是否超过最大缩放限制
if (newScale > MAX_SCALE) {
return {
width: maxWidth,
height: maxHeight,
left,
top,
scale: MAX_SCALE
} as xSIZEiMage;
}
if (newScale < MIN_SCALE) {
return {
width: minWidth,
height: minHeight,
left,
top,
scale: MIN_SCALE
} as xSIZEiMage;
}
// 计算新的图片宽高
const newWidth = Math.max(minWidth, Math.min(originWidth * newScale, maxWidth));
const newHeight = Math.max(minHeight, Math.min(originHeight * newScale, maxHeight));
// 计算缩放中心点
const initialCenter = getCenter(initialPoints);
const currentCenter = getCenter(currentPoints);
// 计算偏移量(同样应用阻尼)
const rawOffsetX = (initialCenter.x - left) * (dampedScaleChange - 1);
const rawOffsetY = (initialCenter.y - top) * (dampedScaleChange - 1);
// 计算新的位置
const newLeft = left - rawOffsetX;
const newTop = top - rawOffsetY;
return {
width: newWidth,
height: newHeight,
left: newLeft,
top: newTop,
scale: newScale
} as xSIZEiMage;
}
// 根据裁剪框的缩放后的大小,与原始大小的缩放比,确定图片的当前大小的缩放比与位置
export function maskRatioScaleToPhotoSizePosition (oldMaskSize:xSIZEiMage,newMaskSize:xSIZE,oldimg:xImageInfo,nowImgPosSize:xSIZEiMage,index:number){
let difflen = oldMaskSize.width - newMaskSize.width
let scale2 = difflen/oldMaskSize.width
let nwdifflen = scale2*nowImgPosSize.width
let scale = nwdifflen / oldimg.width
if(nowImgPosSize.scale + scale>3){
scale = 3-nowImgPosSize.scale
}
let diffx = oldimg.width*scale
let diffy = oldimg.height*scale
let newWidth = nowImgPosSize.width + diffx
let newHeight = nowImgPosSize.height + diffy
nowImgPosSize.width = newWidth
nowImgPosSize.height = newHeight
// 左上角,应该是左上放大.
if(index == 0){
nowImgPosSize.left = nowImgPosSize.left - diffx
nowImgPosSize.top = nowImgPosSize.top - diffy
}
if(index == 1){
// nowImgPosSize.left = nowImgPosSize.left - diffx
nowImgPosSize.top = nowImgPosSize.top - diffy
}
if(index == 3){
nowImgPosSize.left = nowImgPosSize.left - diffx
// nowImgPosSize.top = nowImgPosSize.top - diffy
}
newMaskSize.width = oldMaskSize.width
newMaskSize.height = oldMaskSize.height
newMaskSize.left = oldMaskSize.left
newMaskSize.top = oldMaskSize.top
nowImgPosSize.scale = nowImgPosSize.scale + scale
}
File diff suppressed because it is too large Load Diff