mirror of
				https://github.com/excalidraw/excalidraw.git
				synced 2025-10-31 02:44:50 +01:00 
			
		
		
		
	Compare commits
	
		
			24 Commits
		
	
	
		
			v0.17.6
			...
			aakansha-f
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 6117c46466 | ||
|   | e69c626ead | ||
|   | ca5e246074 | ||
|   | d75889238d | ||
|   | f21a6b587a | ||
|   | 038714e715 | ||
|   | 8de6516823 | ||
|   | 7f1ef7562c | ||
|   | 6001f59d38 | ||
|   | 1c66f85ec9 | ||
|   | a0b968c8e0 | ||
|   | 3a68f0ae7b | ||
|   | c0e88fbc54 | ||
|   | 99500fc255 | ||
|   | bc5e5e1ef0 | ||
|   | 50ac3bf855 | ||
|   | 2ea883a05e | ||
|   | f8b25375a4 | ||
|   | 974745b9e5 | ||
|   | 9dab749dfd | ||
|   | 895f35ae18 | ||
|   | 79be25fbc0 | ||
|   | 1dbc599b88 | ||
|   | fc80fd15dc | 
| @@ -42,7 +42,7 @@ export const actionUnbindText = register({ | ||||
|     selectedElements.forEach((element) => { | ||||
|       const boundTextElement = getBoundTextElement(element); | ||||
|       if (boundTextElement) { | ||||
|         const { width, height } = measureText( | ||||
|         const { width, height, baseline } = measureText( | ||||
|           boundTextElement.originalText, | ||||
|           getFontString(boundTextElement), | ||||
|           boundTextElement.lineHeight, | ||||
| @@ -56,6 +56,7 @@ export const actionUnbindText = register({ | ||||
|           containerId: null, | ||||
|           width, | ||||
|           height, | ||||
|           baseline, | ||||
|           text: boundTextElement.originalText, | ||||
|         }); | ||||
|         mutateElement(element, { | ||||
|   | ||||
| @@ -31,11 +31,15 @@ import { | ||||
| import { getDefaultAppState } from "../appState"; | ||||
| import { LinearElementEditor } from "../element/linearElementEditor"; | ||||
| import { bumpVersion } from "../element/mutateElement"; | ||||
| import { getUpdatedTimestamp, updateActiveTool } from "../utils"; | ||||
| import { getFontString, getUpdatedTimestamp, updateActiveTool } from "../utils"; | ||||
| import { arrayToMap } from "../utils"; | ||||
| import oc from "open-color"; | ||||
| import { MarkOptional, Mutable } from "../utility-types"; | ||||
| import { detectLineHeight, getDefaultLineHeight } from "../element/textElement"; | ||||
| import { | ||||
|   detectLineHeight, | ||||
|   getDefaultLineHeight, | ||||
|   getDOMMetrics, | ||||
| } from "../element/textElement"; | ||||
|  | ||||
| type RestoredAppState = Omit< | ||||
|   AppState, | ||||
| @@ -171,6 +175,24 @@ const restoreElement = ( | ||||
|       } | ||||
|       const text = element.text ?? ""; | ||||
|  | ||||
|       // line-height might not be specified either when creating elements | ||||
|       // programmatically, or when importing old diagrams. | ||||
|       // For the latter we want to detect the original line height which | ||||
|       // will likely differ from our per-font fixed line height we now use, | ||||
|       // to maintain backward compatibility. | ||||
|       const lineHeight = | ||||
|         element.lineHeight || | ||||
|         (element.height | ||||
|           ? // detect line-height from current element height and font-size | ||||
|             detectLineHeight(element) | ||||
|           : // no element height likely means programmatic use, so default | ||||
|             // to a fixed line height | ||||
|             getDefaultLineHeight(element.fontFamily)); | ||||
|       const { baseline } = getDOMMetrics( | ||||
|         element.text, | ||||
|         getFontString(element), | ||||
|         lineHeight, | ||||
|       ); | ||||
|       element = restoreElementWithProperties(element, { | ||||
|         fontSize, | ||||
|         fontFamily, | ||||
| @@ -179,19 +201,9 @@ const restoreElement = ( | ||||
|         verticalAlign: element.verticalAlign || DEFAULT_VERTICAL_ALIGN, | ||||
|         containerId: element.containerId ?? null, | ||||
|         originalText: element.originalText || text, | ||||
|         // line-height might not be specified either when creating elements | ||||
|         // programmatically, or when importing old diagrams. | ||||
|         // For the latter we want to detect the original line height which | ||||
|         // will likely differ from our per-font fixed line height we now use, | ||||
|         // to maintain backward compatibility. | ||||
|         lineHeight: | ||||
|           element.lineHeight || | ||||
|           (element.height | ||||
|             ? // detect line-height from current element height and font-size | ||||
|               detectLineHeight(element) | ||||
|             : // no element height likely means programmatic use, so default | ||||
|               // to a fixed line height | ||||
|               getDefaultLineHeight(element.fontFamily)), | ||||
|  | ||||
|         lineHeight, | ||||
|         baseline, | ||||
|       }); | ||||
|  | ||||
|       if (refreshDimensions) { | ||||
|   | ||||
| @@ -145,6 +145,7 @@ export const newTextElement = ( | ||||
|   const text = normalizeText(opts.text); | ||||
|   const metrics = measureText(text, getFontString(opts), lineHeight); | ||||
|   const offsets = getTextElementPositionOffsets(opts, metrics); | ||||
|  | ||||
|   const textElement = newElementWith( | ||||
|     { | ||||
|       ..._newElementBase<ExcalidrawTextElement>("text", opts), | ||||
| @@ -157,6 +158,7 @@ export const newTextElement = ( | ||||
|       y: opts.y - offsets.y, | ||||
|       width: metrics.width, | ||||
|       height: metrics.height, | ||||
|       baseline: metrics.baseline, | ||||
|       containerId: opts.containerId || null, | ||||
|       originalText: text, | ||||
|       lineHeight, | ||||
| @@ -174,14 +176,15 @@ const getAdjustedDimensions = ( | ||||
|   y: number; | ||||
|   width: number; | ||||
|   height: number; | ||||
|   baseline: number; | ||||
| } => { | ||||
|   const container = getContainerElement(element); | ||||
|  | ||||
|   const { width: nextWidth, height: nextHeight } = measureText( | ||||
|     nextText, | ||||
|     getFontString(element), | ||||
|     element.lineHeight, | ||||
|   ); | ||||
|   const { | ||||
|     width: nextWidth, | ||||
|     height: nextHeight, | ||||
|     baseline: nextBaseline, | ||||
|   } = measureText(nextText, getFontString(element), element.lineHeight); | ||||
|   const { textAlign, verticalAlign } = element; | ||||
|   let x: number; | ||||
|   let y: number; | ||||
| @@ -256,6 +259,7 @@ const getAdjustedDimensions = ( | ||||
|   return { | ||||
|     width: nextWidth, | ||||
|     height: nextHeight, | ||||
|     baseline: nextBaseline, | ||||
|     x: Number.isFinite(x) ? x : element.x, | ||||
|     y: Number.isFinite(y) ? y : element.y, | ||||
|   }; | ||||
|   | ||||
| @@ -46,6 +46,8 @@ import { | ||||
|   handleBindTextResize, | ||||
|   getMaxContainerWidth, | ||||
|   getApproxMinLineHeight, | ||||
|   measureText, | ||||
|   getMaxContainerHeight, | ||||
| } from "./textElement"; | ||||
|  | ||||
| export const normalizeAngle = (angle: number): number => { | ||||
| @@ -193,7 +195,8 @@ const MIN_FONT_SIZE = 1; | ||||
| const measureFontSizeFromWidth = ( | ||||
|   element: NonDeleted<ExcalidrawTextElement>, | ||||
|   nextWidth: number, | ||||
| ): number | null => { | ||||
|   nextHeight: number, | ||||
| ): { size: number; baseline: number } | null => { | ||||
|   // We only use width to scale font on resize | ||||
|   let width = element.width; | ||||
|  | ||||
| @@ -208,8 +211,15 @@ const measureFontSizeFromWidth = ( | ||||
|   if (nextFontSize < MIN_FONT_SIZE) { | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   return nextFontSize; | ||||
|   const metrics = measureText( | ||||
|     element.text, | ||||
|     getFontString({ fontSize: nextFontSize, fontFamily: element.fontFamily }), | ||||
|     element.lineHeight, | ||||
|   ); | ||||
|   return { | ||||
|     size: nextFontSize, | ||||
|     baseline: metrics.baseline + (nextHeight - metrics.height), | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| const getSidesForTransformHandle = ( | ||||
| @@ -280,8 +290,8 @@ const resizeSingleTextElement = ( | ||||
|   if (scale > 0) { | ||||
|     const nextWidth = element.width * scale; | ||||
|     const nextHeight = element.height * scale; | ||||
|     const nextFontSize = measureFontSizeFromWidth(element, nextWidth); | ||||
|     if (nextFontSize === null) { | ||||
|     const metrics = measureFontSizeFromWidth(element, nextWidth, nextHeight); | ||||
|     if (metrics === null) { | ||||
|       return; | ||||
|     } | ||||
|     const [nextX1, nextY1, nextX2, nextY2] = getResizedElementAbsoluteCoords( | ||||
| @@ -305,9 +315,10 @@ const resizeSingleTextElement = ( | ||||
|       deltaY2, | ||||
|     ); | ||||
|     mutateElement(element, { | ||||
|       fontSize: nextFontSize, | ||||
|       fontSize: metrics.size, | ||||
|       width: nextWidth, | ||||
|       height: nextHeight, | ||||
|       baseline: metrics.baseline, | ||||
|       x: nextElementX, | ||||
|       y: nextElementY, | ||||
|     }); | ||||
| @@ -360,7 +371,7 @@ export const resizeSingleElement = ( | ||||
|   let scaleX = atStartBoundsWidth / boundsCurrentWidth; | ||||
|   let scaleY = atStartBoundsHeight / boundsCurrentHeight; | ||||
|  | ||||
|   let boundTextFontSize: number | null = null; | ||||
|   let boundTextFont: { fontSize?: number; baseline?: number } = {}; | ||||
|   const boundTextElement = getBoundTextElement(element); | ||||
|  | ||||
|   if (transformHandleDirection.includes("e")) { | ||||
| @@ -410,7 +421,10 @@ export const resizeSingleElement = ( | ||||
|       boundTextElement.id, | ||||
|     ) as typeof boundTextElement | undefined; | ||||
|     if (stateOfBoundTextElementAtResize) { | ||||
|       boundTextFontSize = stateOfBoundTextElementAtResize.fontSize; | ||||
|       boundTextFont = { | ||||
|         fontSize: stateOfBoundTextElementAtResize.fontSize, | ||||
|         baseline: stateOfBoundTextElementAtResize.baseline, | ||||
|       }; | ||||
|     } | ||||
|     if (shouldMaintainAspectRatio) { | ||||
|       const updatedElement = { | ||||
| @@ -419,14 +433,18 @@ export const resizeSingleElement = ( | ||||
|         height: eleNewHeight, | ||||
|       }; | ||||
|  | ||||
|       const nextFontSize = measureFontSizeFromWidth( | ||||
|       const nextFont = measureFontSizeFromWidth( | ||||
|         boundTextElement, | ||||
|         getMaxContainerWidth(updatedElement), | ||||
|         getMaxContainerHeight(updatedElement), | ||||
|       ); | ||||
|       if (nextFontSize === null) { | ||||
|       if (nextFont === null) { | ||||
|         return; | ||||
|       } | ||||
|       boundTextFontSize = nextFontSize; | ||||
|       boundTextFont = { | ||||
|         fontSize: nextFont.size, | ||||
|         baseline: nextFont.baseline, | ||||
|       }; | ||||
|     } else { | ||||
|       const minWidth = getApproxMinLineWidth( | ||||
|         getFontString(boundTextElement), | ||||
| @@ -568,9 +586,10 @@ export const resizeSingleElement = ( | ||||
|     }); | ||||
|  | ||||
|     mutateElement(element, resizedElement); | ||||
|     if (boundTextElement && boundTextFontSize != null) { | ||||
|     if (boundTextElement && boundTextFont != null) { | ||||
|       mutateElement(boundTextElement, { | ||||
|         fontSize: boundTextFontSize, | ||||
|         fontSize: boundTextFont.fontSize, | ||||
|         baseline: boundTextFont.baseline, | ||||
|       }); | ||||
|     } | ||||
|     handleBindTextResize(element, transformHandleDirection); | ||||
| @@ -677,6 +696,7 @@ const resizeMultipleElements = ( | ||||
|       y: number; | ||||
|       points?: Point[]; | ||||
|       fontSize?: number; | ||||
|       baseline?: number; | ||||
|     } = { | ||||
|       width, | ||||
|       height, | ||||
| @@ -685,7 +705,7 @@ const resizeMultipleElements = ( | ||||
|       ...rescaledPoints, | ||||
|     }; | ||||
|  | ||||
|     let boundTextUpdates: { fontSize: number } | null = null; | ||||
|     let boundTextUpdates: { fontSize: number; baseline: number } | null = null; | ||||
|  | ||||
|     const boundTextElement = getBoundTextElement(element.latest); | ||||
|  | ||||
| @@ -695,24 +715,29 @@ const resizeMultipleElements = ( | ||||
|         width, | ||||
|         height, | ||||
|       }; | ||||
|       const fontSize = measureFontSizeFromWidth( | ||||
|       const metrics = measureFontSizeFromWidth( | ||||
|         boundTextElement ?? (element.orig as ExcalidrawTextElement), | ||||
|         boundTextElement | ||||
|           ? getMaxContainerWidth(updatedElement) | ||||
|           : updatedElement.width, | ||||
|         boundTextElement | ||||
|           ? getMaxContainerHeight(updatedElement) | ||||
|           : updatedElement.height, | ||||
|       ); | ||||
|  | ||||
|       if (!fontSize) { | ||||
|       if (!metrics) { | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       if (isTextElement(element.orig)) { | ||||
|         update.fontSize = fontSize; | ||||
|         update.fontSize = metrics.size; | ||||
|         update.baseline = metrics.baseline; | ||||
|       } | ||||
|  | ||||
|       if (boundTextElement) { | ||||
|         boundTextUpdates = { | ||||
|           fontSize, | ||||
|           fontSize: metrics.size, | ||||
|           baseline: metrics.baseline, | ||||
|         }; | ||||
|       } | ||||
|     } | ||||
|   | ||||
| @@ -14,6 +14,7 @@ import { | ||||
|   DEFAULT_FONT_FAMILY, | ||||
|   DEFAULT_FONT_SIZE, | ||||
|   FONT_FAMILY, | ||||
|   isSafari, | ||||
|   TEXT_ALIGN, | ||||
|   VERTICAL_ALIGN, | ||||
| } from "../constants"; | ||||
| @@ -58,6 +59,7 @@ export const redrawTextBoundingBox = ( | ||||
|     text: textElement.text, | ||||
|     width: textElement.width, | ||||
|     height: textElement.height, | ||||
|     baseline: textElement.baseline, | ||||
|   }; | ||||
|  | ||||
|   boundTextUpdates.text = textElement.text; | ||||
| @@ -78,6 +80,7 @@ export const redrawTextBoundingBox = ( | ||||
|  | ||||
|   boundTextUpdates.width = metrics.width; | ||||
|   boundTextUpdates.height = metrics.height; | ||||
|   boundTextUpdates.baseline = metrics.baseline; | ||||
|  | ||||
|   if (container) { | ||||
|     if (isArrowElement(container)) { | ||||
| @@ -183,6 +186,7 @@ export const handleBindTextResize = ( | ||||
|     const maxWidth = getMaxContainerWidth(container); | ||||
|     const maxHeight = getMaxContainerHeight(container); | ||||
|     let containerHeight = containerDims.height; | ||||
|     let nextBaseLine = textElement.baseline; | ||||
|     if (transformHandleType !== "n" && transformHandleType !== "s") { | ||||
|       if (text) { | ||||
|         text = wrapText( | ||||
| @@ -191,13 +195,14 @@ export const handleBindTextResize = ( | ||||
|           maxWidth, | ||||
|         ); | ||||
|       } | ||||
|       const dimensions = measureText( | ||||
|       const metrics = measureText( | ||||
|         text, | ||||
|         getFontString(textElement), | ||||
|         textElement.lineHeight, | ||||
|       ); | ||||
|       nextHeight = dimensions.height; | ||||
|       nextWidth = dimensions.width; | ||||
|       nextHeight = metrics.height; | ||||
|       nextWidth = metrics.width; | ||||
|       nextBaseLine = metrics.baseline; | ||||
|     } | ||||
|     // increase height in case text element height exceeds | ||||
|     if (nextHeight > maxHeight) { | ||||
| @@ -225,6 +230,7 @@ export const handleBindTextResize = ( | ||||
|       text, | ||||
|       width: nextWidth, | ||||
|       height: nextHeight, | ||||
|       baseline: nextBaseLine, | ||||
|     }); | ||||
|  | ||||
|     if (!isArrowElement(container)) { | ||||
| @@ -285,8 +291,60 @@ export const measureText = ( | ||||
|   const fontSize = parseFloat(font); | ||||
|   const height = getTextHeight(text, fontSize, lineHeight); | ||||
|   const width = getTextWidth(text, font); | ||||
|   const { baseline } = getDOMMetrics(text, font, lineHeight); | ||||
|   return { width, height, baseline }; | ||||
| }; | ||||
|  | ||||
|   return { width, height }; | ||||
| export const getDOMMetrics = ( | ||||
|   text: string, | ||||
|   font: FontString, | ||||
|   lineHeight: ExcalidrawTextElement["lineHeight"], | ||||
|   wrapInContainer?: boolean, | ||||
| ) => { | ||||
|   const container = document.createElement("div"); | ||||
|   container.style.position = "absolute"; | ||||
|   container.style.whiteSpace = "pre"; | ||||
|   container.style.font = font; | ||||
|   container.style.minHeight = "1em"; | ||||
|   if (wrapInContainer) { | ||||
|     container.style.overflow = "hidden"; | ||||
|     container.style.wordBreak = "break-word"; | ||||
|     container.style.whiteSpace = "pre-wrap"; | ||||
|   } | ||||
|  | ||||
|   container.style.lineHeight = String(lineHeight); | ||||
|   const canvasHeight = getTextHeight(text, parseFloat(font), lineHeight); | ||||
|  | ||||
|   container.innerText = text; | ||||
|  | ||||
|   // Baseline is important for positioning text on canvas | ||||
|   document.body.appendChild(container); | ||||
|  | ||||
|   const span = document.createElement("span"); | ||||
|   span.style.display = "inline-block"; | ||||
|   span.style.overflow = "hidden"; | ||||
|   span.style.width = "1px"; | ||||
|   span.style.height = "1px"; | ||||
|   container.appendChild(span); | ||||
|   let baseline = span.offsetTop + span.offsetHeight; | ||||
|   const height = container.offsetHeight; | ||||
|  | ||||
|   if (isSafari) { | ||||
|     // In Safari sometimes DOM height could be less than canvas height due to | ||||
|     // which text could go out of the bounding box hence shifting the baseline | ||||
|     // to make sure text is rendered correctly | ||||
|     if (canvasHeight > height) { | ||||
|       baseline += canvasHeight - height; | ||||
|     } | ||||
|     // In Safari sometimes DOM height could be more than canvas height due to | ||||
|     // which text could go out of the bounding box hence shifting the baseline | ||||
|     // to make sure text is rendered correctly | ||||
|     if (height > canvasHeight) { | ||||
|       baseline -= height - canvasHeight; | ||||
|     } | ||||
|   } | ||||
|   document.body.removeChild(container); | ||||
|   return { baseline, height }; | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -308,7 +366,9 @@ export const getLineHeightInPx = ( | ||||
|   fontSize: ExcalidrawTextElement["fontSize"], | ||||
|   lineHeight: ExcalidrawTextElement["lineHeight"], | ||||
| ) => { | ||||
|   return fontSize * lineHeight; | ||||
|   const res = fontSize * lineHeight; | ||||
|  | ||||
|   return res; | ||||
| }; | ||||
|  | ||||
| // FIXME rename to getApproxMinContainerHeight | ||||
|   | ||||
| @@ -11,7 +11,7 @@ import { | ||||
|   isBoundToContainer, | ||||
|   isTextElement, | ||||
| } from "./typeChecks"; | ||||
| import { CLASSES, VERTICAL_ALIGN } from "../constants"; | ||||
| import { CLASSES, isSafari, VERTICAL_ALIGN } from "../constants"; | ||||
| import { | ||||
|   ExcalidrawElement, | ||||
|   ExcalidrawLinearElement, | ||||
| @@ -35,6 +35,9 @@ import { | ||||
|   getMaxContainerHeight, | ||||
|   getMaxContainerWidth, | ||||
|   computeContainerDimensionForBoundText, | ||||
|   getDOMMetrics, | ||||
|   splitIntoLines, | ||||
|   detectLineHeight, | ||||
| } from "./textElement"; | ||||
| import { | ||||
|   actionDecreaseFontSize, | ||||
| @@ -271,25 +274,38 @@ export const textWysiwyg = ({ | ||||
|       } else { | ||||
|         textElementWidth += 0.5; | ||||
|       } | ||||
|       const { height: domHeight } = getDOMMetrics( | ||||
|         updatedTextElement.text, | ||||
|         getFontString(updatedTextElement), | ||||
|         updatedTextElement.lineHeight, | ||||
|       ); | ||||
|  | ||||
|       let lineHeight = element.lineHeight; | ||||
|       const fontSize = Math.floor(updatedTextElement.fontSize); | ||||
|  | ||||
|       if (isSafari) { | ||||
|         //@ts-ignore | ||||
|         lineHeight = | ||||
|           updatedTextElement.height / | ||||
|           splitIntoLines(updatedTextElement.text).length / | ||||
|           fontSize; | ||||
|       } | ||||
|  | ||||
|       // Make sure text editor height doesn't go beyond viewport | ||||
|       const editorMaxHeight = | ||||
|         (appState.height - viewportY) / appState.zoom.value; | ||||
|       Object.assign(editable.style, { | ||||
|         font: getFontString(updatedTextElement), | ||||
|         font: getFontString({ | ||||
|           fontSize, | ||||
|           fontFamily: updatedTextElement.fontFamily, | ||||
|         }), | ||||
|         // must be defined *after* font ¯\_(ツ)_/¯ | ||||
|         lineHeight: element.lineHeight, | ||||
|         lineHeight, | ||||
|         width: `${textElementWidth}px`, | ||||
|         height: `${textElementHeight}px`, | ||||
|         left: `${viewportX}px`, | ||||
|         top: `${viewportY}px`, | ||||
|         transform: getTransform( | ||||
|           textElementWidth, | ||||
|           textElementHeight, | ||||
|           getTextElementAngle(updatedTextElement), | ||||
|           appState, | ||||
|           maxWidth, | ||||
|           editorMaxHeight, | ||||
|         ), | ||||
|         transform: `scale(${updatedTextElement.fontSize / fontSize})`, | ||||
|         textAlign, | ||||
|         verticalAlign, | ||||
|         color: updatedTextElement.strokeColor, | ||||
|   | ||||
| @@ -131,6 +131,7 @@ export type ExcalidrawTextElement = _ExcalidrawElementBase & | ||||
|     fontSize: number; | ||||
|     fontFamily: FontFamilyValues; | ||||
|     text: string; | ||||
|     baseline: number; | ||||
|     textAlign: TextAlign; | ||||
|     verticalAlign: VerticalAlign; | ||||
|     containerId: ExcalidrawGenericElement["id"] | null; | ||||
|   | ||||
| @@ -200,7 +200,6 @@ const drawImagePlaceholder = ( | ||||
|     size, | ||||
|   ); | ||||
| }; | ||||
|  | ||||
| const drawElementOnCanvas = ( | ||||
|   element: NonDeletedExcalidrawElement, | ||||
|   rc: RoughCanvas, | ||||
| @@ -273,7 +272,10 @@ const drawElementOnCanvas = ( | ||||
|         } | ||||
|         context.canvas.setAttribute("dir", rtl ? "rtl" : "ltr"); | ||||
|         context.save(); | ||||
|         context.font = getFontString(element); | ||||
|         context.font = getFontString({ | ||||
|           ...element, | ||||
|           fontSize: Math.floor(element.fontSize), | ||||
|         }); | ||||
|         context.fillStyle = element.strokeColor; | ||||
|         context.textAlign = element.textAlign as CanvasTextAlign; | ||||
|  | ||||
| @@ -286,18 +288,16 @@ const drawElementOnCanvas = ( | ||||
|             : element.textAlign === "right" | ||||
|             ? element.width | ||||
|             : 0; | ||||
|         context.textBaseline = "bottom"; | ||||
|  | ||||
|         const lineHeightPx = getLineHeightInPx( | ||||
|           element.fontSize, | ||||
|           element.lineHeight, | ||||
|         ); | ||||
|  | ||||
|         const verticalOffset = element.height - element.baseline; | ||||
|         for (let index = 0; index < lines.length; index++) { | ||||
|           context.fillText( | ||||
|             lines[index], | ||||
|             horizontalOffset, | ||||
|             (index + 1) * lineHeightPx, | ||||
|             (index + 1) * lineHeightPx - verticalOffset, | ||||
|           ); | ||||
|         } | ||||
|         context.restore(); | ||||
|   | ||||
| @@ -282,6 +282,7 @@ exports[`restoreElements should restore text element correctly passing value for | ||||
| Object { | ||||
|   "angle": 0, | ||||
|   "backgroundColor": "transparent", | ||||
|   "baseline": 0, | ||||
|   "boundElements": Array [], | ||||
|   "containerId": null, | ||||
|   "fillStyle": "hachure", | ||||
| @@ -321,6 +322,7 @@ exports[`restoreElements should restore text element correctly with unknown font | ||||
| Object { | ||||
|   "angle": 0, | ||||
|   "backgroundColor": "transparent", | ||||
|   "baseline": 0, | ||||
|   "boundElements": Array [], | ||||
|   "containerId": null, | ||||
|   "fillStyle": "hachure", | ||||
|   | ||||
		Reference in New Issue
	
	Block a user