renderScene.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import { RoughCanvas } from "roughjs/bin/canvas";
  2. import { ExcalidrawElement } from "../element/types";
  3. import { getElementAbsoluteCoords, handlerRectangles } from "../element";
  4. import { roundRect } from "./roundRect";
  5. import { SceneState } from "../scene/types";
  6. import {
  7. getScrollBars,
  8. SCROLLBAR_COLOR,
  9. SCROLLBAR_WIDTH
  10. } from "../scene/scrollbars";
  11. import { renderElement } from "./renderElement";
  12. export function renderScene(
  13. elements: readonly ExcalidrawElement[],
  14. rc: RoughCanvas,
  15. canvas: HTMLCanvasElement,
  16. sceneState: SceneState,
  17. // extra options, currently passed by export helper
  18. {
  19. offsetX,
  20. offsetY,
  21. renderScrollbars = true,
  22. renderSelection = true
  23. }: {
  24. offsetX?: number;
  25. offsetY?: number;
  26. renderScrollbars?: boolean;
  27. renderSelection?: boolean;
  28. } = {}
  29. ) {
  30. if (!canvas) return;
  31. const context = canvas.getContext("2d")!;
  32. const fillStyle = context.fillStyle;
  33. if (typeof sceneState.viewBackgroundColor === "string") {
  34. context.fillStyle = sceneState.viewBackgroundColor;
  35. context.fillRect(0, 0, canvas.width, canvas.height);
  36. } else {
  37. context.clearRect(0, 0, canvas.width, canvas.height);
  38. }
  39. context.fillStyle = fillStyle;
  40. sceneState = {
  41. ...sceneState,
  42. scrollX: typeof offsetX === "number" ? offsetX : sceneState.scrollX,
  43. scrollY: typeof offsetY === "number" ? offsetY : sceneState.scrollY
  44. };
  45. elements.forEach(element => {
  46. context.translate(
  47. element.x + sceneState.scrollX,
  48. element.y + sceneState.scrollY
  49. );
  50. renderElement(element, rc, context);
  51. context.translate(
  52. -element.x - sceneState.scrollX,
  53. -element.y - sceneState.scrollY
  54. );
  55. });
  56. if (renderSelection) {
  57. const selectedElements = elements.filter(el => el.isSelected);
  58. selectedElements.forEach(element => {
  59. const margin = 4;
  60. const [
  61. elementX1,
  62. elementY1,
  63. elementX2,
  64. elementY2
  65. ] = getElementAbsoluteCoords(element);
  66. const lineDash = context.getLineDash();
  67. context.setLineDash([8, 4]);
  68. context.strokeRect(
  69. elementX1 - margin + sceneState.scrollX,
  70. elementY1 - margin + sceneState.scrollY,
  71. elementX2 - elementX1 + margin * 2,
  72. elementY2 - elementY1 + margin * 2
  73. );
  74. context.setLineDash(lineDash);
  75. });
  76. if (selectedElements.length === 1 && selectedElements[0].type !== "text") {
  77. const handlers = handlerRectangles(selectedElements[0], sceneState);
  78. Object.values(handlers).forEach(handler => {
  79. context.strokeRect(handler[0], handler[1], handler[2], handler[3]);
  80. });
  81. }
  82. }
  83. if (renderScrollbars) {
  84. const scrollBars = getScrollBars(
  85. elements,
  86. context.canvas.width / window.devicePixelRatio,
  87. context.canvas.height / window.devicePixelRatio,
  88. sceneState.scrollX,
  89. sceneState.scrollY
  90. );
  91. const strokeStyle = context.strokeStyle;
  92. context.fillStyle = SCROLLBAR_COLOR;
  93. context.strokeStyle = "rgba(255,255,255,0.8)";
  94. [scrollBars.horizontal, scrollBars.vertical].forEach(scrollBar => {
  95. if (scrollBar)
  96. roundRect(
  97. context,
  98. scrollBar.x,
  99. scrollBar.y,
  100. scrollBar.width,
  101. scrollBar.height,
  102. SCROLLBAR_WIDTH / 2
  103. );
  104. });
  105. context.strokeStyle = strokeStyle;
  106. context.fillStyle = fillStyle;
  107. }
  108. }