具體代碼參見: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座標放入,具體詳見源碼