这是我参与「第四届青训营 」笔记创作活动的第7天
本文主要记录低代码项目的学习📖 本期讨论有关组件的旋转遇到的问题
旋转
旋转是低代码一个难点 因为需要考虑的东西很多
-
要计算旋转的角度
-
旋转后光标也要改变
-
旋转后组件的放大缩小模式可能由于光标的改变而变
旋转角度
通过查阅资料 🔍大概总结如下📃
首先介绍一个函数📐
Math.atan2() 是JavaScript数学库中的函数,用于查找其参数商的反正切。 Math.atan2(y,x) 将返回作为(x,y)点和x轴角度的数值。
❗注意
-
第一个参数是y,第二个参数是x
-
算出来是弧度 要转换为角度 即除以
Math.PI/180
我们以组件中心点为原点 那么我们要做的是
- 提前计算出组件中心点
centerX、centerY,因为不会随着旋转而改变 记录一开始的旋转角度rotate - 鼠标点击时计算出 对应的x、y 假设为
startX、startY同时利用公式计算点击时的角度 如下const startRotate = Math.atan2(startY - centerY, startX - centerX)/(Math.PI/180) - 鼠标移动时利用公式计算出实时的角度 如下
const curRotate = Math.atan2(curY - centerY, curX - centerX)/(Math.PI/180) - 计算出最终
style.rotate = rotate+(curRotate -startRotate) - 注意 ❗ 只改变轮廓的transform即可 若父子元素都改变会产生叠加导致子元素旋转两倍 如下图
旋转后的缩放
做到这里 已经可以实现旋转了 但是会发现 缩放出现了bug
这是因为 🤔
-
外框的八个点对应的光标被写死
-
每个光标对应的缩放模式被写死
旋转时中心点不变 故先计算出中心点的坐标
要计算几个重要点的坐标📍
按下鼠标时计算中心点
const center = {
x:style.left + style.width/2,
y:style.top + style.height/2
}
对称点
//当前点击坐标
const startPoint = {
x:e.clientX - rect.left,
y:e.clientY - rect.top
}
//对称点
const symmetricPoint = {
x:center.x - (startPoint.x-center.x),
y:center.y - (startPoint.y-center.y)
}
const move = function (ev) {
//移动中的当前坐标
const curPoint = {
x:ev.clientX - left,
y:ev.clientY - top
}
//计算新的中心点
// const newCenter = centerPoint(curPoint,symmetryPoint)
calcTL(style,curPoint,{symmetricPoint,pointType:i})
}
由于组件旋转过程中 top left 宽高都没改变 故缩放其实是在组件带着对应角度的transform属性下去改变其宽高或top、left
由于中心点不变 实际上 在已旋转状态下缩放 可以 等价为 在没旋转时缩放后再旋转
因此 我们需要利用当前鼠标位置(旋转状态) 及中心点(旋转不变)、 旋转角度 得出 对应的新坐标(没旋转的)
利用当前鼠标位置的对称点(旋转状态) 及中心点(旋转不变)、 旋转角度 得出 对应的新坐标的对称点(没旋转的)
// 计算新top、left
function calcTL(style,curPoint,pointInfo) {
const {symmetricPoint,pointType } = pointInfo // 对称点
const newCenterPoint = centerPoint(curPoint,symmetricPoint)// 得到新的中心点
const newTL = calcRotate(curPoint,newCenterPoint,-style.rotate) // 新的左上角坐标
const newBR = calcRotate(symmetricPoint,newCenterPoint,-style.rotate)// 新的右下角坐标
// 计算新宽高
const width = newBR.x - newTL.x
const height = newBR.y - newTL.y
console.log(typeof(-height));
if (pointType.includes("t")) {
style.height = height
style.top = newTL.y
}
if (pointType.includes("b")) {
style.height = -height
}
if (pointType.includes("l")) {
style.left = newTL.x
style.width = width
}
if (pointType.includes("r")) {
style.width = -width
}
}
光标问题
- 给8个点分别设置初始光标对应角度 如下
const initialAngle = {
// 每个点对应的初始角度
lt: 0,
t: 45,
rt: 90,
r: 135,
rb: 180,
b: 225,
lb: 270,
l: 315,
};
- 规定不同角度对应什么光标 如下
const angleToCursor = [
{ start: 338, end: 23, cursor: "nw" },
{ start: 23, end: 68, cursor: "n" },
{ start: 68, end: 113, cursor: "ne" },
{ start: 113, end: 158, cursor: "e" },
{ start: 158, end: 203, cursor: "se" },
{ start: 203, end: 248, cursor: "s" },
{ start: 248, end: 293, cursor: "sw" },
{ start: 293, end: 338, cursor: "w" },
];
- 根据角度给予对应的光标
//角度计算方法 角度 = 旋转角度 + 初始光标的角度
const angle = style.rotate + initialAngle[pointType]
💭💭💭
记录低代码项目中的问题📜
若本文对你有帮助 欢迎点赞收藏👍📑
若有纰漏,敬请包涵,评论区欢迎指正👂