useCollision.ts 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import { Pos } from '@/sdk'
  2. import { appEl } from '@/store'
  3. import { computed, Ref } from 'vue'
  4. export const collision = (
  5. $app: HTMLElement,
  6. $target: HTMLElement,
  7. pos: Pos,
  8. dire: Dire,
  9. $boxs: HTMLElement[]
  10. ) => {
  11. const appBound = $app.getBoundingClientRect()
  12. const left = $boxs[0] ? $boxs[0].getBoundingClientRect().right : appBound.left
  13. const right = $boxs[1]
  14. ? $boxs[1].getBoundingClientRect().left
  15. : appBound.width
  16. const bound = [left, appBound.top, right, appBound.bottom]
  17. const width = $target.offsetWidth
  18. const height = $target.offsetHeight
  19. const getX = (dire: 'left' | 'right') =>
  20. dire === 'left'
  21. ? pos.x - width < bound[0]
  22. ? bound[0] + width
  23. : pos.x > bound[2]
  24. ? bound[2]
  25. : pos.x
  26. : pos.x < bound[0]
  27. ? bound[0]
  28. : pos.x + width > bound[2]
  29. ? bound[2] - width
  30. : pos.x
  31. const getY = (dire: 'top' | 'bottom') =>
  32. dire === 'top'
  33. ? pos.y - height < bound[1]
  34. ? bound[1] + height
  35. : pos.y > bound[3]
  36. ? bound[3]
  37. : pos.y
  38. : pos.y < bound[1]
  39. ? bound[1]
  40. : pos.y + height > bound[3]
  41. ? bound[3] - height
  42. : pos.y
  43. const dires = dire.split('-') as any
  44. return {
  45. x: getX(dires[0]),
  46. y: getY(dires[1])
  47. }
  48. }
  49. export const useCollision = (
  50. vmRef: Ref<HTMLElement>,
  51. pos: Ref<Pos>,
  52. dire: Dire = 'right-bottom'
  53. ) => {
  54. const $box = appEl.value.querySelector('.ui-editor-toolbox') as HTMLElement
  55. const $menu = appEl.value.querySelector('.ui-editor-menu') as HTMLElement
  56. const { x, y } = collision(appEl.value as any, vmRef.value, pos.value, dire, [
  57. $menu,
  58. $box
  59. ])
  60. return {
  61. left: x + 'px',
  62. top: y + 'px'
  63. }
  64. }
  65. type Dire = 'right-bottom' | 'left-bottom' | 'left-top' | 'right-top'
  66. export const useCollisionComputed = (
  67. vmRef: Ref<HTMLElement>,
  68. pos: Ref<Pos>,
  69. dire: Dire = 'right-bottom'
  70. ) => {
  71. return computed(() => {
  72. if (vmRef.value && pos.value) {
  73. return useCollision(vmRef, pos, dire)
  74. }
  75. })
  76. }