feat(zhst/meta-cropperImage): 修改框

This commit is contained in:
NICE CODE BY DEV 2024-05-11 18:22:01 +08:00
parent b4d001475a
commit 066cd46614
2 changed files with 139 additions and 36 deletions

View File

@ -1,4 +1,4 @@
import React, { useRef, useEffect, forwardRef, useImperativeHandle, useContext, useState, ReactNode } from 'react'
import React, { useRef, useEffect, forwardRef, useImperativeHandle, useContext, useState, ReactNode, useMemo } from 'react'
import classNames from 'classnames'
import { fabric } from 'fabric'
import { addEventListenerWrapper, getTransforms, pick } from '@zhst/func'
@ -12,7 +12,8 @@ import Align from 'rc-align';
import { getTransformRect } from '../BigImagePreview/bigImagePreviewHelper';
interface RectPro extends Rect {
imageRect: string
imageRect?: string;
type?: 'line' | 'rect'; // line:线rect矩形
}
export interface CropperImageProps {
@ -20,7 +21,7 @@ export interface CropperImageProps {
url?: string;
width?: number;
height?: number;
odList?: Rect[] // od框
odList?: RectPro[] // od框
lineConfig?: fabric.Line; // 线条配置
editAble?: boolean; // 是否可编辑
selectedItem?: RectPro
@ -93,7 +94,7 @@ const CropperImage = forwardRef<CropperImageRefProps, CropperImageProps>((props,
} = props;
const { getPrefixCls } = useContext(ConfigContext);
const componentName = getPrefixCls('cropper-view', customizePrefixCls);
const [isMove, setIsMove] = useState(false) // 矩形是否在移动
const [isDrawing, setIsDrawing] = useState(false) // 矩形是否在移动
const canvasRef = useRef<any>(null);
const currentShapeRef = useRef<any>(null)
@ -103,6 +104,7 @@ const CropperImage = forwardRef<CropperImageRefProps, CropperImageProps>((props,
// 自定义弹框
const alginContainerRef: any = useRef(null);
const alignRef: any = useRef(null);
const imageRectRef: any = useRef(null)
// 初始化 - 图片
useEffect(() => {
@ -114,23 +116,37 @@ const CropperImage = forwardRef<CropperImageRefProps, CropperImageProps>((props,
});
// 监听形状选择事件
addEventListenerWrapper(imageRef.current, EVENT_SHAPE_SELECT, (e: { detail: any; }) => {
imageRectRef.current = addEventListenerWrapper(imageRef.current, EVENT_SHAPE_SELECT, (e: { detail: any; }) => {
// 选中的od
const id = e.detail;
if (id) {
const selectRectData = odList!.filter(_od => _od.id === id)?.[0]
// 获取选中的形状
// const shapes = imgIns.getSelectShape();
const selectRectData = odList!.filter(_od => _od.id === id)?.[0] || {}
const _data = percentToLength(selectRectData, viewerRef.current.canvas)
const imageRect = getImageDataByPosition(
{ x: _data.x, y: _data.y, w: _data.w, h: _data.h },
{ canvas: viewerRef.current.canvas }
)
// TODO: 换算成屏幕坐标
// const axisRect = imgIns.imgRectAxisToCanvasAxisRect(selectShape);
// const rect = {
// x: axisRect.x2 > axisRect.x ? axisRect.x : axisRect.x2,
// y: axisRect.y2 > axisRect.y ? axisRect.y : axisRect.y2,
// w: Math.abs(axisRect.x2 - axisRect.x),
// h: Math.abs(axisRect.y2 - axisRect.y),
// };
// getTransformRect(imageRectRef.current.image, )
id && onShapeSelected?.(id, { ..._data, imageRect, originData: selectRectData })
}
})
return () => {
// 再次加载,销毁原来的实例
viewerRef?.current?.destroy?.();
viewerRef.current = null;
imageRectRef.current?.remove();
viewerRef.current?.clearShape?.();
}
}, [url])
@ -149,26 +165,22 @@ const CropperImage = forwardRef<CropperImageRefProps, CropperImageProps>((props,
})
return
} else {
// 编辑模式
_viewer?.clearShape?.();
const { targetTransform = {} } = _viewer
if (type === 'rect') {
// 编辑模式 - 矩形绘制
currentShapeRef.current = initRect()
// 矩形 - 开始绘制实践
cropStartRef.current = addEventListenerWrapper(imageRef.current, EVENT_CROP_START, () => {
setIsMove(true)
onCropStart?.()
});
// 矩形 - 结束绘制实践
cropEndRef.current = addEventListenerWrapper(imageRef.current, EVENT_CROP_END, (event: { detail: any; }) => {
const data = event.detail;
const targetPosition = { x: data.left, y: data.top, w: data.width, h: data.height }
const imageRect = getImageDataByPosition(targetPosition, { canvas: viewerRef.current.canvas })
const targetData = getTransformRect(_viewer.image, targetTransform, targetPosition)
onCropEnd?.({ ...data , imageRect, targetTransform, targetData })
setIsMove(false)
})
// cropEndRef.current = addEventListenerWrapper(imageRef.current, EVENT_CROP_END, (event: { detail: any; }) => {
// const data = event.detail;
// const targetPosition = { x: data.left, y: data.top, w: data.width, h: data.height }
// const imageRect = getImageDataByPosition(targetPosition, { canvas: viewerRef.current.canvas })
// const targetData = getTransformRect(_viewer.image, targetTransform, targetPosition)
// onCropEnd?.({ ...data , imageRect, targetTransform, targetData })
// setIsMove(false)
// })
} else {
// 编辑模式 - 线绘制
currentShapeRef.current = initLine()
}
}
@ -179,17 +191,110 @@ const CropperImage = forwardRef<CropperImageRefProps, CropperImageProps>((props,
currentShapeRef.current?.destroy?.()
currentShapeRef.current?.dispose?.()
}
},[type, editAble, odList])
},[type, editAble])
// 初始化 - 矩形圈选工具
const initRect = () => {
const currentCropper = new Cropper(imageRef.current, {
showMask: true,
scaleAble: false,
viewer: viewerRef.current,
const viewer = viewerRef?.current || {}
const { containerData = {}, targetTransform = {} } = viewer
let currentFabric: CanvasPro = new fabric.Canvas(
canvasRef.current,
{
backgroundColor: 'transparent',
width: containerData.width,
height: containerData.height,
selection: false,
}
)
let rect: fabric.Rect
let origX: number, origY: number
function addOrReplaceRect(newRect) {
// 移除画布上所有的矩形对象
const objects = currentFabric.getObjects();
for (let i = objects.length - 1; i >= 0; i--) {
if (objects[i].type === 'rect') {
currentFabric.remove(objects[i]);
}
}
// 添加新的矩形对象
currentFabric.add(newRect);
}
const checkPointInRect = (o: fabric.IEvent<MouseEvent>) => {
var pointer = currentFabric.getPointer(o.e);
var point = new fabric.Point(pointer.x, pointer.y);
let inRect = false
currentFabric.forEachObject(function(obj) {
if (obj.containsPoint(point) || obj._findTargetCorner(pointer)) {
inRect = true
} else {
inRect = false
}
});
return inRect
}
// 鼠标按下事件
currentFabric.on('mouse:down', function(o) {
currentFabric.startDraw = true
var pointer = currentFabric.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
// 创建一个矩形对象
rect = new fabric.Rect({
left: origX,
top: origY,
originX: 'left',
originY: 'top',
borderColor: '#09f',
cornerColor: '#09f',
cornerSize: 6,
width: pointer.x - origX,
height: pointer.y - origY,
angle: 0,
fill: 'transparent',
hasControls: true,
hasBorders: true,
lockRotation: true, // 锁定旋转
hasRotatingPoint: false // 隐藏旋转控制点
});
// 判断存在实例,并且鼠标点击在实例上
if (checkPointInRect(o) && rect) {
} else {
addOrReplaceRect(rect)
// 监听移动
rect.on('moving', o => console.log('o', o))
rect.on('resizing', o => console.log('o', o))
// 监听缩放
rect.on('scaling', o => console.log('o', o))
}
currentFabric.setActiveObject(currentFabric.item(0));
});
// 鼠标移动事件
currentFabric.on('mouse:move', function(o) {
if (!currentFabric.startDraw) return;
var pointer = currentFabric.getPointer(o.e);
if(origX > pointer.x){
rect.set({ left: Math.abs(pointer.x) });
}
if(origY > pointer.y){
rect.set({ top: Math.abs(pointer.y) });
}
rect.set({ width: Math.abs(origX - pointer.x) });
rect.set({ height: Math.abs(origY - pointer.y) });
currentFabric.renderAll();
});
// 鼠标松开事件
currentFabric.on('mouse:up', function(o) {
currentFabric.startDraw = false
});
return currentCropper
return currentFabric
}
// 初始化线条
@ -316,7 +421,7 @@ const CropperImage = forwardRef<CropperImageRefProps, CropperImageProps>((props,
ref={imageRef}
className={classNames(`${componentName}_img`)}
/>
{showToast && selectedItem && !isMove && (<>
{showToast && selectedItem && !isDrawing && (<>
<div
ref={alginContainerRef}
// @ts-ignore
@ -357,7 +462,7 @@ const CropperImage = forwardRef<CropperImageRefProps, CropperImageProps>((props,
})}
</Align>
</>)}
<canvas style={{ display: (type === 'line' && editAble) ? 'block' : 'none' }} ref={canvasRef} className={classNames(`${componentName}_draw`)}></canvas>
<canvas ref={canvasRef} className={classNames(`${componentName}_draw`)}></canvas>
{children}
</div>
);

View File

@ -30,11 +30,10 @@ export default () => {
odList={[
{
"id": "123",
"x": 0.5519352,
"y": 0.2965385,
"w": 0.05185461,
"h": 0.24698898,
selectAble: false,
h: 0.30666666666666664,
w: 0.27170650730411683,
x: 0.19064741035856572,
y: 0.09703124999999999,
},
{
"id": "456",
@ -53,9 +52,8 @@ export default () => {
}}
onCropStart={() => console.log('矩形开始绘制')}
onCropEnd={(data) => {
console.log('矩形结束绘制', data)
setSelectedItem({ x: data.left, y: data.top, h: data.height, w: data.width })
setImgUrl(data.imageRect as string)
setImgUrl(data?.imageRect as string)
}}
selectedItem={selectedItem}
showToast={editAble}