Html5 Canvas实现图片标记、缩放、移动和保存历史状态功能 (附转换公式)
<div className="mark-paper__wrap" ref={wrapRef}> <canvas ref={canvasRef} className="mark-paper__canvas"> <p>很可惜,这个东东与您的电脑不搭!</p> </canvas> <div className="mark-paper__sider" /> </div> 我们唯一需要的一点就是,容器需要设置属性 overflow: hidden 用来隐藏内部canvas画布溢出的内容,也就是说,我们要控制我们可视的区域。同时我们需要动态获取容器宽高来为canvas设置尺寸 2. 初始化canvas画布与填充图片 我们可以弄个方法来初始化并且填充画布,以下截取主要部分,其实就是为canvas画布设置尺寸与填充我们的图片 const fillImage = async () => { // 此处省略... const img: HTMLImageElement = new Image() img.src = await getURLBase64(fillImageSrc) img.onload = () => { canvas.width = img.width canvas.height = img.height context.drawImage(img, 0, 0) // 设置变化基点,为画布容器中央 canvas.style.transformOrigin = `${wrap?.offsetWidth / 2}px ${wrap?.offsetHeight / 2}px` // 清除上一次变化的效果 canvas.style.transform = '' } } 3. 监听canvas画布的各种鼠标事件 这个控制移动的话,我们首先可以弄一个方法来监听画布鼠标的各种事件,可以区分不同的模式来进行不同的事件处理 const handleCanvas = () => { const { current: canvas } = canvasRef const { current: wrap } = wrapRef const context: CanvasRenderingContext2D | undefined | null = canvas?.getContext('2d') if (!context || !wrap) return // 清除上一次设置的监听,以防获取参数错误 wrap.onmousedown = null wrap.onmousedown = function (event: MouseEvent) { const downX: number = event.pageX const downY: number = event.pageY // 区分我们现在选择的鼠标模式:移动、画笔、橡皮擦 switch (mouseMode) { case MOVE_MODE: handleMoveMode(downX, downY) break case LINE_MODE: handleLineMode(downX, downY) break case ERASER_MODE: handleEraserMode(downX, downY) break default: break } } 4. 实现画布移动 这个就比较好办啦,我们只需要利用鼠标按下的坐标,和我们拖动的距离就可以实现画布的移动啦,因为涉及到每次移动都需要计算最新的位移距离,我们可以定义几个变量来进行计算。 这里监听的是容器的鼠标事件,而不是canvas画布的事件,因为这样子我们可以再移动超过边界的时候也可以进行移动操作 简单的总结一下: 传入鼠标按下的坐标 计算当前位移距离,并更新css变化效果 鼠标抬起时更新最新的位移状态 // 定义一些变量,来保存当前/最新的移动状态 // 当前位移的距离 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 handleMoveMode = (downX: number, downY: number) => { const { current: canvas } = canvasRef const { current: wrap } = wrapRef const { current: fillStartPointX } = fillStartPointXRef const { current: fillStartPointY } = fillStartPointYRef if (!canvas || !wrap || mouseMode !== 0) return // 为容器添加移动事件,可以在空白处移动图片 wrap.onmousemove = (event: MouseEvent) => { const moveX: number = event.pageX const moveY: number = event.pageY // 更新现在的位移距离,值为:上一次位移结束的坐标+移动的距离 translatePointXRef.current = fillStartPointX + (moveX - downX) translatePointYRef.current = fillStartPointY + (moveY - downY) // 更新画布的css变化 canvas.style.transform = `scale(${canvasScale},${canvasScale}) translate(${translatePointXRef.current}px,${translatePointYRef.current}px)` } wrap.onmouseup = (event: MouseEvent) => { const upX: number = event.pageX const upY: number = event.pageY // 取消事件监听 wrap.onmousemove = null wrap.onmouseup = null; // 鼠标抬起时候,更新“上一次唯一结束的坐标” fillStartPointXRef.current = fillStartPointX + (upX - downX) fillStartPointYRef.current = fillStartPointY + (upY - downY) } } 5. 实现画布缩放 画布缩放我主要通过右侧的滑动条以及鼠标滚轮来实现,首先我们再监听画布鼠标事件的函数中加一下监听滚轮的事件 总结一下: 监听鼠标滚轮的变化 更新缩放倍数,并改变样式 (编辑:PHP编程网 - 黄冈站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |