use-order-element.ts 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import type { PPTElement } from '@/lib/types/slides';
  2. export function useOrderElement() {
  3. /**
  4. * Get the z-order range of grouped elements
  5. * @param elementList All elements on the page
  6. * @param combineElementList Grouped elements list
  7. */
  8. const getCombineElementLevelRange = (
  9. elementList: PPTElement[],
  10. combineElementList: PPTElement[],
  11. ) => {
  12. return {
  13. minLevel: elementList.findIndex((_element) => _element.id === combineElementList[0].id),
  14. maxLevel: elementList.findIndex(
  15. (_element) => _element.id === combineElementList[combineElementList.length - 1].id,
  16. ),
  17. };
  18. };
  19. /**
  20. * Move up one layer
  21. * @param elementList All elements on the page
  22. * @param element The element being operated on
  23. */
  24. const moveUpElement = (elementList: PPTElement[], element: PPTElement) => {
  25. const copyOfElementList: PPTElement[] = JSON.parse(JSON.stringify(elementList));
  26. // If the element is a group member, all group members must be moved together
  27. if (element.groupId) {
  28. // Get all group members and their z-order range
  29. const combineElementList = copyOfElementList.filter(
  30. (_element) => _element.groupId === element.groupId,
  31. );
  32. const { minLevel, maxLevel } = getCombineElementLevelRange(elementList, combineElementList);
  33. // Already at the top level, cannot move further
  34. if (maxLevel >= elementList.length - 1) return;
  35. const nextElement = copyOfElementList[maxLevel + 1];
  36. const movedElementList = copyOfElementList.splice(minLevel, combineElementList.length);
  37. if (nextElement.groupId) {
  38. const nextCombineElementList = copyOfElementList.filter(
  39. (_element) => _element.groupId === nextElement.groupId,
  40. );
  41. copyOfElementList.splice(minLevel + nextCombineElementList.length, 0, ...movedElementList);
  42. } else copyOfElementList.splice(minLevel + 1, 0, ...movedElementList);
  43. }
  44. // If the element is not a group member
  45. else {
  46. // Get the element's z-level in the list
  47. const level = elementList.findIndex((item) => item.id === element.id);
  48. // Already at the top level, cannot move further
  49. if (level === elementList.length - 1) return;
  50. // Get the element above, remove this element from the list (cache removed element).
  51. // If the above element is in a group, insert above that group.
  52. // If the above element is not in any group, insert above that element.
  53. const nextElement = copyOfElementList[level + 1];
  54. const [movedElement] = copyOfElementList.splice(level, 1);
  55. if (nextElement.groupId) {
  56. const combineElementList = copyOfElementList.filter(
  57. (_element) => _element.groupId === nextElement.groupId,
  58. );
  59. copyOfElementList.splice(level + combineElementList.length, 0, movedElement);
  60. } else copyOfElementList.splice(level + 1, 0, movedElement);
  61. }
  62. return copyOfElementList;
  63. };
  64. /**
  65. * Move down one layer, same approach as move up
  66. * @param elementList All elements on the page
  67. * @param element The element being operated on
  68. */
  69. const moveDownElement = (elementList: PPTElement[], element: PPTElement) => {
  70. const copyOfElementList: PPTElement[] = JSON.parse(JSON.stringify(elementList));
  71. if (element.groupId) {
  72. const combineElementList = copyOfElementList.filter(
  73. (_element) => _element.groupId === element.groupId,
  74. );
  75. const { minLevel } = getCombineElementLevelRange(elementList, combineElementList);
  76. if (minLevel === 0) return;
  77. const prevElement = copyOfElementList[minLevel - 1];
  78. const movedElementList = copyOfElementList.splice(minLevel, combineElementList.length);
  79. if (prevElement.groupId) {
  80. const prevCombineElementList = copyOfElementList.filter(
  81. (_element) => _element.groupId === prevElement.groupId,
  82. );
  83. copyOfElementList.splice(minLevel - prevCombineElementList.length, 0, ...movedElementList);
  84. } else copyOfElementList.splice(minLevel - 1, 0, ...movedElementList);
  85. } else {
  86. const level = elementList.findIndex((item) => item.id === element.id);
  87. if (level === 0) return;
  88. const prevElement = copyOfElementList[level - 1];
  89. const movedElement = copyOfElementList.splice(level, 1)[0];
  90. if (prevElement.groupId) {
  91. const combineElementList = copyOfElementList.filter(
  92. (_element) => _element.groupId === prevElement.groupId,
  93. );
  94. copyOfElementList.splice(level - combineElementList.length, 0, movedElement);
  95. } else copyOfElementList.splice(level - 1, 0, movedElement);
  96. }
  97. return copyOfElementList;
  98. };
  99. /**
  100. * Bring to front
  101. * @param elementList All elements on the page
  102. * @param element The element being operated on
  103. */
  104. const moveTopElement = (elementList: PPTElement[], element: PPTElement) => {
  105. const copyOfElementList: PPTElement[] = JSON.parse(JSON.stringify(elementList));
  106. // If the element is a group member, all group members must be moved together
  107. if (element.groupId) {
  108. // Get all group members and their z-order range
  109. const combineElementList = copyOfElementList.filter(
  110. (_element) => _element.groupId === element.groupId,
  111. );
  112. const { minLevel, maxLevel } = getCombineElementLevelRange(elementList, combineElementList);
  113. // Already at the top level, cannot move further
  114. if (maxLevel === elementList.length - 1) return null;
  115. // Remove the group from the list, then append removed elements to the top
  116. const movedElementList = copyOfElementList.splice(minLevel, combineElementList.length);
  117. copyOfElementList.push(...movedElementList);
  118. }
  119. // If the element is not a group member
  120. else {
  121. // Get the element's z-level in the list
  122. const level = elementList.findIndex((item) => item.id === element.id);
  123. // Already at the top level, cannot move further
  124. if (level === elementList.length - 1) return null;
  125. // Remove the element from the list, then append it to the top
  126. copyOfElementList.splice(level, 1);
  127. copyOfElementList.push(element);
  128. }
  129. return copyOfElementList;
  130. };
  131. /**
  132. * Send to back, same approach as bring to front
  133. * @param elementList All elements on the page
  134. * @param element The element being operated on
  135. */
  136. const moveBottomElement = (elementList: PPTElement[], element: PPTElement) => {
  137. const copyOfElementList: PPTElement[] = JSON.parse(JSON.stringify(elementList));
  138. if (element.groupId) {
  139. const combineElementList = copyOfElementList.filter(
  140. (_element) => _element.groupId === element.groupId,
  141. );
  142. const { minLevel } = getCombineElementLevelRange(elementList, combineElementList);
  143. if (minLevel === 0) return;
  144. const movedElementList = copyOfElementList.splice(minLevel, combineElementList.length);
  145. copyOfElementList.unshift(...movedElementList);
  146. } else {
  147. const level = elementList.findIndex((item) => item.id === element.id);
  148. if (level === 0) return;
  149. copyOfElementList.splice(level, 1);
  150. copyOfElementList.unshift(element);
  151. }
  152. return copyOfElementList;
  153. };
  154. return {
  155. moveUpElement,
  156. moveDownElement,
  157. moveTopElement,
  158. moveBottomElement,
  159. };
  160. }