Stats.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import React from "react";
  2. import { getCommonBounds } from "../element/bounds";
  3. import { NonDeletedExcalidrawElement } from "../element/types";
  4. import { t } from "../i18n";
  5. import { useIsMobile } from "../components/App";
  6. import { getTargetElements } from "../scene";
  7. import { AppState, ExcalidrawProps } from "../types";
  8. import { close } from "./icons";
  9. import { Island } from "./Island";
  10. import "./Stats.scss";
  11. export const Stats = (props: {
  12. appState: AppState;
  13. setAppState: React.Component<any, AppState>["setState"];
  14. elements: readonly NonDeletedExcalidrawElement[];
  15. onClose: () => void;
  16. renderCustomStats: ExcalidrawProps["renderCustomStats"];
  17. }) => {
  18. const isMobile = useIsMobile();
  19. const boundingBox = getCommonBounds(props.elements);
  20. const selectedElements = getTargetElements(props.elements, props.appState);
  21. const selectedBoundingBox = getCommonBounds(selectedElements);
  22. if (isMobile && props.appState.openMenu) {
  23. return null;
  24. }
  25. return (
  26. <div className="Stats">
  27. <Island padding={2}>
  28. <div className="close" onClick={props.onClose}>
  29. {close}
  30. </div>
  31. <h3>{t("stats.title")}</h3>
  32. <table>
  33. <tbody>
  34. <tr>
  35. <th colSpan={2}>{t("stats.scene")}</th>
  36. </tr>
  37. <tr>
  38. <td>{t("stats.elements")}</td>
  39. <td>{props.elements.length}</td>
  40. </tr>
  41. <tr>
  42. <td>{t("stats.width")}</td>
  43. <td>{Math.round(boundingBox[2]) - Math.round(boundingBox[0])}</td>
  44. </tr>
  45. <tr>
  46. <td>{t("stats.height")}</td>
  47. <td>{Math.round(boundingBox[3]) - Math.round(boundingBox[1])}</td>
  48. </tr>
  49. {selectedElements.length === 1 && (
  50. <tr>
  51. <th colSpan={2}>{t("stats.element")}</th>
  52. </tr>
  53. )}
  54. {selectedElements.length > 1 && (
  55. <>
  56. <tr>
  57. <th colSpan={2}>{t("stats.selected")}</th>
  58. </tr>
  59. <tr>
  60. <td>{t("stats.elements")}</td>
  61. <td>{selectedElements.length}</td>
  62. </tr>
  63. </>
  64. )}
  65. {selectedElements.length > 0 && (
  66. <>
  67. <tr>
  68. <td>{"x"}</td>
  69. <td>{Math.round(selectedBoundingBox[0])}</td>
  70. </tr>
  71. <tr>
  72. <td>{"y"}</td>
  73. <td>{Math.round(selectedBoundingBox[1])}</td>
  74. </tr>
  75. <tr>
  76. <td>{t("stats.width")}</td>
  77. <td>
  78. {Math.round(
  79. selectedBoundingBox[2] - selectedBoundingBox[0],
  80. )}
  81. </td>
  82. </tr>
  83. <tr>
  84. <td>{t("stats.height")}</td>
  85. <td>
  86. {Math.round(
  87. selectedBoundingBox[3] - selectedBoundingBox[1],
  88. )}
  89. </td>
  90. </tr>
  91. </>
  92. )}
  93. {selectedElements.length === 1 && (
  94. <tr>
  95. <td>{t("stats.angle")}</td>
  96. <td>
  97. {`${Math.round(
  98. (selectedElements[0].angle * 180) / Math.PI,
  99. )}°`}
  100. </td>
  101. </tr>
  102. )}
  103. {props.renderCustomStats?.(props.elements, props.appState)}
  104. </tbody>
  105. </table>
  106. </Island>
  107. </div>
  108. );
  109. };