element.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import { PPTElement } from '@/types/slides'
  2. // 获取矩形旋转后在画布中的位置范围
  3. interface RotatedElementData {
  4. left: number;
  5. top: number;
  6. width: number;
  7. height: number;
  8. rotate: number;
  9. }
  10. export const getRectRotatedRange = (element: RotatedElementData) => {
  11. const { left, top, width, height, rotate = 0 } = element
  12. const radius = Math.sqrt( Math.pow(width, 2) + Math.pow(height, 2) ) / 2
  13. const auxiliaryAngle = Math.atan(height / width) * 180 / Math.PI
  14. const tlbraRadian = (180 - rotate - auxiliaryAngle) * Math.PI / 180
  15. const trblaRadian = (auxiliaryAngle - rotate) * Math.PI / 180
  16. const halfWidth = width / 2
  17. const halfHeight = height / 2
  18. const middleLeft = left + halfWidth
  19. const middleTop = top + halfHeight
  20. const xAxis = [
  21. middleLeft + radius * Math.cos(tlbraRadian),
  22. middleLeft + radius * Math.cos(trblaRadian),
  23. middleLeft - radius * Math.cos(tlbraRadian),
  24. middleLeft - radius * Math.cos(trblaRadian),
  25. ]
  26. const yAxis = [
  27. middleTop - radius * Math.sin(tlbraRadian),
  28. middleTop - radius * Math.sin(trblaRadian),
  29. middleTop + radius * Math.sin(tlbraRadian),
  30. middleTop + radius * Math.sin(trblaRadian),
  31. ]
  32. return {
  33. xRange: [Math.min(...xAxis), Math.max(...xAxis)],
  34. yRange: [Math.min(...yAxis), Math.max(...yAxis)],
  35. }
  36. }
  37. // 获取元素在画布中的位置范围
  38. export const getElementRange = (element: PPTElement) => {
  39. let minX, maxX, minY, maxY
  40. if (element.type === 'line') {
  41. minX = element.left
  42. maxX = element.left + Math.max(element.start[0], element.end[0])
  43. minY = element.top
  44. maxY = element.top + Math.max(element.start[1], element.end[1])
  45. }
  46. else if ('rotate' in element && element.rotate) {
  47. const { left, top, width, height, rotate } = element
  48. const { xRange, yRange } = getRectRotatedRange({ left, top, width, height, rotate })
  49. minX = xRange[0]
  50. maxX = xRange[1]
  51. minY = yRange[0]
  52. maxY = yRange[1]
  53. }
  54. else {
  55. minX = element.left
  56. maxX = element.left + element.width
  57. minY = element.top
  58. maxY = element.top + element.height
  59. }
  60. return { minX, maxX, minY, maxY }
  61. }
  62. // 获取元素集合在画布中的位置范围
  63. export const getElementListRange = (elementList: PPTElement[]) => {
  64. const leftValues: number[] = []
  65. const topValues: number[] = []
  66. const rightValues: number[] = []
  67. const bottomValues: number[] = []
  68. elementList.forEach(element => {
  69. const { minX, maxX, minY, maxY } = getElementRange(element)
  70. leftValues.push(minX)
  71. topValues.push(minY)
  72. rightValues.push(maxX)
  73. bottomValues.push(maxY)
  74. })
  75. const minX = Math.min(...leftValues)
  76. const maxX = Math.max(...rightValues)
  77. const minY = Math.min(...topValues)
  78. const maxY = Math.max(...bottomValues)
  79. return { minX, maxX, minY, maxY }
  80. }
  81. export interface AlignLine {
  82. value: number;
  83. range: [number, number];
  84. }
  85. // 对齐参考线去重,对于相同位置的多条参考线,取长度范围的最小值和最大值,并基于此范围将多条参考线合并为一条
  86. export const uniqAlignLines = (lines: AlignLine[]) => {
  87. const uniqLines: AlignLine[] = []
  88. lines.forEach(line => {
  89. const index = uniqLines.findIndex(_line => _line.value === line.value)
  90. if (index === -1) uniqLines.push(line)
  91. else {
  92. const uniqLine = uniqLines[index]
  93. const rangeMin = Math.min(uniqLine.range[0], line.range[0])
  94. const rangeMax = Math.max(uniqLine.range[1], line.range[1])
  95. const range: [number, number] = [rangeMin, rangeMax]
  96. const _line = { value: line.value, range }
  97. uniqLines[index] = _line
  98. }
  99. })
  100. return uniqLines
  101. }