Html5 Canvas实现图片标记、缩放、移动和保存历史状态功能 (附转

2020-04-25 07:29:21易采站长站整理

const MOVE_MODE: number = 0
const LINE_MODE: number = 1
const ERASER_MODE: number = 2
const canvasRef: RefObject<HTMLCanvasElement> = useRef(null)
const containerRef: RefObject<HTMLDivElement> = useRef(null)
const wrapRef: RefObject<HTMLDivElement> = useRef(null)
const translatePointXRef: MutableRefObject<number> = useRef(0)
const translatePointYRef: MutableRefObject<number> = useRef(0)
const fillStartPointXRef: MutableRefObject<number> = useRef(0)
const fillStartPointYRef: MutableRefObject<number> = useRef(0)
const canvasHistroyListRef: MutableRefObject<ImageData[]> = useRef([])
const [lineColor, setLineColor] = useState<string>('#fa4b2a')
const [fillImageSrc, setFillImageSrc] = useState<string>('')
const [mouseMode, setmouseMode] = useState<number>(MOVE_MODE)
const [lineWidth, setLineWidth] = useState<number>(5)
const [canvasScale, setCanvasScale] = useState<number>(1)
const [isLoading, setIsLoading] = useState<boolean>(false)
const [canvasCurrentHistory, setCanvasCurrentHistory] = useState<number>(0)

useEffect(() => {
setFillImageSrc('http://cdn.algbb.cn/test/canvasTest.jpg')
}, [])

// 重置变换参数,重新绘制图片
useEffect(() => {
setIsLoading(true)
translatePointXRef.current = 0
translatePointYRef.current = 0
fillStartPointXRef.current = 0
fillStartPointYRef.current = 0
setCanvasScale(1)
fillImage()
}, [fillImageSrc])

// 画布参数变动时,重新监听canvas
useEffect(() => {
handleCanvas()
}, [mouseMode, canvasScale, canvasCurrentHistory])

// 监听画笔颜色变化
useEffect(() => {
const { current: canvas } = canvasRef
const context: CanvasRenderingContext2D | undefined | null = canvas?.getContext('2d')
if (!context) return

context.strokeStyle = lineColor
context.lineWidth = lineWidth
context.lineJoin = 'round'
context.lineCap = 'round'
}, [lineWidth, lineColor])

//监听缩放画布
useEffect(() => {
const { current: canvas } = canvasRef
const { current: translatePointX } = translatePointXRef
const { current: translatePointY } = translatePointYRef
canvas && (canvas.style.transform = `scale(${canvasScale},${canvasScale}) translate(${translatePointX}px,${translatePointY}px)`)
}, [canvasScale])

useEffect(() => {
const { current: canvas } = canvasRef
const { current: canvasHistroyList } = canvasHistroyListRef
const context: CanvasRenderingContext2D | undefined | null = canvas?.getContext('2d')
if (!canvas || !context || canvasCurrentHistory === 0) return
context?.putImageData(canvasHistroyList[canvasCurrentHistory - 1], 0, 0)
}, [canvasCurrentHistory])

const fillImage = async () => {
const { current: canvas } = canvasRef
const { current: wrap } = wrapRef
const context: CanvasRenderingContext2D | undefined | null = canvas?.getContext('2d')