CDarg诞生之路之Canvas实现变形、旋转(图片,文字)

您所在的位置:网站首页 canvas旋转图片 CDarg诞生之路之Canvas实现变形、旋转(图片,文字)

CDarg诞生之路之Canvas实现变形、旋转(图片,文字)

2023-07-02 13:53| 来源: 网络整理| 查看: 265

前言

上一篇我们实现了文字、图片的命中检测与拖拽,再做旋转的时候发现,旋转后的图形在做命中检测时有问题,因为图形已经旋转,但矩形的四点坐标仍然没变,导致无法命中,所以命中检测改为使用 isPointInPath() 检测

isPointInPath命中检测

isPointInPath()  是 Canvas 2D API 用于判断在当前路径中是否包含检测点的方法,

命中逻辑

mousedown 的时候重绘所有图形,每绘制一个图形就使用 isPointInPath() 检测是否命中这个绘制图形

核心代码

// 开始新路径 ctx.beginPath() ctx.rect(x,y,w,h) // 绘制 ctx.stroke() const isHitTest = ctx.isPointInPath(e.clientX, e.clientY)

注意!!! isPointInPath无法检测strokeText()、strokeRect()、drawImage()、fillText()等生成内容

那咱们绘制的图片与文字如何命中检测呢?

咱可以给图片和文字使用 rect() 绘制一个透明的包裹容器,直接 isPointInPath() 容器也是一样的

绘制控件

命中图形后绘制变形、旋转、删除控件,分别在左上、右上、右下位置,这里直接那算出图形的顶点、再以顶点为中心画圆 再绘制按钮图片

ctx.arc(left, top, 16, 0, 2 * Math.PI) ctx.drawImage(image, left - 2, top - 2, 12, 12)

image.png

控件命中

控件命中逻辑与前面一样

mousedown重绘 是否命中图形 命中图形后在绘制控件 是否命中某个控件 旋转

计算旋转角度使用 Math.atan2()

Math.atan2()  返回从原点 (0,0) 到 (x,y) 点的线段与 x 轴正方向之间的平面角度 (弧度值),也就是 Math.atan2(y,x),而角度 = 弧度 * 180 / Math.PI

if (type === 'rotate') { // 计算命中图形中心点 const { centerX, centerY } = this.computeCenter(selectRect) // 按下时的角度 down是mousedown的点 const angleBefore = Math.atan2(downY - centerY, downX - centerX) / Math.PI * 180 // 移动形成的角度 client是mousemove的点 const angleAfter = Math.atan2(clientY - centerY, clientX - centerX) / Math.PI * 180 // 旋转的角度等于初始角度(initRotate)+ 移动角度 - 按下时的角度 selectRect[rotate] = initRotate + angleAfter - angleBefore this.draw() } 旋转图形绘制

绘制旋转图形及使用 rotate() 但是在旋转前还得使用 translate()  方法对当前网格的原点平移到当前图形中心点,否则就是以(0,0)点做旋转,旋转完成后还得 restore()  将 canvas 恢复到最近的保存状态的方法,否则后续图形渲染会位置会不正确

restore() 恢复的状态从哪来?

save()  将当前状态放入栈中,得先有状态才能恢复,所以一开始得先 save()

现在绘制图片核心代码如下

// 开始新路径 ctx.beginPath() // 保证状态 ctx.save() // 改变中心 ctx.translate(drawData.left + drawData.width / 2, drawData.top + drawData.height / 2) // 旋转 ctx.rotate(drawData.rotate * Math.PI / 180) // 绘制 ctx.drawImage(drawData.imageEle, -drawData.width / 2, -drawData.height / 2, drawData.width, drawData.height) // 恢复 ctx.restore() 变形

变形就更简单一点,使用移动点减去按下的点 x,y 坐标 加上初始距离即可,对文字的变形直接用差值赋给 size 即可,因为宽高对文字无效,这个还考虑限制一下最小宽高与最小 size

if (type === 'transform') { // 移动的x距离 const moveX = clientX - downX // 移动的y距离 const moveY = clientY - downY let newWidth = initWidth + moveX let newHeight = initHeight + moveY // 反向 if (newWidth < 0) { newWidth = -newWidth } if (newHeight < 0) { newHeight = -newHeight } // 限制最小宽高与size if (selectRect.img) { selectRect.width = newWidth < 6 ? 6 : newWidth selectRect.height = newHeight < 6 ? 6 : newHeight } else if (selectRect.text) { selectRect.size = newHeight < 12 ? 12 : newHeight } this.draw() }

这里对变形做了反向,如果宽高小于0则反向处理

效果 20230628_143857.gif 结尾

CDrag最核心的功能差不多完成了,后续还要再完善一下,加上超出画布限制等等,测试完成后会发布到npm,敬请期待



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3