具体代码参见:https://github.com/yyccmmkk/js-reference-line
【需求】
对一个元素进行拖拽时,生成这个组件和其它组件对齐的参考线,实现各组件间四条边及水平中心线及垂直中心线对齐。在拖动完成后实现自动吸附对齐。
【解决思路】
1 MAP记录所有需要对齐组件的视窗坐标点(左上,右上,左下,右下)
2 P为当前拖拽对象实时的坐标点(左上,左下,右上,右下,中心点)
3 拿当前对象的坐标点P去匹配座标记录MAP
4 发现某一边对齐时,在canvas中画线,清除画布的操作应该在拖动时进行处理,
问题的关键在于如何快速的去计算当前组件的6条线(四边+中心线)和其它所有组件6条线在一条线上,看似麻烦其实可以简化逻辑为,只要判断三个点,左上角、右下角、中心点,在记录中有没有存在
- 如何判断两个组件垂直对齐?答:坐标x一样
- 如何判断两个组件水平对齐?答:坐标Y一样
- 如何记录坐标点便于查询
- 根据坐标画线
【答:3】
创建一个数组 tempArry 存放所有的坐标对象(包含座标信息),像下边这样
let tempArray=[
{let:1,right:100,top:10,bottom:400},
{let:2,right:200,top:20,bottom:600},
{let:1,right:300,top:30,bottom:400}
];
创建两个对象mapX 、mapY。对tempArray 进行遍历,mapX mapY 分别以x ,y 为key。 值为数组(ps:因为有可能多个组件 坐标是相同的),数组保存了坐标对象在tempArray中的索引。
mapX 记录所有组件的坐标x,每个组件三个x坐标(ps:左、中、右),结果如下
let mapX={
1:[0,2],
2:[1],
50.5:[0],
101:[1],
150.5:[2],
100:[0],
200:[1],
300:[2]
};
mapY 记录所有组件的坐标y,每个组件有三个坐标y(ps:上、中、下),结果如下
let mapY={
10:[0],
205:[0],
310:[1],
215:[2],
20:[1],
30:[2],
400:[0,2],
600:[1],
}
假设有一组件视窗坐标为(left:1,right:600,top:20,bottom:300);
通过判断左上角坐标点(p1) 就可以检测组件左边与上边的对齐,通过右下角坐标点(p2),就可以检测组件 右边与下边的对齐,对过中心坐标(p3)就可以找到水平与垂直线的对齐。
p1 x:1,y:20
p2 x:600,y:300
p3 x:300.5,y:160
mapX 中存在以x 为值的key 就证明有垂直对齐的线,
mapY 中存在以 y为值 的key 就证明有水平对齐的线
通过map 中的值索引可以快速拿到对应的对齐组件信息,把当前组件的坐标点信息扔进去,取最大最小值就可以拿到对齐线的坐标信息,详见源码,大概思路是这样,其中还涉及一些细节,比如排自身的坐标信息等。
【自动吸附】
移动中的自动吸附功能不但性能开销高而且相对来说比较复杂,暂时开发为在拖动完成后进行自动吸附操作。
对于自动吸附可以抒理一下子功能点,
1 在吸附范围内找到符合的坐标点,也就是说 目标点坐标 (有3个目标点坐标)减掉当前座标点 绝对值不大于吸附范围
2 在前边的功能中只要找到三个点就可以,所以吸附功能也要找到当前元素的这三个点坐标 及吸附范围 坐标
3 需要区分的是当前元素的哪条边对齐了,因为操作作当前元素样式时,如果底边或右侧的边对齐了需要减掉元素自身的宽或高
4 需要知道当前移动的方向,当用户在远离在吸附范围内的元素时不要吸附
具体的实现细节详见代码
【对齐到网格】
对齐到网格更简单,在之前的基础上把网格坐标放入需要吸附到的坐点数组里即可,生成网格x,y坐标放入,具体详见源码