-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(core): node => rotate+正常模式resize(#1428) #1835
Conversation
|
cool 啊帅哥。下次找个时间大家认识一下吧 哈哈哈 |
我看一下 PR,有问题再沟通 |
靓仔,我上周看了 pr,这个 PR 会导致 extension 打包报错,好像是类型问题。你抽空也确认下?我原本想自己解决,但最近在忙其它的事情,没顾上弄 |
可以像下面这样解决报错,原因应该是我在此次pr中给 但是我不想在这个pr中修复一些非 目前我在 pull/1858这里修复了上面这个报错,要不先review下这个pull/1858,如果pull/1858满足merge的话,合并过来应该就没有报错了 🤔️或者你先手动改下 |
🤔️有问题吗这个pr?还是你们内部想自己修复这些问题? @boyongjiong |
讲得很详细,👍!确实是旋转之后的 dx,dy 没有对应原有坐标导致的问题。 |
WIP. 大佬的 PR 很优秀,我最近忙别的没顾上弄,这两天处理一下 |
帅哥,那个 PR 我已经合进去了,这个 PR 你基于 master rebase 一下,再重新提一下?现在这个 PR 我想 |
68ea027
to
45eba18
Compare
已经基于 master rebase @boyongjiong 再试试 |
4.2 freezeWidth 和 freezeHeight @wbccb 最上面 4.2 这部分代码为什么本次 PR 不加上呢?我理解是在本次 PR 范围内的吧 |
@@ -0,0 +1,55 @@ | |||
export interface SimplePoint { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我可以接受这个类型定义,但其实我们内部是有一个 Position 的定义,用来表示坐标位置
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个SimplePoint的类型定义,在后续的pr中,我把它干掉,替换一下
有两个原因:
对于这个freezeWidth 和 freezeHeight的功能,我不清楚后续的优化计划(要废弃还是优化之类的),所以我就没加这段代码了 @boyongjiong class RectNodeModel {
setAttributes() {
super.setAttributes()
const { width, height, radius, minWidth, maxWidth, minHeight, maxHeight } =
this.properties
if (!isNil(width)) this.width = width
if (!isNil(height)) this.height = height
// @ts-ignore
if (!isNil(minWidth)) this.minWidth = minWidth
// @ts-ignore
if (!isNil(maxWidth)) this.maxWidth = maxWidth
// @ts-ignore
if (!isNil(minHeight)) this.minHeight = minHeight
// @ts-ignore
if (!isNil(maxHeight)) this.maxHeight = maxHeight
// 矩形特有
if (!isNil(radius)) this.radius = radius
}
} |
soga,我也想想你说的东西。 哈哈,你可以根据你的想法做调整,你觉得合理的,都可以搞,合理性我们再一起讨论嘛 😄 |
🤔️嗯嗯嗯嗯 后续搞搞 |
related: transform相关问题汇总
fix: #1428
fix: #1628
fix: #1813
fix: #1475
1. 前言
node 加入
rotate
后,可能影响的范围有:本次 pr 主要针对 rotate + resize 的正常 resize 模式进行修复
注:由于失误,将control坐标的名称叫成anchorX和anchorY,代码中已经更改,但是这里的pr描述由于篇幅过长,重做比较耗费时间,因此这里没有更改,凡是出现anchor相关单词,都可以替换为control
2.问题发生的原因
在
rotate=0
的情况下,坐标转换简单,通过触摸点计算出 dx 和 dy,然后进行整体的 resize,但是在rotate不等于0
的情况下,我们通过触摸点计算出 dx 和 dy 还得经过一层转化才能正确 resizerotate=0
的处理,也就是触摸点计算出来的 dx 和 dy 就是实际宽度和高度变化的 dx 和 dy,然后计算出newWidth = oldWidth+dx
rotate=0
的情况下拉伸右下角的 anchor,左上角 anchor 保持不变),而由于宽度和高度发生变化,因此中心点 center 也发生变化,因此左上角的 anchor 实际坐标会发生变化,因此这个时候不能简单使用newCenter.x = oldCenter.x + dx
的逻辑因此在
rotate不等于0
的情况下,newWidth
的计算和newCenter
的计算都需要进行调整3.解决方法
在原来逻辑中,
recalcResizeInfo
先处理了PCTResizeInfo
的情况(也就是等比例缩放),返回nextResizeInfo
,然后再处理正常模式下缩放,返回nextResizeInfo
因此我们在原来的逻辑上增加
PCTResizeInfo为空
并且rotate不等于0
的逻辑处理:recalcRotatedResizeInfo()
,不影响原来等比例缩放
和正常模式缩放+rotate=0
的处理逻辑recalcRotatedResizeInfo()
主要是calculateWidthAndHeight()
计算出宽度、高度和新的中心点newCenter
newCenter
和oldCenter
的比较得出deltaX
和deltaY
,因为最终我们是通过BaseNodeModel.resize()
来重置 width、height,以及通过BaseNodeModel.move()
的this.x = this.x+deltaX
来更新中心点的坐标如下面代码所示,当我们不考虑
freezeWidth
和freezeHeight
时,代码逻辑是非常简单的3.1 图解
第1个图=>第2个图
:利用目前已知的坐标oldCenter
、startRotatedTouchAnchorPoint
(也就是 anchor 坐标)、手指触摸的距离(也就是 onDraging 得到的 dx 和 dy),我们可以计算得到的坐标endRotatedTouchAnchorPoint
和freezePoint
第2个图=>第3个图
:利用freezePoint
和endRotatedTouchAnchorPoint
,我们可以得到新的中心点newCenter
第3个图=>第4个图
:自此我们知道了几乎所有点的坐标,我们进行-angle
的翻转得到去掉transform
的图形以及对应的坐标(也就是rotate=0
的图形)第4个图
:利用rotate=0
的图形顺利计算出新的 width 和 height 以及 newCenter 和 oldCenter 之间的偏移量 deltaX 和 deltaY3.2 freezeWidth 和 freezeHeight
当加入
freezeWidth
和freezeHeight
后,情况会变的比较复杂,因为 rotate 不为 0 的时候,recalcRotatedResizeInfo()计算出来的中心点会发生变化,因此我们不能简单限制freezeWidth
,我们就设置为deltaX=0
,我们还是得计算出来deltaX
和deltaY
因此我们在原来的
calculateWidthAndHeight()
加入一段修正deltaX
和deltaY
的逻辑图1->图2
: 当freezeWidth=true
时,我们进行宽度的恢复,得出需要减去的宽度widthDx
图2->图3
: 我们使用减去的宽度widthDx
去修正目前的中心点newCenter.x=newCenter.x-widthDx/2
图3->图4
: 我们旋转angle
得到 transform 后的左上角坐标,此时应该保持一致,因此我们可以得出目前的偏移量,通过偏移量,我们整体平移图形,修正newCenter
的误差图4->图5
: 通过准确的newCenter
以及固定不变的freezePoint
,我们可以计算出新的左上角和右下角,然后计算出width
和height
3.3 其他小优化点
3.3.1 freezeWidth 和 freezeHeight 滑动卡顿问题
当
freezeWidth=true
时,minWidth等于maxHeight
,因此nextSize.width
必须等于minWidth
rotate!==0
触发calculateWidthAndHeight()
计算width
和height
,理论计算出来的nextSize.width
必须等于oldWidth
,但是实际上有误差,比如因此在
calculateWidthAndHeight()
直接width = oldWidth
,防止误差导致cancelDrag()
发生3.3.2 onDragging 没有销毁注册事件
如下面视频所示,有一定小概率会发生,当
ResizeControlGroup
销毁时,也就是 Resize 的组件销毁时,此时的DOC.removeEventListener("mousemove")
没有触发,也就是没有销毁注册监听,导致 onDragging 一直触发,造成滑动错乱情况发生onDragging.mov
通过代码分析,当
<ResizeControlGroup>
在滑动过程中因为某些原因造成销毁,并且在销毁前没有触发handleMouseUp()
事件,也就是跟视频展示一样,在滑动过程中,某些特殊原因导致滑动过程中就触发ResizeControlGroup
销毁时,还没来得及触发handleMouseUp()
时,就会导致window?.document
注册的mousemove
一直存在!因此在
ResizeControl
销毁时,应该主动触发一次事件销毁this.dragHandler.cancelDrag()
,才能避免一些错乱事情发生4. 测试代码和效果视频
4.1 正常模式的 rotate+resize
代码已经上传到
examples/feature-examples/src/pages/graph/index.tsx
test-resize_compressed.mp4
4.2 freezeWidth 和 freezeHeight
由于代码中好像没有实现
maxHeight
和minHeight
的初始化处理,因此我添加了一些测试代码,没有上传在
examples/feature-examples/src/pages/nodes/native/index.tsx
const data = {}
增加测试数据freeWidth矩形
和freeHeight矩形
const config
增加配置allowRotate=true
和allowResize=true
在
packages/core/src/model/node/RectNodeModel.ts
的setAttributes()
增加this.minWidth = minWidth
this.maxWidth = maxWidth
this.minHeight = minHeight
this.maxHeight = maxHeight
test-freezeWidth.mp4