2025-03-12 22:23:31 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import rough from "roughjs/bin/rough";
							 | 
						
					
						
							
								
									
										
										
										
											2025-03-26 22:24:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import { getStroke } from "perfect-freehand";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import { isRightAngleRads } from "@excalidraw/math";
							 | 
						
					
						
							
								
									
										
										
										
											2025-03-12 22:23:31 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  BOUND_TEXT_PADDING,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  DEFAULT_REDUCED_GLOBAL_ALPHA,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  ELEMENT_READY_TO_ERASE_OPACITY,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  FRAME_STYLE,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  MIME_TYPES,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  THEME,
							 | 
						
					
						
							
								
									
										
										
										
											2025-03-26 22:24:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  distance,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  getFontString,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  isRTL,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  getVerticalOffset,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								} from "@excalidraw/common";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import type {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  AppState,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  StaticCanvasAppState,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  Zoom,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  InteractiveCanvasAppState,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  ElementsPendingErasure,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  PendingExcalidrawElements,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  NormalizedZoomValue,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								} from "@excalidraw/excalidraw/types";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import type {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  StaticCanvasRenderConfig,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  RenderableElementsMap,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  InteractiveCanvasRenderConfig,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								} from "@excalidraw/excalidraw/scene/types";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import { getElementAbsoluteCoords } from "./bounds";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import { getUncroppedImageElement } from "./cropElement";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import { LinearElementEditor } from "./linearElementEditor";
							 | 
						
					
						
							
								
									
										
										
										
											2025-03-12 22:23:31 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  getBoundTextElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  getContainerCoords,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  getContainerElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  getBoundTextMaxHeight,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  getBoundTextMaxWidth,
							 | 
						
					
						
							
								
									
										
										
										
											2025-03-26 22:24:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								} from "./textElement";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import { getLineHeightInPx } from "./textMeasurements";
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  isTextElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  isLinearElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  isFreeDrawElement,
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-22 04:05:48 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  isInitializedImageElement,
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 23:33:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  isArrowElement,
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-03 20:31:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  hasBoundTextElement,
							 | 
						
					
						
							
								
									
										
										
										
											2023-11-24 06:07:53 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  isMagicFrameElement,
							 | 
						
					
						
							
								
									
										
										
										
											2024-10-22 04:26:52 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  isImageElement,
							 | 
						
					
						
							
								
									
										
										
										
											2025-03-26 22:24:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								} from "./typeChecks";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import { getContainingFrame } from "./frame";
							 | 
						
					
						
							
								
									
										
										
										
											2025-06-13 03:08:37 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								import { getCornerRadius } from "./utils";
							 | 
						
					
						
							
								
									
										
										
										
											2025-03-26 22:24:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2025-06-13 03:08:37 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								import { ShapeCache } from "./shape";
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-16 23:44:03 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2025-03-12 22:23:31 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import type {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  ExcalidrawElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  ExcalidrawTextElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  NonDeletedExcalidrawElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  ExcalidrawFreeDrawElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  ExcalidrawImageElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  ExcalidrawTextElementWithContainer,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  ExcalidrawFrameLikeElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  NonDeletedSceneElementsMap,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  ElementsMap,
							 | 
						
					
						
							
								
									
										
										
										
											2025-03-26 22:24:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								} from "./types";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2024-05-08 16:51:50 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import type { StrokeOptions } from "perfect-freehand";
							 | 
						
					
						
							
								
									
										
										
										
											2025-03-12 22:23:31 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import type { RoughCanvas } from "roughjs/bin/canvas";
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-05 01:49:15 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-20 22:31:51 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// using a stronger invert (100% vs our regular 93%) and saturate
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// as a temp hack to make images in dark theme look closer to original
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// color scheme (it's still not quite there and the colors look slightly
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// desatured, alas...)
							 | 
						
					
						
							
								
									
										
										
										
											2024-02-27 13:07:44 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								export const IMAGE_INVERT_FILTER =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  "invert(100%) hue-rotate(180deg) saturate(1.25)";
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-20 22:31:51 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-22 04:05:48 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								const isPendingImageElement = (
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  element: ExcalidrawElement,
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  renderConfig: StaticCanvasRenderConfig,
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-22 04:05:48 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								) =>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  isInitializedImageElement(element) &&
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-25 21:05:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  !renderConfig.imageCache.has(element.fileId);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								const shouldResetImageFilter = (
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  element: ExcalidrawElement,
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  renderConfig: StaticCanvasRenderConfig,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  appState: StaticCanvasAppState,
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-25 21:05:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								) => {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  return (
							 | 
						
					
						
							
								
									
										
										
										
											2024-04-08 22:46:24 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    appState.theme === THEME.DARK &&
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-25 21:05:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    isInitializedImageElement(element) &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    !isPendingImageElement(element, renderConfig) &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    renderConfig.imageCache.get(element.fileId)?.mimeType !== MIME_TYPES.svg
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-22 04:05:48 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2024-07-26 00:55:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								const getCanvasPadding = (element: ExcalidrawElement) => {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  switch (element.type) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "freedraw":
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      return element.strokeWidth * 12;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "text":
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      return element.fontSize / 2;
							 | 
						
					
						
							
								
									
										
										
										
											2025-07-23 16:49:56 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    case "arrow":
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      if (element.endArrowhead || element.endArrowhead) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return 40;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      return 20;
							 | 
						
					
						
							
								
									
										
										
										
											2024-07-26 00:55:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    default:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      return 20;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-11 23:00:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								export const getRenderOpacity = (
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  element: ExcalidrawElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  containingFrame: ExcalidrawFrameLikeElement | null,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  elementsPendingErasure: ElementsPendingErasure,
							 | 
						
					
						
							
								
									
										
										
										
											2024-08-09 03:43:15 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  pendingNodes: Readonly<PendingExcalidrawElements> | null,
							 | 
						
					
						
							
								
									
										
										
										
											2024-11-27 01:53:25 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  globalAlpha: number = 1,
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-11 23:00:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								) => {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // multiplying frame opacity with element opacity to combine them
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // (e.g. frame 50% and element 50% opacity should result in 25% opacity)
							 | 
						
					
						
							
								
									
										
										
										
											2024-11-27 01:53:25 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  let opacity =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    (((containingFrame?.opacity ?? 100) * element.opacity) / 10000) *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    globalAlpha;
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-11 23:00:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // if pending erasure, multiply again to combine further
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // (so that erasing always results in lower opacity than original)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  if (
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    elementsPendingErasure.has(element.id) ||
							 | 
						
					
						
							
								
									
										
										
										
											2024-08-09 03:43:15 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    (pendingNodes && pendingNodes.some((node) => node.id === element.id)) ||
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-11 23:00:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    (containingFrame && elementsPendingErasure.has(containingFrame.id))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  ) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    opacity *= ELEMENT_READY_TO_ERASE_OPACITY / 100;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  return opacity;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-09 01:20:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								export interface ExcalidrawElementWithCanvas {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  element: ExcalidrawElement | ExcalidrawTextElement;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  canvas: HTMLCanvasElement;
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  theme: AppState["theme"];
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-07 23:30:44 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  scale: number;
							 | 
						
					
						
							
								
									
										
										
										
											2024-07-23 13:47:32 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  angle: number;
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  zoomValue: AppState["zoom"]["value"];
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-09 01:20:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  canvasOffsetX: number;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  canvasOffsetY: number;
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 23:33:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  boundTextElementVersion: number | null;
							 | 
						
					
						
							
								
									
										
										
										
											2024-10-23 17:58:43 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  imageCrop: ExcalidrawImageElement["crop"] | null;
							 | 
						
					
						
							
								
									
										
										
										
											2023-06-15 00:42:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  containingFrameOpacity: number;
							 | 
						
					
						
							
								
									
										
										
										
											2024-07-23 13:47:32 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  boundTextCanvas: HTMLCanvasElement;
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-09 01:20:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-07 23:30:44 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								const cappedElementCanvasSize = (
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  element: NonDeletedExcalidrawElement,
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap (#7663)
* fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap
* lint
* fix
* use non deleted elements where possible
* use non deleted elements map in actions
* pass elementsMap instead of array to elementOverlapsWithFrame
* lint
* fix
* pass elementsMap to getElementsCorners
* pass elementsMap to getEligibleElementsForBinding
* pass elementsMap in bindOrUnbindSelectedElements and unbindLinearElements
* pass elementsMap in elementsAreInFrameBounds,elementOverlapsWithFrame,isCursorInFrame,getElementsInResizingFrame
* pass elementsMap in getElementsWithinSelection, getElementsCompletelyInFrame, isElementContainingFrame, getElementsInNewFrame
* pass elementsMap to getElementWithTransformHandleType
* pass elementsMap to getVisibleGaps, getMaximumGroups,getReferenceSnapPoints,snapDraggedElements
* lint
* pass elementsMap to bindTextToShapeAfterDuplication,bindLinearElementToElement,getTextBindableContainerAtPosition
* revert changes for bindTextToShapeAfterDuplication
											
										 
										
											2024-02-16 14:05:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  elementsMap: ElementsMap,
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-07 23:30:44 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  zoom: Zoom,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								): {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  width: number;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  height: number;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  scale: number;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								} => {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // these limits are ballpark, they depend on specific browsers and device.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // We've chosen lower limits to be safe. We might want to change these limits
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // based on browser/device type, if we get reports of low quality rendering
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // on zoom.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  //
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // ~ safari mobile canvas area limit
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const AREA_LIMIT = 16777216;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // ~ safari width/height limit based on developer.mozilla.org.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const WIDTH_HEIGHT_LIMIT = 32767;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const padding = getCanvasPadding(element);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap (#7663)
* fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap
* lint
* fix
* use non deleted elements where possible
* use non deleted elements map in actions
* pass elementsMap instead of array to elementOverlapsWithFrame
* lint
* fix
* pass elementsMap to getElementsCorners
* pass elementsMap to getEligibleElementsForBinding
* pass elementsMap in bindOrUnbindSelectedElements and unbindLinearElements
* pass elementsMap in elementsAreInFrameBounds,elementOverlapsWithFrame,isCursorInFrame,getElementsInResizingFrame
* pass elementsMap in getElementsWithinSelection, getElementsCompletelyInFrame, isElementContainingFrame, getElementsInNewFrame
* pass elementsMap to getElementWithTransformHandleType
* pass elementsMap to getVisibleGaps, getMaximumGroups,getReferenceSnapPoints,snapDraggedElements
* lint
* pass elementsMap to bindTextToShapeAfterDuplication,bindLinearElementToElement,getTextBindableContainerAtPosition
* revert changes for bindTextToShapeAfterDuplication
											
										 
										
											2024-02-16 14:05:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-07 23:30:44 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const elementWidth =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    isLinearElement(element) || isFreeDrawElement(element)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      ? distance(x1, x2)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      : element.width;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const elementHeight =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    isLinearElement(element) || isFreeDrawElement(element)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      ? distance(y1, y2)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      : element.height;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  let width = elementWidth * window.devicePixelRatio + padding * 2;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  let height = elementHeight * window.devicePixelRatio + padding * 2;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  let scale: number = zoom.value;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // rescale to ensure width and height is within limits
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  if (
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    width * scale > WIDTH_HEIGHT_LIMIT ||
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    height * scale > WIDTH_HEIGHT_LIMIT
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  ) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    scale = Math.min(WIDTH_HEIGHT_LIMIT / width, WIDTH_HEIGHT_LIMIT / height);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // rescale to ensure canvas area is within limits
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  if (width * height * scale * scale > AREA_LIMIT) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    scale = Math.sqrt(AREA_LIMIT / (width * height));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  width = Math.floor(width * scale);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  height = Math.floor(height * scale);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  return { width, height, scale };
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 21:21:37 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								const generateElementCanvas = (
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-09 00:49:52 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  element: NonDeletedExcalidrawElement,
							 | 
						
					
						
							
								
									
										
										
										
											2024-07-23 13:47:32 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  elementsMap: NonDeletedSceneElementsMap,
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-05 01:49:15 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  zoom: Zoom,
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  renderConfig: StaticCanvasRenderConfig,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  appState: StaticCanvasAppState,
							 | 
						
					
						
							
								
									
										
										
										
											2024-08-10 03:36:04 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								): ExcalidrawElementWithCanvas | null => {
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const canvas = document.createElement("canvas");
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-09 01:20:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const context = canvas.getContext("2d")!;
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const padding = getCanvasPadding(element);
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap (#7663)
* fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap
* lint
* fix
* use non deleted elements where possible
* use non deleted elements map in actions
* pass elementsMap instead of array to elementOverlapsWithFrame
* lint
* fix
* pass elementsMap to getElementsCorners
* pass elementsMap to getEligibleElementsForBinding
* pass elementsMap in bindOrUnbindSelectedElements and unbindLinearElements
* pass elementsMap in elementsAreInFrameBounds,elementOverlapsWithFrame,isCursorInFrame,getElementsInResizingFrame
* pass elementsMap in getElementsWithinSelection, getElementsCompletelyInFrame, isElementContainingFrame, getElementsInNewFrame
* pass elementsMap to getElementWithTransformHandleType
* pass elementsMap to getVisibleGaps, getMaximumGroups,getReferenceSnapPoints,snapDraggedElements
* lint
* pass elementsMap to bindTextToShapeAfterDuplication,bindLinearElementToElement,getTextBindableContainerAtPosition
* revert changes for bindTextToShapeAfterDuplication
											
										 
										
											2024-02-16 14:05:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const { width, height, scale } = cappedElementCanvasSize(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    element,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    elementsMap,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    zoom,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  );
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-07 23:30:44 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2024-08-10 03:36:04 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  if (!width || !height) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return null;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-07 23:30:44 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  canvas.width = width;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  canvas.height = height;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2024-07-26 00:55:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  let canvasOffsetX = -100;
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-09 01:20:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  let canvasOffsetY = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  if (isLinearElement(element) || isFreeDrawElement(element)) {
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap (#7663)
* fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap
* lint
* fix
* use non deleted elements where possible
* use non deleted elements map in actions
* pass elementsMap instead of array to elementOverlapsWithFrame
* lint
* fix
* pass elementsMap to getElementsCorners
* pass elementsMap to getEligibleElementsForBinding
* pass elementsMap in bindOrUnbindSelectedElements and unbindLinearElements
* pass elementsMap in elementsAreInFrameBounds,elementOverlapsWithFrame,isCursorInFrame,getElementsInResizingFrame
* pass elementsMap in getElementsWithinSelection, getElementsCompletelyInFrame, isElementContainingFrame, getElementsInNewFrame
* pass elementsMap to getElementWithTransformHandleType
* pass elementsMap to getVisibleGaps, getMaximumGroups,getReferenceSnapPoints,snapDraggedElements
* lint
* pass elementsMap to bindTextToShapeAfterDuplication,bindLinearElementToElement,getTextBindableContainerAtPosition
* revert changes for bindTextToShapeAfterDuplication
											
										 
										
											2024-02-16 14:05:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    const [x1, y1] = getElementAbsoluteCoords(element, elementsMap);
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-09 01:20:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    canvasOffsetX =
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      element.x > x1
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-07 23:30:44 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ? distance(element.x, x1) * window.devicePixelRatio * scale
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        : 0;
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-12 23:34:36 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-09 01:20:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    canvasOffsetY =
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      element.y > y1
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-07 23:30:44 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ? distance(element.y, y1) * window.devicePixelRatio * scale
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        : 0;
							 | 
						
					
						
							
								
									
										
										
										
											2020-12-12 23:34:36 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    context.translate(canvasOffsetX, canvasOffsetY);
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-07-14 19:29:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.save();
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-07 23:30:44 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.translate(padding * scale, padding * scale);
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-05 01:49:15 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.scale(
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-07 23:30:44 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    window.devicePixelRatio * scale,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    window.devicePixelRatio * scale,
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-05 01:49:15 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  );
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const rc = rough.canvas(canvas);
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-20 22:31:51 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // in dark theme, revert the image color filter
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  if (shouldResetImageFilter(element, renderConfig, appState)) {
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-20 22:31:51 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    context.filter = IMAGE_INVERT_FILTER;
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-22 04:05:48 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  drawElementOnCanvas(element, rc, context, renderConfig, appState);
							 | 
						
					
						
							
								
									
										
										
										
											2024-07-23 13:47:32 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-07-14 19:29:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.restore();
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-22 04:05:48 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2024-07-23 13:47:32 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const boundTextElement = getBoundTextElement(element, elementsMap);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const boundTextCanvas = document.createElement("canvas");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const boundTextCanvasContext = boundTextCanvas.getContext("2d")!;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  if (isArrowElement(element) && boundTextElement) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    // Take max dimensions of arrow canvas so that when canvas is rotated
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    // the arrow doesn't get clipped
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    const maxDim = Math.max(distance(x1, x2), distance(y1, y2));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    boundTextCanvas.width =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      maxDim * window.devicePixelRatio * scale + padding * scale * 10;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    boundTextCanvas.height =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      maxDim * window.devicePixelRatio * scale + padding * scale * 10;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    boundTextCanvasContext.translate(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      boundTextCanvas.width / 2,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      boundTextCanvas.height / 2,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    boundTextCanvasContext.rotate(element.angle);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    boundTextCanvasContext.drawImage(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      canvas!,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      -canvas.width / 2,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      -canvas.height / 2,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      canvas.width,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      canvas.height,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    const [, , , , boundTextCx, boundTextCy] = getElementAbsoluteCoords(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      boundTextElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      elementsMap,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    boundTextCanvasContext.rotate(-element.angle);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    const offsetX = (boundTextCanvas.width - canvas!.width) / 2;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    const offsetY = (boundTextCanvas.height - canvas!.height) / 2;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    const shiftX =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      boundTextCanvas.width / 2 -
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      (boundTextCx - x1) * window.devicePixelRatio * scale -
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      offsetX -
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      padding * scale;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    const shiftY =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      boundTextCanvas.height / 2 -
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      (boundTextCy - y1) * window.devicePixelRatio * scale -
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      offsetY -
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      padding * scale;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    boundTextCanvasContext.translate(-shiftX, -shiftY);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    // Clear the bound text area
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    boundTextCanvasContext.clearRect(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      -(boundTextElement.width / 2 + BOUND_TEXT_PADDING) *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        window.devicePixelRatio *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        scale,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      -(boundTextElement.height / 2 + BOUND_TEXT_PADDING) *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        window.devicePixelRatio *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        scale,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      (boundTextElement.width + BOUND_TEXT_PADDING * 2) *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        window.devicePixelRatio *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        scale,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      (boundTextElement.height + BOUND_TEXT_PADDING * 2) *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        window.devicePixelRatio *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        scale,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-05 01:49:15 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  return {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    element,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    canvas,
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    theme: appState.theme,
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-07 23:30:44 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    scale,
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-17 17:41:27 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    zoomValue: zoom.value,
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-05 01:49:15 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    canvasOffsetX,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    canvasOffsetY,
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-26 13:59:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    boundTextElementVersion:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      getBoundTextElement(element, elementsMap)?.version || null,
							 | 
						
					
						
							
								
									
										
										
										
											2024-02-21 19:04:20 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    containingFrameOpacity:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      getContainingFrame(element, elementsMap)?.opacity || 100,
							 | 
						
					
						
							
								
									
										
										
										
											2024-07-23 13:47:32 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    boundTextCanvas,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    angle: element.angle,
							 | 
						
					
						
							
								
									
										
										
										
											2024-10-23 17:58:43 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    imageCrop: isImageElement(element) ? element.crop : null,
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-05 01:49:15 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  };
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 21:21:37 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2025-05-14 22:01:43 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								export const DEFAULT_LINK_SIZE = 14;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								const IMAGE_PLACEHOLDER_IMG =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  typeof document !== "undefined"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    ? document.createElement("img")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    : ({ src: "" } as HTMLImageElement); // mock image element outside of browser
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-22 04:05:48 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								IMAGE_PLACEHOLDER_IMG.src = `data:${MIME_TYPES.svg},${encodeURIComponent(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  `<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="image" class="svg-inline--fa fa-image fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#888" d="M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM112 120c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56zM64 384h384V272l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L208 320l-55.515-55.515c-4.686-4.686-12.284-4.686-16.971 0L64 336v48z"></path></svg>`,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								)}`;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2025-05-14 22:01:43 +08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								const IMAGE_ERROR_PLACEHOLDER_IMG =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  typeof document !== "undefined"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    ? document.createElement("img")
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    : ({ src: "" } as HTMLImageElement); // mock image element outside of browser
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-22 04:05:48 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								IMAGE_ERROR_PLACEHOLDER_IMG.src = `data:${MIME_TYPES.svg},${encodeURIComponent(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  `<svg viewBox="0 0 668 668" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"><path d="M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48ZM112 120c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56ZM64 384h384V272l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L208 320l-55.515-55.515c-4.686-4.686-12.284-4.686-16.971 0L64 336v48Z" style="fill:#888;fill-rule:nonzero" transform="matrix(.81709 0 0 .81709 124.825 145.825)"/><path d="M256 8C119.034 8 8 119.033 8 256c0 136.967 111.034 248 248 248s248-111.034 248-248S392.967 8 256 8Zm130.108 117.892c65.448 65.448 70 165.481 20.677 235.637L150.47 105.216c70.204-49.356 170.226-44.735 235.638 20.676ZM125.892 386.108c-65.448-65.448-70-165.481-20.677-235.637L361.53 406.784c-70.203 49.356-170.226 44.736-235.638-20.676Z" style="fill:#888;fill-rule:nonzero" transform="matrix(.30366 0 0 .30366 506.822 60.065)"/></svg>`,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								)}`;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								const drawImagePlaceholder = (
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  element: ExcalidrawImageElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context: CanvasRenderingContext2D,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								) => {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.fillStyle = "#E7E7E7";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.fillRect(0, 0, element.width, element.height);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const imageMinWidthOrHeight = Math.min(element.width, element.height);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const size = Math.min(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    imageMinWidthOrHeight,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    Math.min(imageMinWidthOrHeight * 0.4, 100),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.drawImage(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    element.status === "error"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      ? IMAGE_ERROR_PLACEHOLDER_IMG
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      : IMAGE_PLACEHOLDER_IMG,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    element.width / 2 - size / 2,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    element.height / 2 - size / 2,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    size,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    size,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 21:21:37 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								const drawElementOnCanvas = (
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-09 00:49:52 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  element: NonDeletedExcalidrawElement,
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  rc: RoughCanvas,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context: CanvasRenderingContext2D,
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  renderConfig: StaticCanvasRenderConfig,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  appState: StaticCanvasAppState,
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 21:21:37 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								) => {
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  switch (element.type) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "rectangle":
							 | 
						
					
						
							
								
									
										
										
										
											2023-11-24 06:07:53 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "iframe":
							 | 
						
					
						
							
								
									
										
										
										
											2023-07-24 22:51:53 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "embeddable":
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "diamond":
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "ellipse": {
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-08 00:03:23 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      context.lineJoin = "round";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      context.lineCap = "round";
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      rc.draw(ShapeCache.get(element)!);
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      break;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "arrow":
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "line": {
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-08 00:03:23 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      context.lineJoin = "round";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      context.lineCap = "round";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      ShapeCache.get(element)!.forEach((shape) => {
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-14 23:04:33 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        rc.draw(shape);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      });
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      break;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "freedraw": {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      // Draw directly to canvas
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      context.save();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      context.fillStyle = element.strokeColor;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      const path = getFreeDrawPath2D(element) as Path2D;
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      const fillShape = ShapeCache.get(element);
							 | 
						
					
						
							
								
									
										
										
										
											2022-02-10 00:43:21 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      if (fillShape) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        rc.draw(fillShape);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      context.fillStyle = element.strokeColor;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      context.fill(path);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      context.restore();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      break;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-22 04:05:48 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "image": {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      const img = isInitializedImageElement(element)
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-25 21:05:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ? renderConfig.imageCache.get(element.fileId)?.image
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-22 04:05:48 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        : undefined;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      if (img != null && !(img instanceof Promise)) {
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-29 22:27:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (element.roundness && context.roundRect) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.beginPath();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.roundRect(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            0,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            0,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            element.width,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            element.height,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            getCornerRadius(Math.min(element.width, element.height), element),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.clip();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2024-10-22 04:26:52 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const { x, y, width, height } = element.crop
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          ? element.crop
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          : {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              x: 0,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              y: 0,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              width: img.naturalWidth,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              height: img.naturalHeight,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            };
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-22 04:05:48 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.drawImage(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          img,
							 | 
						
					
						
							
								
									
										
										
										
											2024-10-22 04:26:52 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          x,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          y,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          width,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          height,
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-22 04:05:48 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          0 /* hardcoded for the selection box*/,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          0,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          element.width,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          element.height,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      } else {
							 | 
						
					
						
							
								
									
										
										
										
											2024-05-07 22:52:51 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        drawImagePlaceholder(element, context);
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-22 04:05:48 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      break;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    default: {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      if (isTextElement(element)) {
							 | 
						
					
						
							
								
									
										
										
										
											2020-06-07 17:55:08 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const rtl = isRTL(element.text);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const shouldTemporarilyAttach = rtl && !context.canvas.isConnected;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (shouldTemporarilyAttach) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          // to correctly render RTL text mixed with LTR, we have to append it
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-06 01:06:18 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          // to the DOM
							 | 
						
					
						
							
								
									
										
										
										
											2020-06-07 17:55:08 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          document.body.appendChild(context.canvas);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.canvas.setAttribute("dir", rtl ? "rtl" : "ltr");
							 | 
						
					
						
							
								
									
										
										
										
											2021-07-14 19:29:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.save();
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-27 21:14:50 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.font = getFontString(element);
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.fillStyle = element.strokeColor;
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-09 04:00:27 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.textAlign = element.textAlign as CanvasTextAlign;
							 | 
						
					
						
							
								
									
										
										
										
											2020-06-07 17:55:08 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        // Canvas does not support multiline text by default
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const lines = element.text.replace(/\r\n?/g, "\n").split("\n");
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-22 14:02:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-09 04:00:27 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const horizontalOffset =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          element.textAlign === "center"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            ? element.width / 2
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            : element.textAlign === "right"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            ? element.width
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            : 0;
							 | 
						
					
						
							
								
									
										
										
										
											2024-03-06 03:33:27 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-22 14:02:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const lineHeightPx = getLineHeightInPx(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          element.fontSize,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          element.lineHeight,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        );
							 | 
						
					
						
							
								
									
										
										
										
											2024-03-06 03:33:27 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const verticalOffset = getVerticalOffset(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          element.fontFamily,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          element.fontSize,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          lineHeightPx,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-30 00:32:51 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        for (let index = 0; index < lines.length; index++) {
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-09 04:00:27 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.fillText(
							 | 
						
					
						
							
								
									
										
										
										
											2020-11-30 00:32:51 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            lines[index],
							 | 
						
					
						
							
								
									
										
										
										
											2020-06-07 17:55:08 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            horizontalOffset,
							 | 
						
					
						
							
								
									
										
										
										
											2024-03-06 03:33:27 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            index * lineHeightPx + verticalOffset,
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-09 04:00:27 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          );
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2021-07-14 19:29:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.restore();
							 | 
						
					
						
							
								
									
										
										
										
											2020-06-07 17:55:08 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (shouldTemporarilyAttach) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.canvas.remove();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      } else {
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-10 03:43:36 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        throw new Error(`Unimplemented type ${element.type}`);
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 21:21:37 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							
								
									
										
										
										
											2020-01-06 23:34:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-14 19:52:25 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								export const elementWithCanvasCache = new WeakMap<
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-09 01:20:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  ExcalidrawElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  ExcalidrawElementWithCanvas
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								>();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-06-09 23:36:25 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								const generateElementWithCanvas = (
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  element: NonDeletedExcalidrawElement,
							 | 
						
					
						
							
								
									
										
										
										
											2024-07-23 13:47:32 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  elementsMap: NonDeletedSceneElementsMap,
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  renderConfig: StaticCanvasRenderConfig,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  appState: StaticCanvasAppState,
							 | 
						
					
						
							
								
									
										
										
										
											2020-06-09 23:36:25 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								) => {
							 | 
						
					
						
							
								
									
										
										
										
											2025-03-26 22:24:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const zoom: Zoom = renderConfig
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    ? appState.zoom
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    : {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        value: 1 as NormalizedZoomValue,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      };
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-09 01:20:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const prevElementWithCanvas = elementWithCanvasCache.get(element);
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-29 07:59:36 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const shouldRegenerateBecauseZoom =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    prevElementWithCanvas &&
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-17 17:41:27 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    prevElementWithCanvas.zoomValue !== zoom.value &&
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    !appState?.shouldCacheIgnoreZoom;
							 | 
						
					
						
							
								
									
										
										
										
											2024-07-23 13:47:32 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const boundTextElement = getBoundTextElement(element, elementsMap);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const boundTextElementVersion = boundTextElement?.version || null;
							 | 
						
					
						
							
								
									
										
										
										
											2024-10-23 17:58:43 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const imageCrop = isImageElement(element) ? element.crop : null;
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-26 13:59:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2024-02-21 19:04:20 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const containingFrameOpacity =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    getContainingFrame(element, elementsMap)?.opacity || 100;
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-22 04:05:48 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  if (
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    !prevElementWithCanvas ||
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    shouldRegenerateBecauseZoom ||
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    prevElementWithCanvas.theme !== appState.theme ||
							 | 
						
					
						
							
								
									
										
										
										
											2023-06-15 00:42:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    prevElementWithCanvas.boundTextElementVersion !== boundTextElementVersion ||
							 | 
						
					
						
							
								
									
										
										
										
											2024-10-23 17:58:43 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    prevElementWithCanvas.imageCrop !== imageCrop ||
							 | 
						
					
						
							
								
									
										
										
										
											2024-07-23 13:47:32 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    prevElementWithCanvas.containingFrameOpacity !== containingFrameOpacity ||
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    // since we rotate the canvas when copying from cached canvas, we don't
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    // regenerate the cached canvas. But we need to in case of labels which are
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    // cached alongside the arrow, and we want the labels to remain unrotated
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    // with respect to the arrow.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    (isArrowElement(element) &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      boundTextElement &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      element.angle !== prevElementWithCanvas.angle)
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-22 04:05:48 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  ) {
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-25 21:05:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    const elementWithCanvas = generateElementCanvas(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      element,
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-26 13:59:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      elementsMap,
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-25 21:05:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      zoom,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      renderConfig,
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      appState,
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-25 21:05:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    );
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2024-08-10 03:36:04 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (!elementWithCanvas) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      return null;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-09 14:08:26 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    elementWithCanvasCache.set(element, elementWithCanvas);
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-09 14:08:26 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return elementWithCanvas;
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-09 01:20:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  return prevElementWithCanvas;
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 21:21:37 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 21:21:37 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								const drawElementFromCanvas = (
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-09 01:20:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  elementWithCanvas: ExcalidrawElementWithCanvas,
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context: CanvasRenderingContext2D,
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  renderConfig: StaticCanvasRenderConfig,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  appState: StaticCanvasAppState,
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-26 13:59:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  allElementsMap: NonDeletedSceneElementsMap,
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 21:21:37 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								) => {
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-02 16:40:26 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const element = elementWithCanvas.element;
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const padding = getCanvasPadding(element);
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-07 23:30:44 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const zoom = elementWithCanvas.scale;
							 | 
						
					
						
							
								
									
										
										
										
											2024-07-14 16:44:47 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, allElementsMap);
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const cx = ((x1 + x2) / 2 + appState.scrollX) * window.devicePixelRatio;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const cy = ((y1 + y2) / 2 + appState.scrollY) * window.devicePixelRatio;
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-22 04:05:48 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-07-14 19:29:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.save();
							 | 
						
					
						
							
								
									
										
										
										
											2023-01-08 23:22:04 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.scale(1 / window.devicePixelRatio, 1 / window.devicePixelRatio);
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-26 13:59:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const boundTextElement = getBoundTextElement(element, allElementsMap);
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 23:33:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  if (isArrowElement(element) && boundTextElement) {
							 | 
						
					
						
							
								
									
										
										
										
											2024-07-23 13:47:32 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    const offsetX =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      (elementWithCanvas.boundTextCanvas.width -
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        elementWithCanvas.canvas!.width) /
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      2;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    const offsetY =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      (elementWithCanvas.boundTextCanvas.height -
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        elementWithCanvas.canvas!.height) /
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      2;
							 | 
						
					
						
							
								
									
										
										
										
											2023-01-08 23:22:04 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    context.translate(cx, cy);
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 23:33:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    context.drawImage(
							 | 
						
					
						
							
								
									
										
										
										
											2024-07-23 13:47:32 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      elementWithCanvas.boundTextCanvas,
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 23:33:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      (-(x2 - x1) / 2) * window.devicePixelRatio - offsetX / zoom - padding,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      (-(y2 - y1) / 2) * window.devicePixelRatio - offsetY / zoom - padding,
							 | 
						
					
						
							
								
									
										
										
										
											2024-07-23 13:47:32 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      elementWithCanvas.boundTextCanvas.width / zoom,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      elementWithCanvas.boundTextCanvas.height / zoom,
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 23:33:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  } else {
							 | 
						
					
						
							
								
									
										
										
										
											2023-01-08 23:22:04 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    // we translate context to element center so that rotation and scale
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    // originates from the element center
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    context.translate(cx, cy);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    context.rotate(element.angle);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      "scale" in elementWithCanvas.element &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      !isPendingImageElement(element, renderConfig)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    ) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      context.scale(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        elementWithCanvas.element.scale[0],
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        elementWithCanvas.element.scale[1],
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 23:33:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-01-08 23:22:04 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    // revert afterwards we don't have account for it during drawing
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    context.translate(-cx, -cy);
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 23:33:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    context.drawImage(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      elementWithCanvas.canvas!,
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      (x1 + appState.scrollX) * window.devicePixelRatio -
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-07 23:30:44 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        (padding * elementWithCanvas.scale) / elementWithCanvas.scale,
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      (y1 + appState.scrollY) * window.devicePixelRatio -
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-07 23:30:44 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        (padding * elementWithCanvas.scale) / elementWithCanvas.scale,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      elementWithCanvas.canvas!.width / elementWithCanvas.scale,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      elementWithCanvas.canvas!.height / elementWithCanvas.scale,
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 23:33:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    );
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-03 20:31:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (
							 | 
						
					
						
							
								
									
										
										
										
											2023-07-28 02:20:11 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      import.meta.env.VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX ===
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-19 19:32:20 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        "true" &&
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-03 20:31:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      hasBoundTextElement(element)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    ) {
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-25 20:36:23 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      const textElement = getBoundTextElement(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        element,
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-26 13:59:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        allElementsMap,
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-25 20:36:23 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      ) as ExcalidrawTextElementWithContainer;
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-03 20:31:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      const coords = getContainerCoords(element);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      context.strokeStyle = "#c92a2a";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      context.lineWidth = 3;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      context.strokeRect(
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        (coords.x + appState.scrollX) * window.devicePixelRatio,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        (coords.y + appState.scrollY) * window.devicePixelRatio,
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-26 13:59:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        getBoundTextMaxWidth(element, textElement) * window.devicePixelRatio,
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-25 20:36:23 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        getBoundTextMaxHeight(element, textElement) * window.devicePixelRatio,
							 | 
						
					
						
							
								
									
										
										
										
											2023-03-03 20:31:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 23:33:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							
								
									
										
										
										
											2021-07-14 19:29:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.restore();
							 | 
						
					
						
							
								
									
										
										
										
											2020-06-07 17:55:08 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // Clear the nested element we appended to the DOM
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 21:21:37 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							
								
									
										
										
										
											2020-01-07 23:04:52 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								export const renderSelectionElement = (
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  element: NonDeletedExcalidrawElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context: CanvasRenderingContext2D,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  appState: InteractiveCanvasAppState,
							 | 
						
					
						
							
								
									
										
										
										
											2024-05-28 21:53:52 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  selectionColor: InteractiveCanvasRenderConfig["selectionColor"],
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								) => {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.save();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.translate(element.x + appState.scrollX, element.y + appState.scrollY);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.fillStyle = "rgba(0, 0, 200, 0.04)";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // render from 0.5px offset  to get 1px wide line
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // https://stackoverflow.com/questions/7530593/html5-canvas-and-line-width/7531540#7531540
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // TODO can be be improved by offseting to the negative when user selects
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // from right to left
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const offset = 0.5 / appState.zoom.value;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.fillRect(offset, offset, element.width, element.height);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.lineWidth = 1 / appState.zoom.value;
							 | 
						
					
						
							
								
									
										
										
										
											2024-05-28 21:53:52 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.strokeStyle = selectionColor;
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.strokeRect(offset, offset, element.width, element.height);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.restore();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 21:21:37 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								export const renderElement = (
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-09 00:49:52 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  element: NonDeletedExcalidrawElement,
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-22 07:23:02 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  elementsMap: RenderableElementsMap,
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-26 13:59:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  allElementsMap: NonDeletedSceneElementsMap,
							 | 
						
					
						
							
								
									
										
										
										
											2020-01-29 04:25:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  rc: RoughCanvas,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context: CanvasRenderingContext2D,
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  renderConfig: StaticCanvasRenderConfig,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  appState: StaticCanvasAppState,
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 21:21:37 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								) => {
							 | 
						
					
						
							
								
									
										
										
										
											2024-11-27 01:53:25 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const reduceAlphaForSelection =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    appState.openDialog?.name === "elementLinkSelector" &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    !appState.selectedElementIds[element.id] &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    !appState.hoveredElementIds[element.id];
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-11 23:00:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.globalAlpha = getRenderOpacity(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    element,
							 | 
						
					
						
							
								
									
										
										
										
											2024-02-21 19:04:20 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    getContainingFrame(element, elementsMap),
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-11 23:00:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    renderConfig.elementsPendingErasure,
							 | 
						
					
						
							
								
									
										
										
										
											2024-08-09 03:43:15 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    renderConfig.pendingFlowchartNodes,
							 | 
						
					
						
							
								
									
										
										
										
											2024-11-27 01:53:25 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    reduceAlphaForSelection ? DEFAULT_REDUCED_GLOBAL_ALPHA : 1,
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-11 23:00:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-01-29 04:25:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  switch (element.type) {
							 | 
						
					
						
							
								
									
										
										
										
											2023-11-24 06:07:53 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "magicframe":
							 | 
						
					
						
							
								
									
										
										
										
											2023-06-15 00:42:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "frame": {
							 | 
						
					
						
							
								
									
										
										
										
											2023-11-10 00:00:21 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      if (appState.frameRendering.enabled && appState.frameRendering.outline) {
							 | 
						
					
						
							
								
									
										
										
										
											2023-06-15 00:42:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.save();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.translate(
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          element.x + appState.scrollX,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          element.y + appState.scrollY,
							 | 
						
					
						
							
								
									
										
										
										
											2023-06-15 00:42:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.fillStyle = "rgba(0, 0, 200, 0.04)";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-11-10 00:00:21 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.lineWidth = FRAME_STYLE.strokeWidth / appState.zoom.value;
							 | 
						
					
						
							
								
									
										
										
										
											2023-06-15 00:42:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.strokeStyle = FRAME_STYLE.strokeColor;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-11-24 06:07:53 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        // TODO change later to only affect AI frames
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (isMagicFrameElement(element)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.strokeStyle =
							 | 
						
					
						
							
								
									
										
										
										
											2024-04-08 22:46:24 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            appState.theme === THEME.LIGHT ? "#7affd7" : "#1d8264";
							 | 
						
					
						
							
								
									
										
										
										
											2023-11-24 06:07:53 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-06-15 00:42:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (FRAME_STYLE.radius && context.roundRect) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.beginPath();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.roundRect(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            0,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            0,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            element.width,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            element.height,
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            FRAME_STYLE.radius / appState.zoom.value,
							 | 
						
					
						
							
								
									
										
										
										
											2023-06-15 00:42:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.stroke();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.closePath();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        } else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.strokeRect(0, 0, element.width, element.height);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.restore();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2020-01-29 04:25:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      break;
							 | 
						
					
						
							
								
									
										
										
										
											2020-01-12 08:00:00 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "freedraw": {
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-14 19:52:25 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      // TODO investigate if we can do this in situ. Right now we need to call
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      // beforehand because math helpers (such as getElementAbsoluteCoords)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      // rely on existing shapes
							 | 
						
					
						
							
								
									
										
										
										
											2023-12-06 23:00:00 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      ShapeCache.generateElementShape(element, null);
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-25 21:05:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      if (renderConfig.isExporting) {
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap (#7663)
* fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap
* lint
* fix
* use non deleted elements where possible
* use non deleted elements map in actions
* pass elementsMap instead of array to elementOverlapsWithFrame
* lint
* fix
* pass elementsMap to getElementsCorners
* pass elementsMap to getEligibleElementsForBinding
* pass elementsMap in bindOrUnbindSelectedElements and unbindLinearElements
* pass elementsMap in elementsAreInFrameBounds,elementOverlapsWithFrame,isCursorInFrame,getElementsInResizingFrame
* pass elementsMap in getElementsWithinSelection, getElementsCompletelyInFrame, isElementContainingFrame, getElementsInNewFrame
* pass elementsMap to getElementWithTransformHandleType
* pass elementsMap to getVisibleGaps, getMaximumGroups,getReferenceSnapPoints,snapDraggedElements
* lint
* pass elementsMap to bindTextToShapeAfterDuplication,bindLinearElementToElement,getTextBindableContainerAtPosition
* revert changes for bindTextToShapeAfterDuplication
											
										 
										
											2024-02-16 14:05:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const cx = (x1 + x2) / 2 + appState.scrollX;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const cy = (y1 + y2) / 2 + appState.scrollY;
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const shiftX = (x2 - x1) / 2 - (element.x - x1);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const shiftY = (y2 - y1) / 2 - (element.y - y1);
							 | 
						
					
						
							
								
									
										
										
										
											2021-07-14 19:29:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.save();
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.translate(cx, cy);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.rotate(element.angle);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.translate(-shiftX, -shiftY);
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        drawElementOnCanvas(element, rc, context, renderConfig, appState);
							 | 
						
					
						
							
								
									
										
										
										
											2021-07-14 19:29:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.restore();
							 | 
						
					
						
							
								
									
										
										
										
											2022-07-22 22:18:41 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      } else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const elementWithCanvas = generateElementWithCanvas(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          element,
							 | 
						
					
						
							
								
									
										
										
										
											2024-07-23 13:47:32 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          allElementsMap,
							 | 
						
					
						
							
								
									
										
										
										
											2022-07-22 22:18:41 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          renderConfig,
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          appState,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        );
							 | 
						
					
						
							
								
									
										
										
										
											2024-08-10 03:36:04 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (!elementWithCanvas) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        drawElementFromCanvas(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          elementWithCanvas,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          renderConfig,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          appState,
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-26 13:59:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          allElementsMap,
							 | 
						
					
						
							
								
									
										
										
										
											2022-07-22 22:18:41 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        );
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      break;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2020-01-29 04:25:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "rectangle":
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "diamond":
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "ellipse":
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "line":
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "arrow":
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-22 04:05:48 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "image":
							 | 
						
					
						
							
								
									
										
										
										
											2023-07-24 22:51:53 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "text":
							 | 
						
					
						
							
								
									
										
										
										
											2023-11-24 06:07:53 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "iframe":
							 | 
						
					
						
							
								
									
										
										
										
											2023-07-24 22:51:53 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    case "embeddable": {
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-14 19:52:25 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      // TODO investigate if we can do this in situ. Right now we need to call
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      // beforehand because math helpers (such as getElementAbsoluteCoords)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      // rely on existing shapes
							 | 
						
					
						
							
								
									
										
										
										
											2023-12-06 23:00:00 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      ShapeCache.generateElementShape(element, renderConfig);
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-25 21:05:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      if (renderConfig.isExporting) {
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap (#7663)
* fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap
* lint
* fix
* use non deleted elements where possible
* use non deleted elements map in actions
* pass elementsMap instead of array to elementOverlapsWithFrame
* lint
* fix
* pass elementsMap to getElementsCorners
* pass elementsMap to getEligibleElementsForBinding
* pass elementsMap in bindOrUnbindSelectedElements and unbindLinearElements
* pass elementsMap in elementsAreInFrameBounds,elementOverlapsWithFrame,isCursorInFrame,getElementsInResizingFrame
* pass elementsMap in getElementsWithinSelection, getElementsCompletelyInFrame, isElementContainingFrame, getElementsInNewFrame
* pass elementsMap to getElementWithTransformHandleType
* pass elementsMap to getVisibleGaps, getMaximumGroups,getReferenceSnapPoints,snapDraggedElements
* lint
* pass elementsMap to bindTextToShapeAfterDuplication,bindLinearElementToElement,getTextBindableContainerAtPosition
* revert changes for bindTextToShapeAfterDuplication
											
										 
										
											2024-02-16 14:05:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const cx = (x1 + x2) / 2 + appState.scrollX;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const cy = (y1 + y2) / 2 + appState.scrollY;
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 23:33:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        let shiftX = (x2 - x1) / 2 - (element.x - x1);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        let shiftY = (y2 - y1) / 2 - (element.y - y1);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (isTextElement(element)) {
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-22 07:23:02 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          const container = getContainerElement(element, elementsMap);
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 23:33:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          if (isArrowElement(container)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            const boundTextCoords =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              LinearElementEditor.getBoundTextElementPosition(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                container,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                element as ExcalidrawTextElementWithContainer,
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap (#7663)
* fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap
* lint
* fix
* use non deleted elements where possible
* use non deleted elements map in actions
* pass elementsMap instead of array to elementOverlapsWithFrame
* lint
* fix
* pass elementsMap to getElementsCorners
* pass elementsMap to getEligibleElementsForBinding
* pass elementsMap in bindOrUnbindSelectedElements and unbindLinearElements
* pass elementsMap in elementsAreInFrameBounds,elementOverlapsWithFrame,isCursorInFrame,getElementsInResizingFrame
* pass elementsMap in getElementsWithinSelection, getElementsCompletelyInFrame, isElementContainingFrame, getElementsInNewFrame
* pass elementsMap to getElementWithTransformHandleType
* pass elementsMap to getVisibleGaps, getMaximumGroups,getReferenceSnapPoints,snapDraggedElements
* lint
* pass elementsMap to bindTextToShapeAfterDuplication,bindLinearElementToElement,getTextBindableContainerAtPosition
* revert changes for bindTextToShapeAfterDuplication
											
										 
										
											2024-02-16 14:05:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                elementsMap,
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 23:33:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            shiftX = (x2 - x1) / 2 - (boundTextCoords.x - x1);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            shiftY = (y2 - y1) / 2 - (boundTextCoords.y - y1);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2021-07-14 19:29:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.save();
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-02 16:40:26 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.translate(cx, cy);
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-25 21:05:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (shouldResetImageFilter(element, renderConfig, appState)) {
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-25 21:05:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.filter = "none";
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-26 13:59:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const boundTextElement = getBoundTextElement(element, elementsMap);
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 23:33:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (isArrowElement(element) && boundTextElement) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          const tempCanvas = document.createElement("canvas");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          const tempCanvasContext = tempCanvas.getContext("2d")!;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          // Take max dimensions of arrow canvas so that when canvas is rotated
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          // the arrow doesn't get clipped
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          const maxDim = Math.max(distance(x1, x2), distance(y1, y2));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          const padding = getCanvasPadding(element);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          tempCanvas.width =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            maxDim * appState.exportScale + padding * 10 * appState.exportScale;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          tempCanvas.height =
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            maxDim * appState.exportScale + padding * 10 * appState.exportScale;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          tempCanvasContext.translate(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            tempCanvas.width / 2,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            tempCanvas.height / 2,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          tempCanvasContext.scale(appState.exportScale, appState.exportScale);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          // Shift the canvas to left most point of the arrow
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          shiftX = element.width / 2 - (element.x - x1);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          shiftY = element.height / 2 - (element.y - y1);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          tempCanvasContext.rotate(element.angle);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          const tempRc = rough.canvas(tempCanvas);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          tempCanvasContext.translate(-shiftX, -shiftY);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          drawElementOnCanvas(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            element,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            tempRc,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            tempCanvasContext,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            renderConfig,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            appState,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          );
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 23:33:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          tempCanvasContext.translate(shiftX, shiftY);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          tempCanvasContext.rotate(-element.angle);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          // Shift the canvas to center of bound text
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap (#7663)
* fix: remove scene from getElementAbsoluteCoords and dependent functions and use elementsMap
* lint
* fix
* use non deleted elements where possible
* use non deleted elements map in actions
* pass elementsMap instead of array to elementOverlapsWithFrame
* lint
* fix
* pass elementsMap to getElementsCorners
* pass elementsMap to getEligibleElementsForBinding
* pass elementsMap in bindOrUnbindSelectedElements and unbindLinearElements
* pass elementsMap in elementsAreInFrameBounds,elementOverlapsWithFrame,isCursorInFrame,getElementsInResizingFrame
* pass elementsMap in getElementsWithinSelection, getElementsCompletelyInFrame, isElementContainingFrame, getElementsInNewFrame
* pass elementsMap to getElementWithTransformHandleType
* pass elementsMap to getVisibleGaps, getMaximumGroups,getReferenceSnapPoints,snapDraggedElements
* lint
* pass elementsMap to bindTextToShapeAfterDuplication,bindLinearElementToElement,getTextBindableContainerAtPosition
* revert changes for bindTextToShapeAfterDuplication
											
										 
										
											2024-02-16 14:05:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          const [, , , , boundTextCx, boundTextCy] = getElementAbsoluteCoords(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            boundTextElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            elementsMap,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          );
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 23:33:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          const boundTextShiftX = (x1 + x2) / 2 - boundTextCx;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          const boundTextShiftY = (y1 + y2) / 2 - boundTextCy;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          tempCanvasContext.translate(-boundTextShiftX, -boundTextShiftY);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          // Clear the bound text area
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          tempCanvasContext.clearRect(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            -boundTextElement.width / 2,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            -boundTextElement.height / 2,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            boundTextElement.width,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            boundTextElement.height,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.scale(1 / appState.exportScale, 1 / appState.exportScale);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.drawImage(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            tempCanvas,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            -tempCanvas.width / 2,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            -tempCanvas.height / 2,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            tempCanvas.width,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            tempCanvas.height,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        } else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.rotate(element.angle);
							 | 
						
					
						
							
								
									
										
										
										
											2023-01-08 23:22:04 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          if (element.type === "image") {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            // note: scale must be applied *after* rotating
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            context.scale(element.scale[0], element.scale[1]);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 23:33:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.translate(-shiftX, -shiftY);
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          drawElementOnCanvas(element, rc, context, renderConfig, appState);
							 | 
						
					
						
							
								
									
										
										
										
											2022-12-05 23:33:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-25 21:05:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-07-14 19:29:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.restore();
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-25 21:05:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        // not exporting → optimized rendering (cache & render from element
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        // canvases)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      } else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const elementWithCanvas = generateElementWithCanvas(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          element,
							 | 
						
					
						
							
								
									
										
										
										
											2024-07-23 13:47:32 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          allElementsMap,
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-25 21:05:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          renderConfig,
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          appState,
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-25 21:05:22 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        );
							 | 
						
					
						
							
								
									
										
										
										
											2023-02-04 00:07:14 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2024-08-10 03:36:04 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (!elementWithCanvas) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          return;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-02-04 00:07:14 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        const currentImageSmoothingStatus = context.imageSmoothingEnabled;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          // do not disable smoothing during zoom as blurry shapes look better
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          // on low resolution (while still zooming in) than sharp ones
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          !appState?.shouldCacheIgnoreZoom &&
							 | 
						
					
						
							
								
									
										
										
										
											2023-02-04 00:07:14 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          // angle is 0 -> always disable smoothing
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          (!element.angle ||
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            // or check if angle is a right angle in which case we can still
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            // disable smoothing without adversely affecting the result
							 | 
						
					
						
							
								
									
										
										
										
											2024-09-03 06:23:38 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            // We need less-than comparison because of FP artihmetic
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            isRightAngleRads(element.angle))
							 | 
						
					
						
							
								
									
										
										
										
											2023-02-04 00:07:14 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          // Disabling smoothing makes output much sharper, especially for
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          // text. Unless for non-right angles, where the aliasing is really
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          // terrible on Chromium.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          //
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          // Note that `context.imageSmoothingQuality="high"` has almost
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          // zero effect.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          //
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.imageSmoothingEnabled = false;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2024-10-22 04:26:52 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          element.id === appState.croppingElementId &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          isImageElement(elementWithCanvas.element) &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          elementWithCanvas.element.crop !== null
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        ) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.save();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.globalAlpha = 0.1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          const uncroppedElementCanvas = generateElementCanvas(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            getUncroppedImageElement(elementWithCanvas.element, elementsMap),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            allElementsMap,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            appState.zoom,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            renderConfig,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            appState,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          if (uncroppedElementCanvas) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            drawElementFromCanvas(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              uncroppedElementCanvas,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              context,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              renderConfig,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              appState,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              allElementsMap,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            );
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context.restore();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2024-10-23 17:58:43 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        drawElementFromCanvas(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          elementWithCanvas,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          context,
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          renderConfig,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          appState,
							 | 
						
					
						
							
								
									
										
										
										
											2024-10-23 17:58:43 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          allElementsMap,
							 | 
						
					
						
							
								
									
										
										
										
											2023-08-13 04:56:59 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        );
							 | 
						
					
						
							
								
									
										
										
										
											2023-02-04 00:07:14 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        // reset
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        context.imageSmoothingEnabled = currentImageSmoothingStatus;
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2020-01-29 04:25:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      break;
							 | 
						
					
						
							
								
									
										
										
										
											2020-01-16 03:07:19 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2020-01-29 04:25:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    default: {
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-18 03:55:40 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      // @ts-ignore
							 | 
						
					
						
							
								
									
										
										
										
											2020-02-20 00:25:01 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      throw new Error(`Unimplemented type ${element.type}`);
							 | 
						
					
						
							
								
									
										
										
										
											2020-01-29 04:25:13 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-11 23:00:07 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  context.globalAlpha = 1;
							 | 
						
					
						
							
								
									
										
										
										
											2020-05-20 21:21:37 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							
								
									
										
										
										
											2020-01-16 03:07:19 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								export const pathsCache = new WeakMap<ExcalidrawFreeDrawElement, Path2D>([]);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								export function generateFreeDrawShape(element: ExcalidrawFreeDrawElement) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const svgPathData = getFreeDrawSvgPath(element);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const path = new Path2D(svgPathData);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  pathsCache.set(element, path);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  return path;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								export function getFreeDrawPath2D(element: ExcalidrawFreeDrawElement) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  return pathsCache.get(element);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								export function getFreeDrawSvgPath(element: ExcalidrawFreeDrawElement) {
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-18 22:56:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // If input points are empty (should they ever be?) return a dot
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const inputPoints = element.simulatePressure
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    ? element.points
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    : element.points.length
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    ? element.points.map(([x, y], i) => [x, y, element.pressures[i]])
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-18 22:56:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    : [[0, 0, 0.5]];
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  // Consider changing the options for simulated pressure vs real pressure
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-18 22:56:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const options: StrokeOptions = {
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    simulatePressure: element.simulatePressure,
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-18 22:56:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    size: element.strokeWidth * 4.25,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    thinning: 0.6,
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    smoothing: 0.5,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    streamline: 0.5,
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-18 22:56:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    easing: (t) => Math.sin((t * Math.PI) / 2), // https://easings.net/#easeOutSine
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-12 02:11:26 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    last: !!element.lastCommittedPoint, // LastCommittedPoint is added on pointerup
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  };
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-18 22:56:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  return getSvgPathFromStroke(getStroke(inputPoints as number[][], options));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-18 22:56:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								function med(A: number[], B: number[]) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  return [(A[0] + B[0]) / 2, (A[1] + B[1]) / 2];
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-18 22:56:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// Trim SVG path data so number are each two decimal points. This
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// improves SVG exports, and prevents rendering errors on points
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// with long decimals.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								const TO_FIXED_PRECISION = /(\s?[A-Z]?,?-?[0-9]*\.[0-9]{0,2})(([0-9]|e|-)*)/g;
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-18 22:56:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								function getSvgPathFromStroke(points: number[][]): string {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  if (!points.length) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return "";
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-18 22:56:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  const max = points.length - 1;
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-18 22:56:55 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  return points
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    .reduce(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      (acc, point, i, arr) => {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if (i === max) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          acc.push(point, med(point, arr[0]), "L", arr[0], "Z");
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        } else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          acc.push(point, med(point, arr[i + 1]));
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return acc;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      },
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      ["M", points[0], "Q"],
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    )
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    .join(" ")
							 | 
						
					
						
							
								
									
										
										
										
											2021-10-12 02:11:26 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    .replace(TO_FIXED_PRECISION, "$1");
							 | 
						
					
						
							
								
									
										
										
										
											2021-05-09 23:42:10 +08:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 |