feat(zhst/meta-cropperImage): 修改框
This commit is contained in:
parent
b4d001475a
commit
066cd46614
@ -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>
|
||||
);
|
||||
|
@ -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}
|
||||
|
Loading…
Reference in New Issue
Block a user