export default { data() { return { deviation: 5, // 对齐误差范围 xLines: [], yLines: [], }; }, methods: { getMax(arr) { return Math.max.apply(null, arr); }, getMin(arr) { return Math.min.apply(null, arr); }, getPoints(item) { // 权重关系:先左后右 // 具体:左上 > 左下 > 中心 > 右上 > 右下 return [ { x: item.x, y: item.y }, { x: item.x, y: item.y + item.h }, { x: item.x + item.w / 2, y: item.y + item.h / 2 }, { x: item.x + item.w, y: item.y }, { x: item.x + item.w, y: item.y + item.h }, ]; }, rebuild(elements, curElement, actionType = "move") { this.clear(); const curPoints = this.getPoints(curElement); const envPoints = elements .filter((item) => item.id !== curElement.id) .map((item) => this.getPoints(item)); let fitPoints = []; // 提取可能的辅助线 // y线分三种:左中右 // x线分三种:上中下 let xMaybeLines = {}, yMaybeLines = {}; const yPointTypes = { 0: "left", 1: "left", 2: "center", 3: "right", 4: "right", }; const xPointTypes = { 0: "top", 1: "bottom", 2: "center", 3: "top", 4: "bottom", }; envPoints.forEach((points) => { points.forEach((point, pindex) => { // 中心点的对齐误差值取半数误差值 const deviation = pindex === 2 ? this.deviation / 2 : this.deviation; const curPoint = curPoints[pindex]; if ( curPoint.x <= point.x + deviation && curPoint.x >= point.x - deviation ) { if (!yMaybeLines[yPointTypes[pindex]]) yMaybeLines[yPointTypes[pindex]] = []; yMaybeLines[yPointTypes[pindex]].push({ pindex, x: point.x, y: Math.min(curPoint.y, point.y), h: Math.abs(curPoint.y - point.y), offset: Math.abs(curPoint.x - point.x), }); } if ( curPoint.y <= point.y + deviation && curPoint.y >= point.y - deviation ) { if (!xMaybeLines[xPointTypes[pindex]]) xMaybeLines[xPointTypes[pindex]] = []; xMaybeLines[xPointTypes[pindex]].push({ pindex, x: Math.min(curPoint.x, point.x), y: point.y, w: Math.abs(curPoint.x - point.x), offset: Math.abs(curPoint.y - point.y), }); } }); }); // 过滤误差过大的辅助线,即取误差最小的辅助线 let yLines = []; Object.values(yMaybeLines).forEach((lines) => { lines.sort((a, b) => a.offset - b.offset); const validX = lines[0].x; const validLines = lines.filter((line) => line.x === validX); validLines.forEach((line) => { const pindex = line.pindex; if (!fitPoints[pindex]) fitPoints[pindex] = {}; fitPoints[pindex].x = validX; }); yLines = [...yLines, ...validLines]; }); let xLines = []; Object.values(xMaybeLines).forEach((lines) => { lines.sort((a, b) => a.offset - b.offset); const validY = lines[0].y; const validLines = lines.filter((line) => line.y === validY); validLines.forEach((line) => { const pindex = line.pindex; if (!fitPoints[pindex]) fitPoints[pindex] = {}; fitPoints[pindex].y = validY; }); xLines = [...xLines, ...validLines]; }); // 合并辅助线 let yLinesMap = {}; yLines.forEach((line) => { if (!yLinesMap[line.x]) yLinesMap[line.x] = []; yLinesMap[line.x].push(line); }); this.yLines = Object.values(yLinesMap).map((lines) => { const lowH = this.getMax(lines.map((l) => l.y + l.h)); const topY = this.getMin(lines.map((l) => l.y)); return { left: lines[0].x + "px", top: topY + "px", height: lowH - topY + "px", }; }); let xLinesMap = {}; xLines.forEach((line) => { if (!xLinesMap[line.y]) xLinesMap[line.y] = []; xLinesMap[line.y].push(line); }); this.xLines = Object.values(xLinesMap).map((lines) => { const rightW = this.getMax(lines.map((l) => l.x + l.w)); const leftX = this.getMin(lines.map((l) => l.x)); return { left: leftX + "px", top: lines[0].y + "px", width: rightW - leftX + "px", }; }); // 计算自动贴合后的坐标点 if (actionType === "move") { // 移动模式时,算偏移量 // 按照getPoints中设置的点顺序权重进行计算 // 只要获得结果,便停止计算 let xOffset = null, yOffset = null; curPoints.forEach((point, pindex) => { const fitPoint = fitPoints[pindex] || {}; if (xOffset === null && fitPoint.x) { xOffset = fitPoint.x - point.x; } if (yOffset === null && fitPoint.y) { yOffset = fitPoint.y - point.y; } }); return { x: curElement.x + xOffset, y: curElement.y + yOffset, w: curElement.w, h: curElement.h, }; } else { // 变形模式时,算贴合点 const newPoints = curPoints.map((point, pindex) => { const fitPoint = fitPoints[pindex] || {}; return { x: Object.prototype.hasOwnProperty.call(fitPoint, "x") ? fitPoint.x : point.x, y: Object.prototype.hasOwnProperty.call(fitPoint, "y") ? fitPoint.y : point.y, }; }); return { x: newPoints[0].x, y: newPoints[0].y, w: newPoints[4].x - newPoints[0].x, h: newPoints[4].y - newPoints[0].y, }; } }, clear() { this.xLines = []; this.yLines = []; }, }, };