comparisons.ts 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import {
  2. ExcalidrawElement,
  3. ExcalidrawTextContainer,
  4. NonDeletedExcalidrawElement,
  5. } from "../element/types";
  6. import { getElementAbsoluteCoords } from "../element";
  7. import { isTextBindableContainer } from "../element/typeChecks";
  8. export const hasBackground = (type: string) =>
  9. type === "rectangle" ||
  10. type === "ellipse" ||
  11. type === "diamond" ||
  12. type === "line" ||
  13. type === "freedraw";
  14. export const hasStrokeColor = (type: string) => type !== "image";
  15. export const hasStrokeWidth = (type: string) =>
  16. type === "rectangle" ||
  17. type === "ellipse" ||
  18. type === "diamond" ||
  19. type === "freedraw" ||
  20. type === "arrow" ||
  21. type === "line";
  22. export const hasStrokeStyle = (type: string) =>
  23. type === "rectangle" ||
  24. type === "ellipse" ||
  25. type === "diamond" ||
  26. type === "arrow" ||
  27. type === "line";
  28. export const canChangeSharpness = (type: string) =>
  29. type === "rectangle" ||
  30. type === "arrow" ||
  31. type === "line" ||
  32. type === "diamond";
  33. export const hasText = (type: string) => type === "text";
  34. export const canHaveArrowheads = (type: string) => type === "arrow";
  35. export const getElementAtPosition = (
  36. elements: readonly NonDeletedExcalidrawElement[],
  37. isAtPositionFn: (element: NonDeletedExcalidrawElement) => boolean,
  38. ) => {
  39. let hitElement = null;
  40. // We need to to hit testing from front (end of the array) to back (beginning of the array)
  41. // because array is ordered from lower z-index to highest and we want element z-index
  42. // with higher z-index
  43. for (let index = elements.length - 1; index >= 0; --index) {
  44. const element = elements[index];
  45. if (element.isDeleted) {
  46. continue;
  47. }
  48. if (isAtPositionFn(element)) {
  49. hitElement = element;
  50. break;
  51. }
  52. }
  53. return hitElement;
  54. };
  55. export const getElementsAtPosition = (
  56. elements: readonly NonDeletedExcalidrawElement[],
  57. isAtPositionFn: (element: NonDeletedExcalidrawElement) => boolean,
  58. ) => {
  59. // The parameter elements comes ordered from lower z-index to higher.
  60. // We want to preserve that order on the returned array.
  61. return elements.filter(
  62. (element) => !element.isDeleted && isAtPositionFn(element),
  63. );
  64. };
  65. export const getTextBindableContainerAtPosition = (
  66. elements: readonly ExcalidrawElement[],
  67. x: number,
  68. y: number,
  69. ): ExcalidrawTextContainer | null => {
  70. let hitElement = null;
  71. // We need to to hit testing from front (end of the array) to back (beginning of the array)
  72. for (let index = elements.length - 1; index >= 0; --index) {
  73. if (elements[index].isDeleted) {
  74. continue;
  75. }
  76. const [x1, y1, x2, y2] = getElementAbsoluteCoords(elements[index]);
  77. if (x1 < x && x < x2 && y1 < y && y < y2) {
  78. hitElement = elements[index];
  79. break;
  80. }
  81. }
  82. return isTextBindableContainer(hitElement) ? hitElement : null;
  83. };