guideLines.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. export default {
  2. data() {
  3. return {
  4. deviation: 5, // 对齐误差范围
  5. xLines: [],
  6. yLines: []
  7. };
  8. },
  9. methods: {
  10. getMax(arr) {
  11. return Math.max.apply(null, arr);
  12. },
  13. getMin(arr) {
  14. return Math.min.apply(null, arr);
  15. },
  16. getPoints(item) {
  17. // 权重关系:先左后右
  18. // 具体:左上 > 左下 > 中心 > 右上 > 右下
  19. return [
  20. { x: item.x, y: item.y },
  21. { x: item.x, y: item.y + item.h },
  22. { x: item.x + item.w / 2, y: item.y + item.h / 2 },
  23. { x: item.x + item.w, y: item.y },
  24. { x: item.x + item.w, y: item.y + item.h }
  25. ];
  26. },
  27. rebuild(elements, curElement, actionType = "move") {
  28. this.clear();
  29. const curPoints = this.getPoints(curElement);
  30. const envPoints = elements
  31. .filter(item => item.id !== curElement.id)
  32. .map(item => this.getPoints(item));
  33. let fitPoints = [];
  34. // 提取可能的辅助线
  35. // y线分三种:左中右
  36. // x线分三种:上中下
  37. let xMaybeLines = {},
  38. yMaybeLines = {};
  39. const yPointTypes = {
  40. 0: "left",
  41. 1: "left",
  42. 2: "center",
  43. 3: "right",
  44. 4: "right"
  45. };
  46. const xPointTypes = {
  47. 0: "top",
  48. 1: "bottom",
  49. 2: "center",
  50. 3: "top",
  51. 4: "bottom"
  52. };
  53. envPoints.forEach(points => {
  54. points.forEach((point, pindex) => {
  55. // 中心点的对齐误差值取半数误差值
  56. const deviation = pindex === 2 ? this.deviation / 2 : this.deviation;
  57. const curPoint = curPoints[pindex];
  58. if (
  59. curPoint.x <= point.x + deviation &&
  60. curPoint.x >= point.x - deviation
  61. ) {
  62. if (!yMaybeLines[yPointTypes[pindex]])
  63. yMaybeLines[yPointTypes[pindex]] = [];
  64. yMaybeLines[yPointTypes[pindex]].push({
  65. pindex,
  66. x: point.x,
  67. y: Math.min(curPoint.y, point.y),
  68. h: Math.abs(curPoint.y - point.y),
  69. offset: Math.abs(curPoint.x - point.x)
  70. });
  71. }
  72. if (
  73. curPoint.y <= point.y + deviation &&
  74. curPoint.y >= point.y - deviation
  75. ) {
  76. if (!xMaybeLines[xPointTypes[pindex]])
  77. xMaybeLines[xPointTypes[pindex]] = [];
  78. xMaybeLines[xPointTypes[pindex]].push({
  79. pindex,
  80. x: Math.min(curPoint.x, point.x),
  81. y: point.y,
  82. w: Math.abs(curPoint.x - point.x),
  83. offset: Math.abs(curPoint.y - point.y)
  84. });
  85. }
  86. });
  87. });
  88. // 过滤误差过大的辅助线,即取误差最小的辅助线
  89. let yLines = [];
  90. Object.values(yMaybeLines).forEach(lines => {
  91. lines.sort((a, b) => a.offset - b.offset);
  92. const validX = lines[0].x;
  93. const validLines = lines.filter(line => line.x === validX);
  94. validLines.forEach(line => {
  95. const pindex = line.pindex;
  96. if (!fitPoints[pindex]) fitPoints[pindex] = {};
  97. fitPoints[pindex].x = validX;
  98. });
  99. yLines = [...yLines, ...validLines];
  100. });
  101. let xLines = [];
  102. Object.values(xMaybeLines).forEach(lines => {
  103. lines.sort((a, b) => a.offset - b.offset);
  104. const validY = lines[0].y;
  105. const validLines = lines.filter(line => line.y === validY);
  106. validLines.forEach(line => {
  107. const pindex = line.pindex;
  108. if (!fitPoints[pindex]) fitPoints[pindex] = {};
  109. fitPoints[pindex].y = validY;
  110. });
  111. xLines = [...xLines, ...validLines];
  112. });
  113. // 合并辅助线
  114. let yLinesMap = {};
  115. yLines.forEach(line => {
  116. if (!yLinesMap[line.x]) yLinesMap[line.x] = [];
  117. yLinesMap[line.x].push(line);
  118. });
  119. this.yLines = Object.values(yLinesMap).map(lines => {
  120. const lowH = this.getMax(lines.map(l => l.y + l.h));
  121. const topY = this.getMin(lines.map(l => l.y));
  122. return {
  123. left: lines[0].x + "px",
  124. top: topY + "px",
  125. height: lowH - topY + "px"
  126. };
  127. });
  128. let xLinesMap = {};
  129. xLines.forEach(line => {
  130. if (!xLinesMap[line.y]) xLinesMap[line.y] = [];
  131. xLinesMap[line.y].push(line);
  132. });
  133. this.xLines = Object.values(xLinesMap).map(lines => {
  134. const rightW = this.getMax(lines.map(l => l.x + l.w));
  135. const leftX = this.getMin(lines.map(l => l.x));
  136. return {
  137. left: leftX + "px",
  138. top: lines[0].y + "px",
  139. width: rightW - leftX + "px"
  140. };
  141. });
  142. // 计算自动贴合后的坐标点
  143. if (actionType === "move") {
  144. // 移动模式时,算偏移量
  145. // 按照getPoints中设置的点顺序权重进行计算
  146. // 只要获得结果,便停止计算
  147. let xOffset = null,
  148. yOffset = null;
  149. curPoints.forEach((point, pindex) => {
  150. const fitPoint = fitPoints[pindex] || {};
  151. if (xOffset === null && fitPoint.x) {
  152. xOffset = fitPoint.x - point.x;
  153. }
  154. if (yOffset === null && fitPoint.y) {
  155. yOffset = fitPoint.y - point.y;
  156. }
  157. });
  158. return {
  159. x: curElement.x + xOffset,
  160. y: curElement.y + yOffset,
  161. w: curElement.w,
  162. h: curElement.h
  163. };
  164. } else {
  165. // 变形模式时,算贴合点
  166. const newPoints = curPoints.map((point, pindex) => {
  167. const fitPoint = fitPoints[pindex] || {};
  168. return {
  169. x: Object.prototype.hasOwnProperty.call(fitPoint, "x")
  170. ? fitPoint.x
  171. : point.x,
  172. y: Object.prototype.hasOwnProperty.call(fitPoint, "y")
  173. ? fitPoint.y
  174. : point.y
  175. };
  176. });
  177. return {
  178. x: newPoints[0].x,
  179. y: newPoints[0].y,
  180. w: newPoints[4].x - newPoints[0].x,
  181. h: newPoints[4].y - newPoints[0].y
  182. };
  183. }
  184. },
  185. clear() {
  186. this.xLines = [];
  187. this.yLines = [];
  188. }
  189. }
  190. };