renderElement.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import { ExcalidrawElement } from "../element/types";
  2. import { isTextElement } from "../element/typeChecks";
  3. import {
  4. getDiamondPoints,
  5. getArrowPoints,
  6. getLinePoints,
  7. } from "../element/bounds";
  8. import { RoughCanvas } from "roughjs/bin/canvas";
  9. import { Drawable } from "roughjs/bin/core";
  10. export function renderElement(
  11. element: ExcalidrawElement,
  12. rc: RoughCanvas,
  13. context: CanvasRenderingContext2D,
  14. ) {
  15. const generator = rc.generator;
  16. if (element.type === "selection") {
  17. const fillStyle = context.fillStyle;
  18. context.fillStyle = "rgba(0, 0, 255, 0.10)";
  19. context.fillRect(0, 0, element.width, element.height);
  20. context.fillStyle = fillStyle;
  21. } else if (element.type === "rectangle") {
  22. if (!element.shape) {
  23. element.shape = generator.rectangle(0, 0, element.width, element.height, {
  24. stroke: element.strokeColor,
  25. fill:
  26. element.backgroundColor === "transparent"
  27. ? undefined
  28. : element.backgroundColor,
  29. fillStyle: element.fillStyle,
  30. strokeWidth: element.strokeWidth,
  31. roughness: element.roughness,
  32. seed: element.seed,
  33. });
  34. }
  35. context.globalAlpha = element.opacity / 100;
  36. rc.draw(element.shape as Drawable);
  37. context.globalAlpha = 1;
  38. } else if (element.type === "diamond") {
  39. if (!element.shape) {
  40. const [
  41. topX,
  42. topY,
  43. rightX,
  44. rightY,
  45. bottomX,
  46. bottomY,
  47. leftX,
  48. leftY,
  49. ] = getDiamondPoints(element);
  50. element.shape = generator.polygon(
  51. [
  52. [topX, topY],
  53. [rightX, rightY],
  54. [bottomX, bottomY],
  55. [leftX, leftY],
  56. ],
  57. {
  58. stroke: element.strokeColor,
  59. fill:
  60. element.backgroundColor === "transparent"
  61. ? undefined
  62. : element.backgroundColor,
  63. fillStyle: element.fillStyle,
  64. strokeWidth: element.strokeWidth,
  65. roughness: element.roughness,
  66. seed: element.seed,
  67. },
  68. );
  69. }
  70. context.globalAlpha = element.opacity / 100;
  71. rc.draw(element.shape as Drawable);
  72. context.globalAlpha = 1;
  73. } else if (element.type === "ellipse") {
  74. if (!element.shape) {
  75. element.shape = generator.ellipse(
  76. element.width / 2,
  77. element.height / 2,
  78. element.width,
  79. element.height,
  80. {
  81. stroke: element.strokeColor,
  82. fill:
  83. element.backgroundColor === "transparent"
  84. ? undefined
  85. : element.backgroundColor,
  86. fillStyle: element.fillStyle,
  87. strokeWidth: element.strokeWidth,
  88. roughness: element.roughness,
  89. seed: element.seed,
  90. curveFitting: 1,
  91. },
  92. );
  93. }
  94. context.globalAlpha = element.opacity / 100;
  95. rc.draw(element.shape as Drawable);
  96. context.globalAlpha = 1;
  97. } else if (element.type === "arrow") {
  98. const [x1, y1, x2, y2, x3, y3, x4, y4] = getArrowPoints(element);
  99. const options = {
  100. stroke: element.strokeColor,
  101. strokeWidth: element.strokeWidth,
  102. roughness: element.roughness,
  103. seed: element.seed,
  104. };
  105. if (!element.shape) {
  106. element.shape = [
  107. // \
  108. generator.line(x3, y3, x2, y2, options),
  109. // -----
  110. generator.line(x1, y1, x2, y2, options),
  111. // /
  112. generator.line(x4, y4, x2, y2, options),
  113. ];
  114. }
  115. context.globalAlpha = element.opacity / 100;
  116. (element.shape as Drawable[]).forEach(shape => rc.draw(shape));
  117. context.globalAlpha = 1;
  118. return;
  119. } else if (element.type === "line") {
  120. const [x1, y1, x2, y2] = getLinePoints(element);
  121. const options = {
  122. stroke: element.strokeColor,
  123. strokeWidth: element.strokeWidth,
  124. roughness: element.roughness,
  125. seed: element.seed,
  126. };
  127. if (!element.shape) {
  128. element.shape = generator.line(x1, y1, x2, y2, options);
  129. }
  130. context.globalAlpha = element.opacity / 100;
  131. rc.draw(element.shape as Drawable);
  132. context.globalAlpha = 1;
  133. } else if (isTextElement(element)) {
  134. context.globalAlpha = element.opacity / 100;
  135. const font = context.font;
  136. context.font = element.font;
  137. const fillStyle = context.fillStyle;
  138. context.fillStyle = element.strokeColor;
  139. context.fillText(
  140. element.text,
  141. 0,
  142. element.baseline || element.actualBoundingBoxAscent || 0,
  143. );
  144. context.fillStyle = fillStyle;
  145. context.font = font;
  146. context.globalAlpha = 1;
  147. } else {
  148. throw new Error("Unimplemented type " + element.type);
  149. }
  150. }